diff --git a/CHANGELOG.md b/CHANGELOG.md index 5341b40..9af0494 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,19 +1,22 @@ -## 1.2.0 October 26, 2012 +## 2.0.0 November 1, 2012 New API for updating structure fields: passbook.headerFields.add("time", "The Time", "10:00AM"); - passbook.backFields.add("url", "Web site", "http://example.com"); + passbook.backFields.add({ key: "url", label: "Web site", value: "http://example.com" }); console.log(passbook.backFields.get("url")); passbook.backFields.remove("url"); console.log(passbook.backFields.all()); -passbook.pipe is now passbook.writeToOutputStream, which better reflects what it -does. +The `pipe` method no longer accepts a callback, instead, register listener on +the `end` and `error` events. -Added passbook.render to render a Passbook to an HTTP response. +For HTTP servers, you can use the `render` method. -Should send complete bufferred resources first. +New optimization to send completes resources first (useful when downloading +images from URLs). + +Renamed `createPassbook` to `createPass`. ## 1.1.1 October 24, 2012 diff --git a/README.md b/README.md index 33aba4c..1709990 100644 --- a/README.md +++ b/README.md @@ -21,7 +21,7 @@ This is the same directory into which you placet the `.p12` files. # Start with a template Start with a template. A template has all the common data fields that will be -shared between your passbook, and also defines the keys to use for signing it. +shared between your passes, and also defines the keys to use for signing it. ``` var createTemplate = require("passbook"); @@ -29,84 +29,134 @@ var createTemplate = require("passbook"); var template = createTemplate("coupon", { passTypeIdentifier: "pass.com.example.passbook", teamIdentifier: "MXL", - "backgroundColor": "rgb(255,255,255)" + backgroundColor: "rgb(255,255,255)" }); -template.keys("/etc/passbook/keys", "secret"); ``` -The first argument is the Passbook style (`coupon`, `eventTicket`, etc), and the -second optional argument has any fields you want to set on th template. +The first argument is the pass style (`coupon`, `eventTicket`, etc), and the +second optional argument has any fields you want to set on the template. You can access template fields directly, or from chained accessor methods, e.g: ``` template.fields.passTypeIdentifier = "pass.com.example.passbook"; + console.log(template.passTypeIdentifier()); + template.teamIdentifier("MXL"). passTypeIdentifier("pass.com.example.passbook") ``` -The template fields are `passTypeIdentifier`, `teamIdentifier`, -`backgroundColor`, `foregroundColor`, `labelColor`, `logoText`, -`organizationName`, `suppressStripShine` and `webServiceURL`. +The following template fields are required: +`passTypeIdentifier` - The Passbook Type ID, begins with "pass." +`teamIdentifier` - May contain an I + +Optional fields that you can set on the template (or pass): `backgroundColor`, +`foregroundColor`, `labelColor`, `logoText`, `organizationName`, +`suppressStripShine` and `webServiceURL`. -The first two are required: `passTypeIdentifier` is the Passbook Type ID, begins -with "pass." and has to be registered with Apple. The `teamIdentifier` may -contain an I. +In addition, you need to tell the template where to find the key files and where +to load images from: -All other fields can be set on either template or passbook. +``` +template.keys("/etc/passbook/keys", "secret"); +template.loadImagesFrom("images"); +``` +The last part is optional, but if you have images that are common to all passes, +you may want to specify them once in the template. -# Create your passbook -To create a new passbook from a template: +# Create your pass + +To create a new pass from a template: ``` -var passbook = template.createPassbook({ +var pass = template.createPass({ serialNumber: "123456", description: "20% off" }); ``` -Just like template, you can access Passbook fields directly, or from chained +Just like template, you can access pass fields directly, or from chained accessor methods, e.g: ``` -passbook.fields.serialNumber = "12345"; -console.log(passbook.serialNumber()); -passbook.serialNumber("12345"). +pass.fields.serialNumber = "12345"; +console.log(pass.serialNumber()); +pass.serialNumber("12345"). description("20% off"); ``` -You can also access structure fields directly, or from chained accessor methods. -The following three are equivalent: +In the JSON specification, structure fields (primary fields, secondary fields, +etc) are represented as arrays, but items must have distinct key properties. Le +sigh. + +To make it easier, you can use methods like `add`, `get` and `remove` that +will do the logical thing. For example, to add a primary field: ``` -passbook.fields.coupon.headerFields = header; -passbook.structure.headerFields = header; -passbook.headerFields(header); +pass.primaryFields.add("date", "Date", "Nov 1"); +pass.primaryFields.add({ key: "time", label: "Time", value: "10:00AM"); +``` + +You can also call `add` with an array of triplets or array of objects. + +To get one or all fields: + ``` +var dateField = pass.primaryFields.get("date"); +var allFields = pass.primaryFields.all(); +``` + +To remove one or all fields: + +``` +pass.primaryFields.remove("date"); +pass.primaryFields.clear(); +``` + +Adding images to a pass is the same as adding images to a template: + +``` +pass.images.icon = iconFilename; +pass.icon(iconFilename); +pass.loadImagesFrom("images"); +``` + +You can add the image itself (a `Buffer`), or provide the name of a file or an +HTTP/S URL for retrieving the image. You can also provide a function that will +be called when it's time to load the image, and should pass an error, or `null` +and a buffer to its callback. + + +# Generate the file -Same drill when it comes to adding images to your Passbook: +To generate a file: ``` -passbook.images.icon = iconFilename; -passbook.icon(iconFilename); +var file = File.createWriteStream("mypass.pkpass"); +passbook.on("error", function(error) { + console.error(error); + process.exit(1); +}) +passbook.pipe(output); ``` -You can add the image itself (`Buffer`), the name of a file containing the image -(`String`), or a function that will be called to load the image, and should pass -an error, or `null` and a `Buffer` to its callback. +Your pass will emit the `error` event if it fails to generate a valid Passbook +file, and emit the `end` event when it successfuly completed generating the +file. -Finally, to generate a Passbook file: +You can pipe to any writeable stream. When working with HTTP, the `render` +method will set the content type, pipe to the HTTP response, and make use of a +callback (if supplied). ``` -passbook.generate(function(error, buffer) { - if (error) { - console.log(error); - } else { - File.writeFile("passbook.pkpass", buffer); - } +server.get("/mypass", function(request, response) { + passbook.render(response, function(error) { + if (error) + console.error(error); + }); }); ``` diff --git a/lib/images.js b/lib/images.js index 4e1851d..36e8f5a 100644 --- a/lib/images.js +++ b/lib/images.js @@ -17,14 +17,14 @@ function applyImageMethods(constructor) { // Call with an argument to set the image and return self, call with no // argument to get image value. // - // passbook.icon(function(callback) { ... }; - // console.log(passbook.icon()); + // pass.icon(function(callback) { ... }; + // console.log(pass.icon()); // // The 2x suffix is used for high resolution version (file name uses @2x // suffix). // - // passbook.icon2x("icon@2x.png"); - // console.log(passbook.icon2x()); + // pass.icon2x("icon@2x.png"); + // console.log(pass.icon2x()); IMAGES.forEach(function(key) { prototype[key] = function(value) { if (arguments.length === 0) { diff --git a/lib/index.js b/lib/index.js index 7f564b7..542dcda 100644 --- a/lib/index.js +++ b/lib/index.js @@ -1,16 +1,15 @@ // Exports function for creating a new template, from which you can create new -// passbooks. +// passes. var Template = require("./template"); // Create a new template. // -// style - Passbook style (coupon, eventTicket, etc) -// fields - Passbook fields (passTypeIdentifier, teamIdentifier, etc) +// style - Pass style (coupon, eventTicket, etc) +// fields - Pass fields (passTypeIdentifier, teamIdentifier, etc) function createTemplate(style, fields) { return new Template(style, fields); } module.exports = createTemplate; - diff --git a/lib/passbook.js b/lib/pass.js similarity index 74% rename from lib/passbook.js rename to lib/pass.js index df49633..7b0de99 100644 --- a/lib/passbook.js +++ b/lib/pass.js @@ -1,5 +1,8 @@ +// Generate a pass file. + var applyImageMethods = require("./images"); var Crypto = require("crypto"); +var EventEmitter = require("events").EventEmitter; var execFile = require("child_process").execFile; var Stream = require("stream"); var inherits = require("util").inherits; @@ -10,28 +13,28 @@ var Path = require("path"); var Zip = require("./zip"); -// Top-level passbook fields. +// Top-level pass fields. var TOP_LEVEL = [ "authenticationToken", "backgroundColor", "barcode", "description", "foregroundColor", "labelColor", "locations", "logoText", "organizationName", "relevantDate", "serialNumber", "suppressStripShine", "webServiceURL"]; -// These top level fields are required for a valid passbook +// These top level fields are required for a valid pass. var REQUIRED_TOP_LEVEL = [ "description", "organizationName", "passTypeIdentifier", "serialNumber", "teamIdentifier" ]; -// Passbook structure keys. +// Pass structure keys. var STRUCTURE_FIELDS = [ "auxiliaryFields", "backFields", "headerFields", "primaryFields", "secondaryFields" ]; -// These images are required for a valid passbook. +// These images are required for a valid pass. var REQUIRED_IMAGES = [ "icon", "logo" ]; -// Create a new passbook. +// Create a new pass. // // tempplate - The template -// fields - Passbook fields (description, serialNumber, logoText) -function Passbook(template, fields, images) { +// fields - Pass fields (description, serialNumber, logoText) +function Pass(template, fields, images) { this.template = template; this.fields = cloneObject(fields); // Structure is basically reference to all the fields under a given style @@ -44,7 +47,8 @@ function Passbook(template, fields, images) { this.images = cloneObject(images); } -applyImageMethods(Passbook); +inherits(Pass, EventEmitter); +applyImageMethods(Pass); // Accessor methods for top-level fields (description, serialNumber, logoText, @@ -53,10 +57,10 @@ applyImageMethods(Passbook); // Call with an argument to set field and return self, call with no argument to // get field value. // -// passbook.description("Unbelievable discount"); -// console.log(passbook.description()); +// pass.description("Unbelievable discount"); +// console.log(pass.description()); TOP_LEVEL.forEach(function(key) { - Passbook.prototype[key] = function(value) { + Pass.prototype[key] = function(value) { if (arguments.length === 0) { return this.fields[key]; } else { @@ -70,38 +74,61 @@ TOP_LEVEL.forEach(function(key) { // // For example: // -// passbook.headerFields.add("time", "The Time", "10:00AM"); -// passbook.backFields.add("url", "Web site", "http://example.com"); +// pass.headerFields.add("time", "The Time", "10:00AM"); +// pass.backFields.add("url", "Web site", "http://example.com"); STRUCTURE_FIELDS.forEach(function(key) { - Passbook.prototype.__defineGetter__(key, function() { + Pass.prototype.__defineGetter__(key, function() { return new Fields(this, key); }); }); // Field accessors. -function Fields(passbook, key) { - this.passbook = passbook; +function Fields(pass, key) { + this.pass = pass; this.key = key; } // Adds a field to the end of the list. // +// You can call this method with three/four arguments: // key - Field key // label - Field label (optional) // value - Field value -// options - Other field options (e.g. dateStyle) +// options - Other field options (e.g. dateStyle) +// +// You can call this method with a single object that contains all field +// properties (key, label, etc). +// +// You can also call with an array of either one. +// +// Returns self. Fields.prototype.add = function(key, label, value, options) { - this.remove(key); - var field = { key: key, value: value }; - if (label) - field.label = label; - if (options) { - for (var k in options) - field[k] = options[k]; + var field, k; + if (arguments.length > 1) { + this.remove(key); + field = { key: key, value: value }; + if (label) + field.label = label; + if (options) { + for (k in options) + field[k] = options[k]; + } + this.all().push(field); + } else if (Array.isArray(arguments[0])) { + var array = arguments[0]; + for (var i in array) + this.add.call(this, array[i]); + } else { + var properties = arguments[0]; + key = properties.key; + this.remove(key); + field = {}; + for (k in properties) + field[k] = properties[k]; + this.all().push(field); } - this.all().push(field); return this; }; @@ -113,7 +140,7 @@ Fields.prototype.add = function(key, label, value, options) { // value - Field value // Other field options (e.g. dateStyle) Fields.prototype.get = function(key) { - var fields = this.passbook.structure[this.key]; + var fields = this.pass.structure[this.key]; if (fields) { for (var i in fields) { var field = fields[i]; @@ -126,15 +153,15 @@ Fields.prototype.get = function(key) { // Returns an array of all fields. Fields.prototype.all = function() { - var fields = this.passbook.structure[this.key]; + var fields = this.pass.structure[this.key]; if (!fields) - this.passbook.structure[this.key] = fields = []; + this.pass.structure[this.key] = fields = []; return fields; }; // Removes a given field. Fields.prototype.remove = function(key) { - var fields = this.passbook.structure[this.key]; + var fields = this.pass.structure[this.key]; if (fields) { for (var i in fields) { if (fields[i].key == key) { @@ -148,13 +175,13 @@ Fields.prototype.remove = function(key) { // Removes all fields. Fields.prototype.clear = function() { - this.passbook.structure[this.key] = []; + this.pass.structure[this.key] = []; return this; }; -// Validate passbook, throws error if missing a mandatory top-level field or image. -Passbook.prototype.validate = function() { +// Validate pass, throws error if missing a mandatory top-level field or image. +Pass.prototype.validate = function() { for (var i in REQUIRED_TOP_LEVEL) { var k1 = REQUIRED_TOP_LEVEL[i]; if (!this.fields[k1]) @@ -168,18 +195,17 @@ Passbook.prototype.validate = function() { }; // Returns the pass.json object (not a string). -Passbook.prototype.getPassbookJSON = function() { +Pass.prototype.getPassJSON = function() { var fields = cloneObject(this.fields); fields.formatVersion = 1; return fields; }; -// Generate Passbook file and stream it to output stream. +// Pipe pass to a write stream. // -// output - Output stream -// callback - Optional, notified when done writing -Passbook.prototype.writeToOutputStream = function(output, callback) { +// output - Write stream +Pass.prototype.pipe = function(output) { var self = this; var zip = new Zip(output); var lastError; @@ -189,7 +215,15 @@ Passbook.prototype.writeToOutputStream = function(output, callback) { }); // Validate before attempting to create - this.validate(); + try { + this.validate(); + } catch (error) { + process.nextTick(function() { + self.emit("error", error); + }); + return; + } + // Construct manifest here var manifest = {}; // Add file to zip and it's SHA to manifest @@ -200,7 +234,7 @@ Passbook.prototype.writeToOutputStream = function(output, callback) { } // Create pass.json - var passJson = new Buffer(JSON.stringify(this.getPassbookJSON()), "utf-8"); + var passJson = new Buffer(JSON.stringify(this.getPassJSON()), "utf-8"); addFile("pass.json").end(passJson, "utf8"); var expecting = 0; @@ -219,27 +253,35 @@ Passbook.prototype.writeToOutputStream = function(output, callback) { function doneWithImages() { if (lastError) { zip.close(); - callback(lastError); + self.emit("error", lastError); } else { self.signZip(zip, manifest, function(error) { zip.close(); - zip.on("end", callback); - zip.on("error", callback); + zip.on("end", function() { + self.emit("end"); + }); + zip.on("error", function(error) { + self.emit("error", error); + }); }); } } }; -// Use this to send Passbook as HTTP response. +// Use this to send pass as HTTP response. // // response - HTTP response // callback - Called when done sending/error occurred // -// Adds appropriate headers and pipes Passbook to response. -Passbook.prototype.render = function(response, callback) { +// Adds appropriate headers and pipes pass to response. +Pass.prototype.render = function(response, callback) { response.setHeader("Content-Type", "application/vnd.apple.pkpass"); - this.writeToOutputStream(response, callback); + if (callback) { + this.on("error", callback); + this.on("end", callback); + } + this.pipe(response); }; @@ -280,7 +322,7 @@ function addImage(file, source, callback) { // Add manifest.json and signature files. -Passbook.prototype.signZip = function(zip, manifest, callback) { +Pass.prototype.signZip = function(zip, manifest, callback) { var json = JSON.stringify(manifest); // Add manifest.json zip.addFile("manifest.json").end(json, "utf-8"); @@ -369,4 +411,4 @@ SHAWriteStream.prototype.end = function(buffer, encoding) { }; -module.exports = Passbook; +module.exports = Pass; diff --git a/lib/template.js b/lib/template.js index 6f42cf3..abc9895 100644 --- a/lib/template.js +++ b/lib/template.js @@ -2,7 +2,7 @@ var applyImageMethods = require("./images"); -var Passbook = require("./passbook"); +var Pass = require("./pass"); // Supported passbook styles. @@ -15,11 +15,11 @@ var TEMPLATE = [ "passTypeIdentifier", "teamIdentifier", // Create a new template. // -// style - Passbook style (coupon, eventTicket, etc) -// fields - Passbook fields (passTypeIdentifier, teamIdentifier, etc) +// style - Pass style (coupon, eventTicket, etc) +// fields - Pass fields (passTypeIdentifier, teamIdentifier, etc) function Template(style, fields) { if (!~STYLES.indexOf(style)) - throw new Error("Unsupported passbook style " + style); + throw new Error("Unsupported pass style " + style); this.style = style; this.fields = {}; for (var key in fields) @@ -43,15 +43,15 @@ Template.prototype.keys = function(path, password) { }; -// Create a new passbook from a template. -Template.prototype.createPassbook = function(fields) { - // Combine template and passbook fields +// Create a new pass from a template. +Template.prototype.createPass = function(fields) { + // Combine template and pass fields var combined = {}; for (var k1 in this.fields) combined[k1] = this.fields[k1]; for (var k2 in fields) combined[k2] = fields[k2]; - return new Passbook(this, combined, this.images); + return new Pass(this, combined, this.images); }; @@ -75,4 +75,3 @@ TEMPLATE.forEach(function(key) { module.exports = Template; - diff --git a/test/passbook_test.js b/test/pass_test.js similarity index 60% rename from test/passbook_test.js rename to test/pass_test.js index ff56464..b9b5b4e 100644 --- a/test/passbook_test.js +++ b/test/pass_test.js @@ -5,7 +5,7 @@ var execFile = require("child_process").execFile; var File = require("fs"); -describe("Passbook", function() { +describe("Pass", function() { before(function() { this.template = createTemplate("coupon", { passTypeIdentifier: "pass.com.example.passbook", @@ -21,29 +21,29 @@ describe("Passbook", function() { describe("from template", function() { before(function() { - this.passbook = this.template.createPassbook(); + this.pass = this.template.createPass(); }); it("should copy template fields", function() { - assert.equal(this.passbook.fields.passTypeIdentifier, "pass.com.example.passbook"); + assert.equal(this.pass.fields.passTypeIdentifier, "pass.com.example.passbook"); }); it("should start with no images", function() { - assert.deepEqual(this.passbook.images, {}); + assert.deepEqual(this.pass.images, {}); }); it("should create a structure based on style", function() { - assert(this.passbook.fields.coupon); - assert(!this.passbook.fields.eventTicket); + assert(this.pass.fields.coupon); + assert(!this.pass.fields.eventTicket); }); }); describe("without serial number", function() { it("should not be valid", function() { - var passbook = this.template.createPassbook(cloneExcept(this.fields, "serialNumber")); + var pass = this.template.createPass(cloneExcept(this.fields, "serialNumber")); try { - passbook.validate(); - assert(false, "Passbook validated without serialNumber"); + pass.validate(); + assert(false, "Pass validated without serialNumber"); } catch(ex) { assert.equal(ex.message, "Missing field serialNumber"); } @@ -52,10 +52,10 @@ describe("Passbook", function() { describe("without organization name", function() { it("should not be valid", function() { - var passbook = this.template.createPassbook(cloneExcept(this.fields, "organizationName")); + var pass = this.template.createPass(cloneExcept(this.fields, "organizationName")); try { - passbook.validate(); - assert(false, "Passbook validated without organizationName"); + pass.validate(); + assert(false, "Pass validated without organizationName"); } catch(ex) { assert.equal(ex.message, "Missing field organizationName"); } @@ -64,10 +64,10 @@ describe("Passbook", function() { describe("without description", function() { it("should not be valid", function() { - var passbook = this.template.createPassbook(cloneExcept(this.fields, "description")); + var pass = this.template.createPass(cloneExcept(this.fields, "description")); try { - passbook.validate(); - assert(false, "Passbook validated without description"); + pass.validate(); + assert(false, "Pass validated without description"); } catch(ex) { assert.equal(ex.message, "Missing field description"); } @@ -76,10 +76,10 @@ describe("Passbook", function() { describe("without icon.png", function() { it("should not be valid", function() { - var passbook = this.template.createPassbook(this.fields); + var pass = this.template.createPass(this.fields); try { - passbook.validate(); - assert(false, "Passbook validated without icon.png"); + pass.validate(); + assert(false, "Pass validated without icon.png"); } catch(ex) { assert.equal(ex.message, "Missing image icon.png"); } @@ -87,31 +87,48 @@ describe("Passbook", function() { }); describe("without logo.png", function() { + var validationError; + + before(function(done) { + var pass = this.template.createPass(this.fields); + pass.icon("icon.png"); + var file = File.createWriteStream("/tmp/pass.pkpass"); + pass.pipe(file); + pass.on("done", done); + pass.on("error", function(error) { + validationError = error; + done(); + }); + }); + it("should not be valid", function() { - var passbook = this.template.createPassbook(this.fields); - passbook.icon("icon.png"); - try { - passbook.validate(); - assert(false, "Passbook validated without logo.png"); - } catch(ex) { - assert.equal(ex.message, "Missing image logo.png"); - } + assert(validationError, "Pass validated without logo.png"); + assert.equal(validationError.message, "Missing image logo.png"); }); }); describe("generated", function() { + before(function() { + this.pass = this.template.createPass(this.fields); + this.pass.loadImagesFrom(__dirname + "/resources"); + this.pass.headerFields.add("date", "Date", "Nov 1"); + this.pass.primaryFields.add([ + { key: "location", label: "Place", value: "High ground" } + ]); + + }); + before(function(done) { - var passbook = this.template.createPassbook(this.fields); - passbook.loadImagesFrom(__dirname + "/resources"); - if (File.existsSync("/tmp/passbook.pkpass")) - File.unlinkSync("/tmp/passbook.pkpass"); - var file = File.createWriteStream("/tmp/passbook.pkpass"); - passbook.writeToOutputStream(file, done); + if (File.existsSync("/tmp/pass.pkpass")) + File.unlinkSync("/tmp/pass.pkpass"); + var file = File.createWriteStream("/tmp/pass.pkpass"); + this.pass.pipe(file); + this.pass.on("end", done); }); it("should be a valid ZIP", function(done) { - execFile("unzip", ["-t", "/tmp/passbook.pkpass"], function(error, stdout) { + execFile("unzip", ["-t", "/tmp/pass.pkpass"], function(error, stdout) { if (error) error = new Error(stdout); done(error); @@ -119,14 +136,27 @@ describe("Passbook", function() { }); it("should contain pass.json", function(done) { - unzip("/tmp/passbook.pkpass", "pass.json", function(error, buffer) { + unzip("/tmp/pass.pkpass", "pass.json", function(error, buffer) { assert.deepEqual(JSON.parse(buffer), { passTypeIdentifier: 'pass.com.example.passbook', teamIdentifier: 'MXL', serialNumber: '123456', organizationName: 'Acme flowers', description: '20% of black roses', - coupon: {}, + coupon: { + headerFields: [ + { key: "date", + label: "Date", + value: "Nov 1" + } + ], + primaryFields: [ + { key: "location", + label: "Place", + value: "High ground" + } + ] + }, formatVersion: 1 }); done(); @@ -134,9 +164,9 @@ describe("Passbook", function() { }); it("should contain a manifest", function(done) { - unzip("/tmp/passbook.pkpass", "manifest.json", function(error, buffer) { + unzip("/tmp/pass.pkpass", "manifest.json", function(error, buffer) { assert.deepEqual(JSON.parse(buffer), { - "pass.json": "bcb463e9d94298e2d9757cea4a1af501fe5b45ae", + "pass.json": "87c2bd96d4bcaf55f0d4d7846a5ae1fea85ea628", "icon.png": "e0f0bcd503f6117bce6a1a3ff8a68e36d26ae47f", "icon@2x.png": "10e4a72dbb02cc526cef967420553b459ccf2b9e", "logo.png": "abc97e3b2bc3b0e412ca4a853ba5fd90fe063551", @@ -151,14 +181,14 @@ describe("Passbook", function() { }); it("should contain a signature", function(done) { - execFile("signpass", ["-v", "/tmp/passbook.pkpass"], function(error, stdout) { + execFile("signpass", ["-v", "/tmp/pass.pkpass"], function(error, stdout) { assert(/\*\*\* SUCCEEDED \*\*\*/.test(stdout), stdout); done(); }); }); it("should contain the icon", function(done) { - unzip("/tmp/passbook.pkpass", "icon.png", function(error, buffer) { + unzip("/tmp/pass.pkpass", "icon.png", function(error, buffer) { assert.equal(Crypto.createHash("sha1").update(buffer).digest("hex"), "e0f0bcd503f6117bce6a1a3ff8a68e36d26ae47f"); done(); @@ -166,7 +196,7 @@ describe("Passbook", function() { }); it("should contain the logo", function(done) { - unzip("/tmp/passbook.pkpass", "logo.png", function(error, buffer) { + unzip("/tmp/pass.pkpass", "logo.png", function(error, buffer) { assert.equal(Crypto.createHash("sha1").update(buffer).digest("hex"), "abc97e3b2bc3b0e412ca4a853ba5fd90fe063551"); done();