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:

  1. la sécurité: le lien ne doit être lisible que par le site web lors de sa réception.
  2. 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:

  1. Sur le site web, on ouvre la page “Receive a link”. Un code QR s’affiche.
  2. Dans l’app android, on choisit le lien a transférer puis on scanne le code QR.
  3. 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 !! **

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:

  1. libérer de l’espace de stockage (qui n’est pas infini).
  2. 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.

Liens