Categories
Non classé

Mac App Store: soumettre l’application

Après avoir préparé l’application et implémenté la vérification du reçu, nous sommes enfin prêts à soumettre notre application à Apple pour qu’elle soit publiée sur son magasin. Cette étape n’est pas très compliquée, mais est mal documentée.

Note: Cet article a été établi en utilisant la version 3.2.5 de Xcode. Certaines procédures ont pu évoluer.

Installer Application Loader

Si ce n’est pas déjà fait, téléchargez Application Loader depuis la section Mac d’Apple Developer. À présent, dans Xcode, l’article de menu ”Build > Build & Archive” devrait être dégrisé.

Préparer l’application

Sous iTunes Connect, créez l’application et renseignez sa fiche. L’application doit se trouver dans l’état “Prepare For Upload”

Générer les certificats

Suivez les instructions d’iTunes Connect. Vous devez vous retrouver avec deux certificats dans le Trousseau d’accès: 3rd Party Mac Developer Application: MaBoite 3rd Party Mac Developer Installer: MaBoite.

Les certificats se trouvent dans le trousseau Système. Copiez-les dans le trousseau Session, autrement, Xcode ne saura pas les trouver.

Signer l’application

Retour à Xcode. Affichez la rubrique Build des infos de la cible. Pour la configuration Release: Code Signing Identity 3rd Party Mac Developer Application: MaBoite

Sélectionnez l’article de menu ”Build>Build & Archive”.

Soumettre l’application

  • Dans l’organiseur, nommez l’archive.
  • Cliquez le bouton ”Submit…”
  • Dans la boîte de dialogue, dans le menu qui donne le choix du certificat, sélectionnez “Don’t Sign” puis sélectionnez “3rd Party Mac Developer Installer: MaBoite”. Changer la sélection est nécessaire à cause d’un bug de Xcode 3.2.5. !
  • Dans l’organiseur, si un point d’interrogation apparaît à la place de l’icône de l’application: Un bug de Xcode oblige à fournir le nom complet de l’icône, avec son extension. Dans Info.plist, changez le nom de l’icône, par exemple de ”AppIcon” à ”AppIcon.icns”.

Et voilà, il n’y a plus qu’à attendre la réponse d’Apple.

Categories
Non classé

Mac App Store: vérifier le reçu

Dans l‘article précédent, je vous expliquai comment maintenir à la fois une version de votre application pour le Mac App Store et pour votre site web. Dans le présent article, nous verrons comment se prémunir du piratage de l’application en validant le reçu fourni par Apple.

Le reçu

Un répertoire _MASReceipt est incorporé au bundle de l’application téléchargée sur le Mac App Store:

.../SampleApp.app/Contents/_MASReceipt/receipt

Ce reçu constitue la pierre angulaire de la protection anti-pirate. Il s’agit de vérifier qu’il a bien été émis par Apple et que son contenu correspond bien à notre application. Malheureusement, Apple ne fournit pas d’API pour effectuer ces vérifications. Devant la difficulté de concevoir un service invulnérable, Apple a baissé les bras et s’est déchargée du travail sur nos épaules de développeurs. C’est donc à chaque application de faire les vérifications, qui n’ont rien de trivial!

Code d’exemple de Roddi

Apple a rédigé un document (réservé aux développeurs inscrits) qui décrit le contenu d’un reçu et les étapes de la validation. Comme vous le verrez, les indications pour l’implémentation concrète sont laconiques. Le but avoué est d’éviter que tous les développeurs utilisent le même code de validation. Le problème, c’est que peu de développeurs possèdent les connaissances nécessaires pour implémenter ces vérifications. Face à cette complexité, des développeurs ont décidé de créer une solution open-source: Roddi-ValidateStoreReceipt. On trouve aussi cet exemple d’Alan Quatermain, qui fut précurseur mais est moins abouti. Attention toutefois, il ne faut en aucun cas réutiliser ce code tel quel: il serait trop facile à repérer et modifier.

Les étapes de la validation

Comparons un peu la solution de Roddi et les préconisations d’Apple.

Vérifier la signature du reçu

Apple donne quelques indications pour vérifier la signature du reçu en utilisant OpenSSL, et indique qu’il faut utiliser le certificat Apple Root CA, mais pas comment l’obtenir. Le code de Roddi va chercher le certificat dans le Trousseau. Celui de Quatermain le récupère sur le site d’Apple, ce qui présente le défaut d’exiger un accès à Internet au lancement de l’appli.

Extraire les informations de la “Payload”

La partie “Payload” du reçu comprend les informations que nous allons vérifier par la suite: Bundle Identifier, version de l’appli, une valeur opaque (=aléatoire) et un hâchage. Apple préconise l’utilisation d’un obscur outil en ligne de commande, asn1c, pour décomposer la Payload. J’ai installé macports, installé asn1c et généré grâce à lui un fichier C permettant la décomposition.

Voici mon constat:

  • ne vous ennuyez pas à installer asn1c. Le code C qu’il a génèré est intégré au projet de Quatermain.
  • le code produit est dégueulasse. À vous les warnings de GCC dans tous les sens. Roddi a adopté une autre solution: la Payload est décomposée grâce à OpenSSL, ce qui dispense d’embarquer le code d’asn1c dans votre projet.

Vérifier le Bundle Identifier et la version

Comparez le Bundle Identifier de votre appli (pour moi, ”com.ceroce.PortraiMatic”) à celui du reçu. Ceci garantit que le reçu correspond bien à votre appli, et qu’on n’a pas remplacé le reçu de votre appli par celui d’une autre appli… (Hein, Angry Birds!) Faites de même pour la version: vous ne voudriez pas que l’utilisateur utilise le reçu de la version 1.5.3 pour valider la version 2.1.0… Il peut être tentant de récupérer ces deux informations depuis Info.plist: mauvaise idée. Ce fichier peut être modifié sans impact sur le reçu. Stockez le Bundle Identifier et la version ”en dur” dans votre code. De même, évitez — en les obscurcissant — que ces deux chaînes apparaissent quand on ouvre l’application avec un éditeur hexa. Notez que le code de Roddi compare les chaînes en dur avec celles d’Info.plist pour éviter les étourderies.

Vérifier le GUID

Le GUID est en fait l’adresse mac de l’ordinateur autorisé. Pour une fois, Apple fournit du code pour la récupérer (adopté tel quel chez Roddi). Il faut concaténer le GUID + la valeur opaque + Bundle Identifier et appliquer au tout un hâchage SHA-1. Ce hâchage doit correspondre au hâchage stocké dans la payload. !!! En conclusion Nous l’avons vu, la validation n’est pas facile. Heureusement, d’autres ont déjà essuyé les plâtres! Peut-être qu’Apple nous proposera une solution plus simple dans un avenir proche.

Categories
Non classé

Adapter son appli au Mac App Store

Si vous proposiez déjà une application pour Mac et que vous souhaitez qu’elle soit disponible sur le Mac App Store, quelques modifications s’avèrent nécessaires. Le présent article prodigue quelques astuces pour créer la version pour le magasin d’Apple, tout en conservant la version distribuée sur votre site web.

S’assurer que l’application peut être commercialisée sur le MAS

Avant toute chose, il faut vous assurer que votre application pourra respecter les restrictions d’Apple. Il s’agit essentiellement que son installation puisse se faire par une simple copie.

BWToolkit

Apple interdit d’appeler des méthodes privées de ses API. Il se trouve justement qu’une framework très populaire, BWToolkit, fait appel à quelques API privées de NSTokenAttachmentCell. L’auteur est au courant; en attendant, il est possible de recompiler la framework en supprimant le code en défaut.

Enregistrement des données

Comme je l’expliquai, le but d’Apple est que la désinstallation de l’application soit aussi simple que sous iOS. Elle impose pour cela des restrictions quant aux répertoires destinés à accueillir les données de l’utilisateur. Pour ma part, j’ai dû changer le chemin d’enregistrement de la galerie des portraits de utilisateur/ Documents à utilisateur/ Bibliothèque/ Application Support/ PortraiMatic.

Nouvelle configuration ou nouvelle cible ?

Passons aux choses sérieuses. Apple impose que l’application pour le MAS ne contienne pas:

  • de code PowerPC. Le MAS n’étant disponible qu’à partir de Mac OS 10.6.6, qui ne tourne que sur processeurs Intel.
  • des frameworks pour mettre à jour l’application. Ici, on parle évidemment de Sparkle, dont l’absence est vérifiée par les validateurs d’Apple.
  • des messages/boites de dialogues qui invitent à entrer un code de débridage. Ma première idée fut de créer une nouvelle “build configuration” pour le MAS. Seulement, cette tactique fonctionne mal: il est difficile de retirer des éléments. Par exemple, pour retirer Sparkle, il faudrait ajouter un script qui supprime la framework de l’application. Tout est à l’avenant: par exemple, il faut retirer des Préférences les rubriques liées aux Mises à jour et au débridage du logiciel. Finalement, il est plus simple de créer une cible (target) spécifique au MAS, pour incorporer ou retirer des fichiers à volonté.

Création d’une nouvelle cible

Dupliquez la cible actuelle par un clic droit > Duplicate Target. Renommez-la, en quelque chose comme MonAppMAS.

Modifier les configurations de la cible MAS

Affichez les build configurations de la cible. Nous modifions toutes les configurations (Debug, Release…).

Architectures i386 x86_64
Nous compilons pour les architectures Intel 32 et 64 bits.

Base SDK Mac OS 10.6
Le MAS n’étant disponible qu’à partir de 10.6.6, adoptons la dernière version du SDK.

Valid Architectures i386 x86_64
Liste des architectures éventuellement à compiler. Seules celles qui se trouvent à la fois dans cette liste et dans ‘Architectures’ seront compilées.

Build Locations Build Product Path build/MAS
Nous créons un sous-dossier dans le répertoire Build pour la version réservée au MAS. Modifiez également ce paramètre pour la cible originelle, par exemple en build/MonSite. En effet, certaines ressources sont références par des chemins relatifs au répertoire Build; il faut alors que le Build Product soit enfoui dans un même nombre de sous-répertoires.

GCC 4.2 – Preprocessing Preprocessor Macros Not Used in Precompiled Header MAC_APP_STORE
Je définis un symbole MAC_APP_STORE qui sera utilisé dans le code pour faire de la compilation conditionnelle:

#ifdef MAC_APP_STORE 
NSLog(@"Version pour le Mac App Store"); 
#else 
NSLog(@"Version pour mon site web"); 
#endif

Packaging Info.plist File Info.plist
En dupliquant la cible, Xcode a aussi créé un deuxième fichier Info.plist. Nous n’en voulons qu’un seul pour les deux cibles, aussi nous supprimons ce deuxième fichier et déclarons le même fichier.

Preprocess Info.plist File YES
Ceci active une étape de pré-traitement sur le fichier Info.plist. Nous l’activons pour permettre sa compilation conditionnelle.

Info.plist Other Preprocessor Flags -traditional
Une fois le pré-traitement activé, le compilateur considère que les // indiquent le début de commentaires. Cela pose problème avec les URL (http://monsite.com). Passer le drapeau -traditional au compilateur l’oblige à considérer que les commentaires ne peuvent être délimités que par /* et */ comme dans le langage C traditionnel. Plus d’infos par ici.

Info.plist Preprocess Definitions MAC_APP_STORE
Nous définissons le symbole MAC_APP_STORE pour la compilation d’Info.plist.

Search Paths Framework Search Paths
Il faut reprendre ces chemins pour supprimer les frameworks inutiles (ex. Sparkle.framework) mais également pour supprimer les / que Xcode ajoute malencontreusement aux chemins, lors de la duplication de la cible. Il s’agit d’un bogue de Xcode 3.2.5.

Editer Info.plist

Les réglages plus haut permettent l’utilisation de la compilation conditionnelle. Clic doit sur Info.plist > Open As > Source Code File…

#ifdef MAC_APP_STORE 
<LSMinimumSystemVersion> <10.6.6>
<LSApplicationCategoryType><public.app-category.photography>
#else 
<LSMinimumSystemVersion><10.5.0>
<SUEnableAutomaticChecks>
<SUPublicDSAKeyFile><dsa_pub.pem>
<SUFeedURL><http://ceroce.com/portraimatic/appcast.xml>
#endif

N’avoir qu’un seul Info.plist est intéressant parce que seule une poignée de clef sont différentes pour la MAS.

Retirer les sources et ressources inutiles

Demandez les infos sur le fichier source ou ressource pour le retirer de la cible à laquelle il n’appartient pas et donc réduire la taille de l’application. À noter qu’il peut être nécessaire de créer deux fichiers ressources. Par exemple, j’ai dû créer un fichier PreferencesMAS.xib, pour que ne soient pas affichées les rubriques liées aux Mises à jour de l’application.

Pour la suite

À ce stade, vous devriez avoir deux applications bien différenciées. Il reste encore deux étapes avant la soumission à Apple:

  • signer l’application
  • implémenter la vérification du reçu d’Apple

Ce sont deux étapes complexes qui feront l’objet d’un autre article.

20 mai 2011: Mise à jour

Voici quelques précisions supplémentaires sur Info.plist et sa compilation conditionnelle:

  • J’ai fait une fausse manipulation pour la version PortraiMatic actuellement proposée sur le MAS: j’avais bien modifié le fichier Info.plist comme indiqué ci-dessus; cependant j’ai eu le malheur d’afficher son contenu dans Xcode en mode ”graphique” et d’enregistrer, si bien qu’Xcode a fait disparaître sa compilation conditionnelle. De fait, les clefs de Sparkle apparaissent dans l’Info.plist et la version minimum du système d’exploitation est fixée à 10.5. Apple a validé cette application sans broncher.
  • Louka Desroziers a eu quelques soucis, en voulant imbriquer des #ifdef. Il faut absolument qu’ils soient placés en début de ligne (sans espace avant).
Categories
Non classé

Piratage sur le MAS

À peine le Mac App Store fut il lancé que des pirates annoncèrent triomphalement voir réussi à cracker de nombreuses applications, dont un célèbre jeu sous iOS, dorénavant disponible sur Mac. Contrairement à ce qu’on a pu lire sur trop de sites, la sécurité du MAS n’a pas été déjouée; il s’agit d’une incompétence des développeurs.

Voici ce que doit faire une application à son lancement, ”au minimum”:

  1. vérifier que le reçu (“receipt”) de l’application qui se trouve dans _MASReceipt est présent
  2. vérifier qu’il a été signé par Apple
  3. vérifier que le CFBundleIdentifier du fichier Info.plist correspond bien à l’application.
  4. Pour pouvoir comparer, il faut stocker cet identifiant dans le code de l’appli
  5. vérifier le numéro de version
  6. vérifier que le GUID (n° d’identification de l’ordinateur) correspond à celui du reçu.

D’après la procédure de piratage qu’on m’a transmise, ces applications n’effectuent vraisemblablement pas la 3e vérification. Sachant que ces consignes ont été données par Apple depuis des mois, je ne peux m’empêcher de penser que cet “oubli” est volontaire. Il s’agit probablement d’une manière de faire parler de ces logiciels, selon la maxime de Richard Branson: “parlez de moi. En bien ou en mal, mais parlez de moi”.