- En voulant réduire les cartes plastiques de la Seattle Public Library et du King County Library System, l’auteur s’est retrouvé à manipuler directement la structure JSON, les images et la signature des passes Wallet sur iPhone
- Wallet ne prend en charge que les QR codes, PDF417, Aztec Code et Code 128, ce qui empêche d’utiliser le Codabar des cartes de bibliothèque comme code-barres natif ; le code-barres réellement scannable a donc été contourné via une image
- Le pass devait être signé avec une clé approuvée par Apple, mais au lieu de payer l’adhésion Apple Developer à 99 $ par an, l’auteur a récupéré un certificat et une clé depuis une app iOS de création de passes fonctionnant hors ligne
- En combinant une mise en page
storeCard, des logos adaptés à chaque résolution, unstrip.pngCodabar et une entrée videPKBarcodeFormatCode128, il a pu afficher un code-barres en image tout en conservant le comportement d’augmentation de luminosité de l’écran d’iOS - Le fichier
.pkpassfinal a pu être créé via la génération du manifest, une signatureopenssl smimeet un empaquetage ZIP ; sans encore tester en bibliothèque réelle, un scanner séparé a bien lu le code-barres affiché sur l’écran du téléphone
Objectif : utiliser le code-barres de bibliothèque sans carte plastique
- La Seattle Public Library et le King County Library System délivrent des cartes plastiques avec code-barres imprimé reliées à un compte d’emprunt
- En 2023, la plupart des fonctions de la bibliothèque de Seattle sont en libre-service et il est généralement possible de saisir manuellement le code-barres de bibliothèque
- Mais comme il est bien plus pratique d’afficher directement le code-barres, l’objectif était de le mettre dans l’app Wallet de l’iPhone plutôt que de garder dans son portefeuille une carte plastique presque jamais utilisée
Un pass Wallet se compose de JSON, d’images et d’une signature
- L’app Wallet gère aujourd’hui les cartes de paiement, les pièces d’identité, les clés, etc., mais lors du lancement de Passbook en 2012, elle ne gérait que des « passes »
- D’après la documentation d’Apple sur les passes, un pass est un fichier ZIP autonome distribuable par e-mail ou sur le web, contenant du JSON et des PNG
- La structure essentielle d’un fichier
.pkpassest simplepass.json: décrit le contenu du pass hors imagesmanifest.json: liste des sommes de contrôle SHA-1 des autres fichierssignature: signature S/MIME du contenu demanifest.json- les fichiers image pris en charge
L’absence de prise en charge de Codabar a été le premier obstacle
- Les passes Wallet ne prennent en charge que quatre types de code-barres
- QR code
- PDF417
- Aztec Code
- Code 128
- La carte de bibliothèque utilisait le format Codabar, très répandu dans les bibliothèques
- Il est possible que les scanners de la bibliothèque prennent aussi en charge d’autres codes-barres linéaires, mais le seul format dont le fonctionnement pouvait être considéré comme certain dans toutes les agences était le Codabar
- Il a donc fallu, au lieu d’utiliser la fonction de code-barres native de Wallet, générer une image Codabar scannable et l’intégrer au pass
Le problème du certificat de signature du pass
- Les passes Wallet exigent une signature cryptographique et doivent être signés avec une clé approuvée par l’une des autorités de certification de confiance d’Apple
- Pour des usages où le fournisseur met à jour automatiquement le pass, comme un changement de porte d’embarquement ou de siège sur un billet d’avion, cette signature est logique dans une certaine mesure
- Un développeur Apple peut obtenir assez facilement une clé de signature de pass, mais l’auteur n’avait aucune intention de payer 99 $ par an pour cette tâche
Pourquoi les apps existantes de création de passes ne convenaient pas
- Il existait déjà diverses apps de conception de passes créées par des personnes déjà développeuses Apple, mais elles n’offraient pas le niveau de contrôle nécessaire
-
Contrôle de la taille du logo
- Apple autorise pour le logo en haut à gauche du pass une hauteur maximale de 50 device-independent pixels
- Le logo carré placé à droite du texte donnait le meilleur rendu à environ 40 px de haut
- Le développeur doit fournir séparément
logo.png,logo@2x.pngetlogo@3x.png, mais les apps ne permettent généralement de choisir qu’un seul logo sans contrôle de l’échelle
-
Comportement de luminosité de l’écran
- Lorsqu’on ouvre un pass contenant un code-barres normalement pris en charge, l’écran devient plus lumineux pour améliorer le contraste avec le scanner
- Pour que iOS augmente la luminosité sans afficher un faux code-barres non fonctionnel, il fallait manipuler directement
pass.json - Même les apps téléchargeables gratuitement limitaient parfois le nombre de passes enregistrables dans Wallet et demandaient un paiement
Trouver une clé de signature dans une app de génération hors ligne
- Plusieurs apps gratuites de création de passes ont été téléchargées pour vérifier si elles pouvaient créer des passes hors ligne
- Les tests, en mode avion avec le Wi-Fi désactivé, ont montré qu’au moins une app pouvait créer un pass sans connexion
- Le nom précis de cette app n’est pas donné afin d’éviter que la clé soit révoquée
- La procédure s’est révélée plus simple que prévu
- Comme on peut exécuter des apps iOS sur un Mac Apple silicon, l’app a été téléchargée sur le Mac
- Un fichier
.p12bien visible a été trouvé dans le bundle enveloppé de l’app iOS - Comme un fichier PKCS#12 demande un mot de passe d’import, la commande
stringsa été exécutée sur le binaire principal pour trouver une chaîne ressemblant au mot de passe
- En examinant les informations du certificat avec
openssl pkcs12, l’émetteur apparaissait comme Apple Worldwide Developer Relations Certification Authority - La chaîne de certificats est également nécessaire ; le certificat intermédiaire peut se trouver dans le bundle de l’app ou se télécharger via l’URL présente dans les champs d’extension X.509
Construction de la mise en page du pass
- Les styles de pass imposent de choisir entre
boarding pass,coupon,event ticket,genericetstore card - Pour intégrer une grande image horizontale, il fallait une mise en page prenant en charge une image
strip- les candidats étaient
coupon,event ticketetstore card - la forme la plus proche d’une carte de bibliothèque physique a conduit au choix de store card
- les candidats étaient
pass.jsoncontient les valeurs suivantespassTypeIdentifierteamIdentifierformatVersionserialNumberorganizationNamelogoTextdescriptionstoreCardbackgroundColorforegroundColorsharingProhibited
passTypeIdentifieretteamIdentifierdoivent correspondre respectivement aux champsUIDetOUdu subject du certificat Apple- Chaque pass créé avec le même
passTypeIdentifierdoit avoir unserialNumberunique - Les images ont été préparées selon leur rôle
icon.pngest obligatoire, mais n’est pas affiché dans le pass lui-mêmelogo.pngest le logo affiché en haut à gauche- des fichiers
logo.png40×40,logo@2x.png80×80 etlogo@3x.png120×120 ont été générés logo@3x.pnga été copié enicon.png- le code-barres généré à l’avance a été placé dans
strip.png
Créer une image de code-barres Codabar
- Comme iOS redimensionne et recadre
strip.pngpour l’adapter à la zone affichée sur l’écran de l’appareil, il n’était pas nécessaire de produire trois versions destrip.pngselon la résolution - Les deux cartes de bibliothèque utilisaient A et D comme symboles de début et de fin
- Les symboles de début et de fin sont les plus faciles à identifier avec un scanner de code-barres ; à défaut, on peut les comparer visuellement au tableau d’encodage Codabar sur Wikipedia
- Il n’existe pas beaucoup de générateurs Codabar directement exploitables en ligne, mais le format lui-même est assez simple à implémenter
- Dans le prototype, la bibliothèque Barcoders pour Rust a servi à produire un SVG, ensuite ajusté puis exporté en PNG
- La mise en page finale a été définie pour équilibrer la lisibilité par scanner et la réduction opérée par iOS
- la hauteur du code-barres a été définie à deux unités par symbole total, y compris les symboles de début et de fin
- par exemple, un numéro de code-barres sur 13 chiffres contient 15 symboles, d’où une hauteur de 30 unités
- un quiet space de 15 unités a été laissé avant le début et après la fin
- un padding de 50 unités a été ajouté au-dessus et au-dessous du code-barres
- chaque unité a été agrandie à 8 pixels afin que iOS réduise toujours l’image
- pour l’exemple d’un code-barres à 15 symboles, l’image finale fait 1040 pixels de haut et le code-barres lui-même 240 pixels
- Un script shell de 69 lignes a été écrit pour générer un BMP Codabar avec cette mise en page, puis le convertir en PNG avec
sips - En enregistrant la sortie du script sous
strip.png, l’image de code-barres destinée au pass était prête
Affichage du numéro de code-barres et contournement de la luminosité
- Le numéro de code-barres est affiché sous le code-barres via
secondaryFieldskey:numberlabel:CARD NUMBERvalue: numéro de la carte
- Quand iOS sélectionne un pass contenant un code-barres, il augmente la luminosité de l’écran pour aider le scanner
- Un simple Codabar intégré comme image ne suffit pas à faire considérer par iOS que le pass contient un code-barres
- Le comportement a été contourné en définissant une entrée de code-barres vide au niveau supérieur de
pass.jsonmessageest une chaîne videformatestPKBarcodeFormatCode128messageEncodingestiso-8859-1
- Cette méthode a permis à l’iPhone d’augmenter la luminosité comme pour un pass avec code-barres, sans afficher de code-barres supplémentaire en bas du pass
Signature et empaquetage
- Une fois tous les fichiers prêts, il faut générer
manifest.json manifest.jsonest un objet dont les clés sont les noms de fichiers et les valeurs leurs sommes de contrôle SHA-1- Le manifest des PNG et de
pass.jsona été généré avec une combinaison desha1sumetjq - La signature du manifest a été réalisée avec la commande
openssl smime- certificat du signataire
- clé privée
- certificat intermédiaire Apple WWDR
- entrée
manifest.json - sortie
signature
- L’option
-attimedeopenssl smimepermet de fixer l’instant de signature souhaité- la valeur de l’option est un epoch UNIX
- même si le certificat obtenu auprès d’Apple ou récupéré autrement a expiré, il est possible de signer à cet instant
- Enfin, les fichiers suivants sont rassemblés dans une archive ZIP pour produire le
.pkpass- les images PNG
pass.jsonmanifest.jsonsignature
Résultats des tests et limites
- macOS dispose d’un outil d’aperçu des passes permettant de vérifier si le pass est valide et s’affiche globalement correctement
- En cas d’invalidité, on peut trouver les erreurs dans
Console.app - L’outil d’aperçu n’est pas fiable à 100 %, mais il propose un bouton pour envoyer le pass vers l’iPhone via iCloud
- Le pass final n’a pas encore été testé dans une vraie bibliothèque
- En revanche, un scanner de code-barres séparé a pu lire sur l’écran du téléphone le code-barres comme sur la vraie carte plastique
- la lecture fonctionnait toutefois bien lorsque la luminosité de l’écran était poussée au maximum
- elle a été réglée encore plus haut que l’augmentation obtenue via le contournement du code-barres vide
- Le fait que la spécification du pass ait à peine changé en 10 ans est appréciable, mais il est regrettable qu’un abonnement Apple Developer à 99 $ par an soit nécessaire pour signer un pass inoffensif composé de PNG et de JSON
- Certaines fonctions de pass peuvent justifier une signature, mais selon l’auteur, ce qu’il a fait ici ne devrait pas en nécessiter une
- Si Apple ajoutait la prise en charge du Codabar dans Wallet, les systèmes de bibliothèque pourraient prendre en charge les cartes de bibliothèque numériques sans devoir auditer tous leurs scanners pour vérifier la compatibilité avec Code 128
1 commentaires
Commentaires sur Hacker News
La prochaine fois, j’aimerais bien qu’on parle aussi de la carte ORCA. Seattle est l’un des pôles technologiques des États-Unis, mais non seulement son métro / ses transports publics ne sont pas terribles, ils sont aussi en retard technologiquement par rapport à ceux de presque toutes les grandes villes que j’ai utilisées
N’importe quelle ville européenne, CDMX ou Denver est bien plus avancée que Seattle, et personnellement je crois que Denver était celle que j’ai préférée
L’un des organismes qui gèrent ORCA avait même publié un billet de blog disant qu’il allait ajouter la prise en charge du NFC à l’app Android, mais ce billet a maintenant disparu et, plusieurs années plus tard, cette fonctionnalité n’existe toujours pas
Tant qu’on utilise la même carte, les correspondances, les pass de plusieurs jours, etc. sont gérés de manière fluide, et le bon tarif est appliqué automatiquement, par exemple sans facturer au-delà d’un certain nombre de trajets sur une période donnée
La porte du bureau s’ouvre avec une carte NFC, donc j’ai regardé si c’était possible sur iOS, et si je me souviens bien Apple contrôle le matériel NFC plus strictement que PassKit en général, donc ça me semble difficile avec une app classique
ORCA disait que le paiement par tap arriverait en 2023, donc il reste maintenant environ deux mois pour que cela devienne vrai
Comme Google a écrit que Google Wallet allait bientôt prendre en charge ORCA, je reste optimiste
Si, parmi les utilisateurs Android, vous n’aimez pas le fait que Google Wallet ne permette pas d’ajouter n’importe quel code-barres comme Apple Passbook, il existe une excellente application sur F-Droid appelée Loyalty Card Keychain : https://f-droid.org/en/packages/protect.card_locker/
On peut saisir les chiffres à la main ou scanner un code-barres existant, puis l’enregistrer en choisissant parmi plusieurs formats, y compris Codabar. En touchant un élément sur l’écran principal de l’application, le code-barres généré s’affiche et la luminosité de l’écran augmente aussi
L’application s’ouvre également très vite, sans doute parce qu’elle ne fait pas grand-chose d’autre qu’afficher des codes-barres. Elle n’a qu’une seule fonction, mais c’est peut-être l’une de mes applications préférées
Apparemment, on recommande plutôt Catima ces jours-ci ; je l’ai essayée rapidement, et elle semble tout aussi simple et basée sur la même base de code
C’est peu pratique, mais ça remplit l’objectif, et la politique de confidentialité est bonne
Je ne vois pas pourquoi il serait logique que les pass soient signés cryptographiquement et avec une clé connue d’une autorité de certification Apple. Pour ce type de mises à jour, HTTPS existe déjà et est largement pris en charge
Peut-être qu’Apple veut que les pass puissent être vérifiés hors ligne sur le téléphone, et pas seulement au moment de la mise à jour, mais ça reste étrange. Un acteur malveillant pourrait simplement remplacer complètement le pass au lieu de le mettre à jour
Je ne vois absolument pas en quoi le fait de le lier à un compte développeur Apple aide à résoudre le problème des mises à jour
La seule raison qui me vient à l’esprit pour exiger qu’il s’agisse d’une entité approuvée par Apple, ce serait la vente de faux billets. Il n’y a aucun moyen de savoir si un fichier pkpass « billet pour le concert X » est authentique ou non, avec ou sans cette exigence
On peut imaginer qu’Apple essaie de répondre aux signalements de fraude en révoquant le compte développeur concerné, mais ça ne ressemble pas non plus à une vraie solution. Le coût d’un compte développeur est probablement bien inférieur à l’argent qu’une arnaque peut rapporter avant d’être repérée
Moi, je me contente de m’envoyer par e-mail un PNG de code-barres contenant mon numéro de carte de bibliothèque, puis je l’ouvre dans Photos ou Gmail devant la borne
J’ai créé avec MakePass un pass contenant mon code de membre StarBucks, et quand je m’approche d’un magasin où je vais souvent, mon téléphone me suggère automatiquement le pass StarBucks sur l’écran verrouillé
Pour les billets d’événement, c’est pareil : si on définit le lieu et la plage horaire, le pass est suggéré automatiquement à l’arrivée, sans avoir à le chercher. Une fois l’événement terminé, il n’est plus proposé et passe dans la section « Expired Passes », ce qui n’encombre pas l’écran principal
MakePass : https://pvieito.com
C’était un bon billet de blog, mais il se termine par « je n’ai pas encore testé ce pass dans une vraie bibliothèque »
Je comprends que c’était un projet fait pour le plaisir, mais je ne vois pas pourquoi il n’a pas pris les 10 minutes nécessaires pour tester la solution finale avant de partager le résultat
Lors de la création de codes-barres, je préfère personnellement le générateur de codes-barres en PostScript
https://bwipp.terryburton.co.uk/
J’ai résolu ce problème en prenant une photo de la carte de bibliothèque. Quand j’emprunte un livre, j’ouvre la photo et je la présente au scanner
Je conserve toutes mes pièces d’identité dans la galerie photo de mon téléphone
Si vous voulez faire quelque chose de similaire sur Android, il y a Catima sur Google Play et F-Droid. L’application prend en charge plusieurs types de codes-barres
https://catima.app/
Les scanners de codes-barres 1D laser bon marché ne peuvent pas lire un code-barres affiché sur un écran. Avec de l’eInk, c’est peut-être possible
La carte de fidélité de mon supermarché habituel repose sur un code-barres, ce qui est peu pratique, mais heureusement le lecteur de codes-barres émule un clavier, donc je peux simplement saisir le code au clavier
Les scanners à caméra se moquent de savoir si l’éclairage du code-barres vient de la lumière ambiante, de leurs propres LED ou d’un écran rétroéclairé, alors que les systèmes à laser dépendent de la réflexion de leur propre lumière et ne fonctionnent donc pas du tout avec un écran activement rétroéclairé
Je me demande si cela fonctionne avec des écrans e-ink ou des écrans LCD passifs
À première vue, on dirait simplement une ligne rouge de type 2D, mais il semble bien que le matériel fasse toute la différence
J’ai simplement mémorisé mon numéro de compte KCLS. Cela ne doit prendre qu’une trentaine de secondes à apprendre, même si ça dépend des gens, et je pense que c’est plus rapide de cette façon
Ensuite, au lieu de scanner le code-barres, il suffit de saisir le numéro de compte, et cela prendra probablement moins de temps que de sortir son téléphone et le préparer
Je ne sais pas si la SPL fonctionne de la même manière. Je n’habite pas à Seattle, donc je ne peux pas vérifier