KMLk: nouveautés sur le site et l’app android
Nouveautés
Il y en a essentiellement deux (et aussi quelques correctifs mineurs):
- Nouveau menu contextuel sur les liens dans l’app android.
- Possibilité de “transférer” un lien entre l’app android et le site web KMLk.
Nouveau menu contextuel
Jusqu’en version 1.0.4, il fallait faire glisser le lien vers la gauche pour afficher les options (partager, supprimer). Ce “slide” est remplacé par un menu contextuel (utilisable grâce au bouton “trois points”) et propose plus d’options:
- Partager
- Supprimer
- Transférer vers le site KMLk (Nouveau!)
- Copier (Nouveau!)
- Ouvrir dans le navigateur (déjà disponible via un appui sur le lien)
Transfert entre app android et site web
C’est la grosse nouveauté de KMLk: on peut envoyer un lien sauvegardé vers un autre appareil, en utilisant le site KMLk. J’ai axé le développement sur deux points:
- la sécurité: le lien ne doit être lisible que par le site web lors de sa réception.
- l’accessibilité: la fonctionnalité doit être autonome et ne pas nécessiter de serveur annexe (genre STUN / Turn).
Principe de fonctionnement
Le transfert du lien s’effectue en trois étapes:
- Sur le site web, on ouvre la page “Receive a link”. Un code QR s’affiche.
- Dans l’app android, on choisit le lien a transférer puis on scanne le code QR.
- Sur le site web, on clique sur le bouton “Open link”
Sécurité
Afin d’éviter de demander un mot de passe pour le transfert (chose contraignante qui devient vite inefficace), j’ai opté pour la génération d’un code QR qui contient les données nécessaires au chiffrement AES-256: une clé et un vecteur d’initialisation. Comme ces informations ne circulent pas sur le réseau, il n’y a pas besoin de les protéger. En scannant le code QR dans l’app android, celle-ci peut chiffrer le lien avant de le déposer sur le serveur KMLk. Comme la clé ne circule pas sur le réseau, il ne reste que l’attaque “brute force” pour déchiffrer le contenu du fichier.
Disséquons le code de l’app android
Le code source est disponible sur mon repository Codeberg.
Fichier kmlk_list_links.dart
Dans cette classe, on effectue plusieurs modifications:
- la première consiste à remplacer le tiroir des actions (Slidable) par un menu contextuel.
- la seconde est d’ajouter la foncionnalité de scan du code QR de chiffrement.
- enfin on ajoute le chiffrement et l’envoi du lien vers le serveur KMLk.
Remplacement du tiroir par un menu contextuel
Dans le ListTile du scaffold (méthode build
), on remplace le ActionPane
par un PopupMenuButton
contenant un PopupMenuItem
pour chaque entrée de menu. On ajoute un type à chaque point de menu avec l’enum KmlkLinkAction
.
Via le onSlected
du PopupMenuButton, on déclenche la fonction _manageAction
qui va recevoir l’action à effectuer et l’index du lien dans la liste à traiter.
Scan du code QR de chiffrement et envoi du lien chiffré
C’est la méthode _qrCodeScan
qui est responsable de lire code QR contenant les informations de chiffrement (clé et vecteur d’initialisation). Ensuite on chiffre le lien et son identifiant (qui sera le nom du fichier déposé sur le serveur) et finalement on envoie l’ensemble sur le serveur KMLk via un appel POST en HTTP.
** A REVOIR après split de la méthode !! **
Méthode _copyLink
L’objectif de cette méthode est de copier le lien dans le presse-papiers. Pour cela, on utilise la fonction Clipboard.setData()
, proposée en standard pour Flutter.
Examinons le code du site web
Le code source est disponible sur mon repository Codeberg. J’ai amélioré le design du site pour les smartphones.
Fichier app.vue
- Ajout du bouton “Receive link”
Fichier links/kmlk_receive.vue
- Génération de la clé et du vecteur d’initialisation pour le chiffrement (méthodes generatePin et generateIV)
- Génération et affichage du code QR
- Bouton “Open link”
Méthode generatePin
Son objectif est de générer une clé pour le chiffrement du lien. Ici on génère deux UUID de 36 caractères chacun puis on garde 32 caractères. Et hop! On dispose d’une clé robuste.
Méthode generateIV
Ici on veut créer un vectuer d’initialisation de 16 octets. Pour y parvenir on prend donc 16 caractères dans un UUID.
Un peu de PHP?
Afin de faire le passe-plat entre l’app android et le site web, j’ai opté pour une solution simple: gérer le dépôt des fichiers via trois scripts PHP. Pourquoi PHP? Parce que mon hébergeur (coucou Infomaniak) laisse uniquement cette possibilité pour exécuter des scripts. En soi, vu l’ampleur de cette foncionnalité, PHP fera parfaitement l’affaire.
Constantes (fichier constants.php)
Dans ce fichier, on définit les constantes nécessaires à la manipulation des données JSON: nom des champs, content-type, dossier de dépôt.
Réception du contenu envoyé par l’app android (fichier push.php)
Ce script effectue les actions suivantes:
- Préparer le header de la reponse HTTP
- Lire les données JSON envoyées par l’app android
- Préparer le fichier de dépôt (en utilisant l’identifiant contenu dans les données JSON)
- Ecrire le contenu JSON dans le fichier
- Retourner une réponse JSON au client
Transfert du contenu au site web (fichier push.php)
Ce script effectue l’action opposée au script précèdent: il va lire le contenu du fichier et le retourner sous forme JSON au client. Il se contente de lire le fichier dont l’identifiant est indiqué. Le script ne déchiffre pas le contenu. Il y a une petite subtilité de fonctionnement: après avoir lu le contenu, le script efface le fichier. Il y a deux objectifs derrière cette suppression:
- libérer de l’espace de stockage (qui n’est pas infini).
- réduire la surface d’attaque (pas de donnée = pas de fuite. Merci Captain Obvious).
Nettoyage planifié
Dans le cas où un utilisateur envoie un lien mais sans le récupérer sur le site Web, le fichier reste sur disque. En conséquence, un script planifié chaque quart d’heure efface les fichiers déposés il y a plus de quinze minutes.