node.jsでPassbookサーバをつくってみる(2)

前回はPassの生成に必要なファイル(pass.json, icon.png, logo.png)の3つのファイルを準備し、Passのデザインの確認までを行いました。
今回は端末にダウンロードできるPassをどのようにサーバサイドで生成するかを説明します。なお、生成にはAppleのデベロッパーサイトで証明書を取得する必要が ありますので、ご注意ください。
あと、もちろん node.js も入れといてくださいね。

まず、Passbookに読み込ませるPassファイルの構造から説明します。
Passファイルの構造は普通のZipファイルになっています。Zipファイル内に必要なファイル(pass.jsonやicon.png)を固めて端末に送信しています。実際に前回作ったPassファイルの中身を unzip -l してみると…

asuna:Passes tetsuo$ unzip -l hoge.pkpass
Archive:  hoge.pkpass
  Length     Date   Time    Name
 --------    ----   ----    ----
    10421  10-23-12 06:23   icon.png
     6458  10-23-12 06:09   logo.png
      180  10-23-12 06:23   manifest.json
     1255  10-23-12 06:10   pass.json
     3201  10-23-12 06:23   signature
 --------                   -------
    21515                   5 files
asuna:Passes tetsuo$

というような構成になっています。
「あれ??」と思ったかたは正解。前回作成したpass.json,icon.png,logo.png以外にもファイルがあることがわかります。
これらはPassファイルの正当性を確認するファイルとなります。manifest.jsonは各ファイルのハッシュ値を保管しているファイルで、signatureはそのmanifest.jsonファイルに対してAppleから取得した鍵で署名を行った結果が保存されています。
Passファイル をunzipしてmanifest.jsonファイルを確認してみると、以下のような内容になっています。

asuna:tmp tetsuo$ cat manifest.json 
{
  "logo.png" : "b99c26ce89c9b380b6c268688fc3cc63e9de2085",
  "pass.json" : "38a0a1b1df5eb1f06c1f23c1eba0562f4dc05069",
  "icon.png" : "a2f6f194ec915de4a49a2325103b511101e82cde"
}

manifest.jsonはPassを構成する各ファイルのSHA-1ハッシュ値となります。これによって各ファイルが改竄されてないかを端末側でチェックする 形となります。
signatureファイルはDER形式なので、表示はできませんがmanifest.jsonファイルの署名結果を保存し、manifest.jsonファイル自体に改竄がないかをチェックします。

つまり、Passファイルを生成するサーバでは…

  1. リクエストパラメータに応じてpass.jsonを編集
  2. Passのコンテンツファイル(pass.jsonや各種pngファイル)のSHA-1ハッシュを計算し、manifest.jsonを生成
  3. manifest.jsonをAppleから取得した鍵で署名し、signatureファイルを生成
  4. コンテンツファイルとmanifest.json,signatureの2つファイルを固めたZipアーカイブを生成
  5. Content-Typeを「application/vnd.apple.pkpass」に設定し、生成したZipアーカイブを端末に転送する

という処理が必要となります。
まずは2の処理までをJavaScriptで記述してみます。各ファイルのディレクトリ構成は以下のような前提です。

.
├── server.js
└── templates
    ├── icon.png
    ├── logo.png
    └── pass.json

1 directory, 4 files

server.jsが今回作成するサーバプログラム、templatesディレクトリ以下にコンテンツファイルを格納します。
まずはmanifest.jsonを生成する処理を記述します。

var fs = require('fs');
var crypto = require('crypto');
var util = require('util');
var manifestHash = {};

TEMPLATE_DIR = './templates/';

var files = fs.readdirSync(TEMPLATE_DIR);

files.forEach(function(file) {
    var fileData = fs.readFileSync(TEMPLATE_DIR + file);

    // SHA1 ハッシュの計算
    var sha1sum = crypto.createHash('sha1');
    sha1sum.update(fileData);
    var digest = sha1sum.digest('hex');

    manifestHash[file] = digest;
});

fs.writeFile('manifest.json', JSON.stringify(manifestHash), function (err) {
    if (err) throw err;
    console.log('manifest.json created');
});

さくっと、node server.js とタイプして実行した結果が以下となります。

asuna:nodejs tetsuo$ cat manifest.json
{ 'icon.png': 'a2f6f194ec915de4a49a2325103b511101e82cde',
  'logo.png': 'b99c26ce89c9b380b6c268688fc3cc63e9de2085',
  'pass.json': '38a0a1b1df5eb1f06c1f23c1eba0562f4dc05069' }

これでmanifest.jsonを生成する処理は完了です。
いまは直接ファイルシステムにmanifest.jsonを保管してますが、実際に使う場合は配置場所 は適宜考える必要があります。

で、次は署名する処理の説明なんですが、ちょっと長くなりそうなので一旦ここで切ります。
次回は署名する処理を記述し、実際にzipファイルを生成するまでの長い道のりを書きたいと思います。(実際にコード書くより下準備が大変なんです…)

 

tetsuo

tetsuo の紹介

こう見えてテックファームの開発チームのえらい人。
カテゴリー: iOS タグ: , , , パーマリンク

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です