Console Web et Web Push
La console navigateur est accessible à https://remote.ivjn.us/console/. Elle prend en charge l'inscription avec vérification par e-mail, la connexion par compte/mot de passe ou jeton opérateur, les appareils par espace de travail, les commandes en flux continu, un PTY xterm, les captures d’écran Android, les appuis, la navigation et la saisie de texte, les métriques, l'audit, la création/suppression d'appareils et les notifications facultatives. Les comptes en lecture seule ne peuvent ni exécuter des commandes ni consulter les écrans Android. Les appareils hors ligne restent visibles.
Les appareils annonçant la capacité ubus affichent un onglet ubus pour saisir un objet, une méthode et des paramètres JSON facultatifs (un champ vide envoie null). Les appels utilisent des sessions chiffrées et exigent un appareil activé, en ligne et une autorisation de contrôle. Annuler termine l’attente sans annuler une méthode déjà exécutée. Changer d’appareil ou perdre les droits efface les appels en attente et les résultats.
L'inscription crée un espace de travail distinct. L'adresse e-mail doit être vérifiée avec son code à huit chiffres avant la connexion ; la console permet de renvoyer les codes et de reprendre la vérification après rechargement. Exchange doit disposer d'une configuration SMTP (SMTP_HOST, SMTP_PORT, SMTP_FROM et paramètres d'authentification/sécurité de .env.example). Sans service de messagerie disponible, l'inscription signale une erreur sans contourner la vérification.
Les identifiants restent en mémoire dans la page. Un rechargement exige une nouvelle connexion. La déconnexion ferme les sessions, tente de supprimer l'abonnement push de ce navigateur et révoque les sessions ouvertes par mot de passe. Les jetons opérateur principaux conservent leur durée de validité existante. Un clic sur une notification active une console déjà ouverte sans recharger ses identifiants.
Compiler et servir
cd website/console
npm ci
npm test
npm run build
Copiez dist/ dans le répertoire console/ du site. Gardez website/assets/ accessible à /assets/ pour les polices et le symbole partagés. Servez index.html, sw.js et le manifeste avec revalidation/no-cache. Les ressources portant un hachage peuvent être mises en cache de manière immuable. Ne mettez pas /api/* ni /ws/* en cache.
La console utilise /api/* et /ws/browser sur la même origine. Transmettez-les à Exchange par proxy inverse en conservant Host et en autorisant les mises à niveau WebSocket. Ne supprimez pas les préfixes /api et /ws. Le serveur de développement Vite transmet API/WS vers 127.0.0.1:18082. Rust Exchange autorise par défaut les navigateurs de même origine. Configurez les origines exactes avec REMOTE_CORS_ORIGINS ; seul un * explicite autorise toutes les origines. Worker utilise CORS_ORIGINS et ses propres valeurs par défaut. Authentification Bearer et tickets WebSocket à usage unique restent obligatoires ; les cookies interorigines sont désactivés.
L'authentification navigateur utilise POST /api/ws-ticket avec autorisation Bearer, puis GET /ws/browser et une première trame JSON {"ticket":"..."}. Les tickets expirent après 30 secondes, sont à usage unique et revérifient à leur consommation l'état actif de l'opérateur et la validité des identifiants. Les identifiants durables ne sont jamais placés dans les URL WebSocket. Les clients natifs continuent d'utiliser /ws/operator.
Toutes les opérations sur les appareils utilisent des sessions WebSocket scellées natives. HTTP fournit l’authentification, les métadonnées des appareils, les annuaires des clés et autorisations, ainsi que l’administration des sessions du relais ; voir l’API HTTP pour les opérations Agent.
Activer Web Push
Définissez ces deux variables dans l'environnement d'Exchange (leur absence à toutes deux désactive le push) :
WEB_PUSH_VAPID_PRIVATE_KEY=<base64url-unpadded-32-byte-P256-private-key>
WEB_PUSH_VAPID_SUBJECT=https://remote.ivjn.us
Générez une clé privée avec python scripts/generate-vapid-key.py. Conservez-la hors de Git dans un fichier d'environnement à accès restreint, stable entre redémarrages, et sauvegardez-la de manière sécurisée. La clé publique est dérivée automatiquement. Changer de clé oblige les navigateurs à se réabonner.
WEB_PUSH_ALLOWED_ORIGINS contient par défaut les origines de confiance exactes https://fcm.googleapis.com,https://updates.push.services.mozilla.com,https://web.push.apple.com. N'ajoutez un autre fournisseur de navigateur qu'après vérification de son origine push HTTPS. Les adresses fournies par les clients ne peuvent pas étendre cette liste. Les redirections ne sont jamais suivies.
Routes authentifiées :
| Méthode et chemin | Fonction |
|---|---|
GET /api/webpush/config |
État d'activation et clé publique du serveur d'application |
GET/POST /api/webpush/subscriptions |
Lister les métadonnées de ses abonnements, ou créer/mettre à jour un abonnement |
DELETE /api/webpush/subscriptions/{id} |
Supprimer un de ses abonnements |
POST /api/webpush/test |
Mettre en file un test visible pour les abonnements de l'appelant |
POST /api/webpush/messages |
Envoyer à soi-même ou, comme administrateur, à un autre compte du même espace |
POST /api/webpush/devices/{id}/messages |
Notifier les administrateurs abonnés qui gèrent cet appareil authentifié |
Les abonnements utilisent PushSubscription.toJSON() du navigateur, application_server_key et triggers. triggers contient au plus un objet online et un objet offline. Chaque objet possède kind, tick_count (3 par défaut, de 1 à 100) et éventuellement device_ids. offline notifie après tick_count échecs consécutifs ; online après tick_count réussites consécutives. device_ids est un identifiant d'appareil (chaîne), une liste d'identifiants, ou absent/null pour tous les appareils de l'espace de travail. Un tableau triggers vide abonne le navigateur sans alertes automatiques en ligne/hors ligne. missed_count et success_count sont refusés. Les messages utilisent éventuellement operator_id et notification avec title, body, ainsi que url relatif de même origine et tag facultatifs. /webpush/ est un client de référence minimal ; la console de production utilise son propre worker limité à /console/.
La migration 0005_web_push.sql ajoute les abonnements et la boîte d'envoi durable. 0008_online_offline_triggers.sql transfère les notifications d'appareils vers triggers et supprime missed_count / success_count. 202 signifie mis en file, sans garantir livraison ni affichage. Les tâches expirent après 15 minutes. Les erreurs réseau, 408, 429 et 5xx sont réessayées jusqu'à cinq tentatives ; 404/410 suppriment la révision correspondante de l'abonnement. Un bail de 90 secondes permet la reprise après défaillance d'un worker. La livraison suit une sémantique « au moins une fois » ; l'affichage dépend du fournisseur, des autorisations et de la politique du système d'exploitation. Avant mise en file durable, les événements d'appareil sont traités au mieux en cas de surcharge ; ceux déjà en file survivent aux redémarrages. Limites : 20 abonnements/compte, 32 messages en file/abonnement et 30 modifications/minute/compte.
iOS/iPadOS peut exiger l'ajout de la console à l'écran d'accueil avant l'activation des notifications. L'accessibilité du service Push du navigateur est indépendante de la connexion à Exchange.
Validation
Exécutez cargo test --workspace, cargo clippy --workspace --all-targets -- -D warnings et les tests/la compilation npm de la console. Pour le test d'intégration PostgreSQL/HTTPS, installez psycopg[binary], définissez WEB_PUSH_TEST_ADMIN_URL sur une connexion PostgreSQL de test dotée du droit CREATE DATABASE, puis lancez python scripts/test-webpush.py. Il crée puis supprime une base jetable ; ne lui donnez jamais un rôle de base de données possédant des privilèges involontaires.
Envoyer depuis chaque client
Web Console propose un formulaire dans les notifications du navigateur. Les paramètres de la Console mobile proposent l’envoi Web Push, un test et un lien vers Web Console. Les paramètres locaux de l’Agent de bureau, ceux de l’Agent Android et la page de configuration de l’extension utilisent les identifiants de l’appareil. Les Agents sans interface/OpenWrt utilisent la commande suivante. Activez les notifications dans Web Console/PWA pour les recevoir ; aucun récepteur natif FCM/APNs n’est ajouté.
remote-cli webpush status
remote-cli webpush subscriptions
remote-cli webpush test
remote-cli webpush send --title "Backup ready" --body "Completed"
remote-cli webpush send --operator-id ACCOUNT_UUID --title "Notice" --body "Hello"
remote-agent --config /path/to/config.json webpush --title "Device ready" --body "Completed"
{"notification":{"title":"Backup ready","body":"Completed","url":"/console/","device_id":"edge-1"}}
POST /api/webpush/messages utilise l’authentification Bearer de l’opérateur. Sans operator_id, le destinataire est votre compte ; un autre compte exige des droits administrateur et le même espace de travail. Le JSON ci-dessus fonctionne aussi avec remote-cli webpush send --json-file message.json. Des déclencheurs d’état vides désactivent les alertes automatiques en ligne/hors ligne tout en conservant les messages généraux.
POST /api/webpush/devices/{id}/messages utilise le jeton Bearer de cet appareil et accepte directement un objet notification (title, body, tag facultatif). Seuls les abonnements actifs des administrateurs activés qui gèrent cet appareil sont ciblés. Le serveur fixe device_id, event=device.message, occurred_at et /console/ ; l’expéditeur ne choisit ni compte ni autre appareil. Les appareils partagent 30 requêtes/minute/espace, avec 256 abonnements maximum par envoi. Les limites des comptes et files restent applicables. Sans destinataire actif, la réponse est 202 {"queued":0} ; queued compte les abonnements, pas les livraisons.