From b0f997c4f3f05104bdcb98534fb8ee1ba4ce61e6 Mon Sep 17 00:00:00 2001 From: Alex Diete Date: Wed, 29 Jan 2014 16:24:30 +0100 Subject: [PATCH 1/5] Modified lib to also be able to use locals --- lib/pass.js | 73 +++++++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 59 insertions(+), 14 deletions(-) diff --git a/lib/pass.js b/lib/pass.js index b9bb30a..25ff420 100644 --- a/lib/pass.js +++ b/lib/pass.js @@ -11,6 +11,7 @@ var HTTP = require("http"); var HTTPS = require("https"); var Path = require("path"); var Zip = require("./zip"); +var async = require("async"); // Top-level pass fields. @@ -209,6 +210,8 @@ Pass.prototype.pipe = function(output) { var self = this; var zip = new Zip(output); var lastError; + var doneImages = false; + var doneLocals = false; zip.on("error", function(error) { lastError = error; @@ -237,20 +240,27 @@ Pass.prototype.pipe = function(output) { var passJson = new Buffer(JSON.stringify(this.getPassJSON()), "utf-8"); addFile("pass.json").end(passJson, "utf8"); - var expecting = 0; - for (var key in this.images) { + var pass = this + async.forEach(Object.keys(pass.images), function (key, cb) { var filename = key.replace(/2x$/, "@2x") + ".png"; - addImage(addFile(filename), this.images[key], function(error) { - --expecting; - if (error) - lastError = error; - if (expecting === 0) - doneWithImages(); - }); - ++expecting; - } + writeFile(addFile(filename), pass.images[key], cb); + }, function(err) { + if (err) { + lastError = err; + doneWithWriting(); + } else { + if(!pass.localizations) return doneWithWriting(); + pass.localizations + async.forEach(Object.keys(pass.localizations), function (key, cb) { + writeFile(addFile(key), pass.localizations[key], cb); + }, function(err) { + if (err) lastError = err; + doneWithWriting(); + }) + } + }); - function doneWithImages() { + function doneWithWriting() { if (lastError) { zip.close(); self.emit("error", lastError); @@ -285,7 +295,7 @@ Pass.prototype.render = function(response, callback) { }; -function addImage(file, source, callback) { +function writeFile(file, source, callback) { if (typeof(source) == "string" || source instanceof String) { if (/^https?:/i.test(source)) { // URL @@ -321,6 +331,41 @@ function addImage(file, source, callback) { } } +function addLocalFile(file, source, callback) { + if (typeof(source) == "string" || source instanceof String) { + if (/^https?:/i.test(source)) { + // URL + var protocol = /^https:/i.test(source) ? HTTPS : HTTP; + protocol.get(source, function(response) { + if (response.statusCode == 200) { + response.on("end", callback); + response.pipe(file); + response.resume(); + } else + callback(new Error("Server returned " + response.statusCode + " for " + source)); + }).on("error", callback); + } else { + // Assume filename + var stream = File.createReadStream(source); + stream.pipe(file); + file.on("close", callback); + } + } else if (source instanceof Buffer) { + file.on("close", callback); + file.write(source); + file.end(); + } else if (typeof(source) == "function") { + try { + source(file); + callback(); + } catch (error) { + callback(error); + } + } else { + // image is not a supported type + callback(new Error("Cannot load image " + file.filename + ", must be String (filename), Buffer or function")); + } +} // Add manifest.json and signature files. Pass.prototype.signZip = function(zip, manifest, callback) { @@ -350,7 +395,7 @@ function signManifest(template, manifest, callback) { "-passin", "pass:" + template.password ]; var sign = execFile("openssl", args, { stdio: "pipe" }, function(error, stdout, stderr) { - if (error || stderr.trim()) { + if (error) { callback(new Error(stderr)); } else { var signature = stdout.split(/\n\n/)[3]; From 8e49d526008bf429b27f20f249c1a7219848e337 Mon Sep 17 00:00:00 2001 From: Alex Diete Date: Wed, 29 Jan 2014 17:05:11 +0100 Subject: [PATCH 2/5] One line deleted --- lib/pass.js | 1 - 1 file changed, 1 deletion(-) diff --git a/lib/pass.js b/lib/pass.js index 25ff420..7b8e2dd 100644 --- a/lib/pass.js +++ b/lib/pass.js @@ -250,7 +250,6 @@ Pass.prototype.pipe = function(output) { doneWithWriting(); } else { if(!pass.localizations) return doneWithWriting(); - pass.localizations async.forEach(Object.keys(pass.localizations), function (key, cb) { writeFile(addFile(key), pass.localizations[key], cb); }, function(err) { From 06f664502ef60f9604a0224a528e5bf6655817f6 Mon Sep 17 00:00:00 2001 From: Alexander Biskop Date: Wed, 9 Jul 2014 18:37:22 +0200 Subject: [PATCH 3/5] added optional mockSignature parameter to ensure deterministic output for testing purposes --- lib/pass.js | 19 ++++++++++++------- lib/template.js | 2 +- 2 files changed, 13 insertions(+), 8 deletions(-) diff --git a/lib/pass.js b/lib/pass.js index 71ecddd..2db74f8 100644 --- a/lib/pass.js +++ b/lib/pass.js @@ -35,7 +35,8 @@ var REQUIRED_IMAGES = [ "icon", "logo" ]; // // tempplate - The template // fields - Pass fields (description, serialNumber, logoText) -function Pass(template, fields, images) { +function Pass(template, fields, images, mockSignature) { + this.mockSignature = mockSignature this.template = template; this.fields = cloneObject(fields); // Structure is basically reference to all the fields under a given style @@ -241,7 +242,7 @@ Pass.prototype.pipe = function(output) { addFile("pass.json").end(passJson, "utf8"); var pass = this - async.forEach(Object.keys(pass.images), function (key, cb) { + async.eachSeries(Object.keys(pass.images), function (key, cb) { var filename = key.replace(/2x$/, "@2x") + ".png"; writeFile(addFile(filename), pass.images[key], cb); }, function(err) { @@ -250,7 +251,7 @@ Pass.prototype.pipe = function(output) { doneWithWriting(); } else { if(!pass.localizations) return doneWithWriting(); - async.forEach(Object.keys(pass.localizations), function (key, cb) { + async.eachSeries(Object.keys(pass.localizations), function (key, cb) { writeFile(addFile(key), pass.localizations[key], cb); }, function(err) { if (err) lastError = err; @@ -272,7 +273,7 @@ Pass.prototype.pipe = function(output) { zip.on("error", function(error) { self.emit("error", error); }); - }); + }, self.mockSignature); } } }; @@ -301,7 +302,7 @@ function writeFile(file, source, callback) { var protocol = /^https:/i.test(source) ? HTTPS : HTTP; protocol.get(source, function(response) { if (response.statusCode == 200) { - file.on("close", callback); + response.on("end", callback); response.pipe(file); response.resume(); } else @@ -367,7 +368,7 @@ function addLocalFile(file, source, callback) { } // Add manifest.json and signature files. -Pass.prototype.signZip = function(zip, manifest, callback) { +Pass.prototype.signZip = function(zip, manifest, callback, mockSignature) { var json = JSON.stringify(manifest); // Add manifest.json zip.addFile("manifest.json").end(json, "utf-8"); @@ -375,7 +376,11 @@ Pass.prototype.signZip = function(zip, manifest, callback) { signManifest(this.template, json, function(error, signature) { if (!error) { // Write signature file - zip.addFile("signature").end(signature); + if (mockSignature) { + zip.addFile("signature").end(mockSignature); + } else { + zip.addFile("signature").end(signature); + } } callback(error); }); diff --git a/lib/template.js b/lib/template.js index abc9895..de2416f 100644 --- a/lib/template.js +++ b/lib/template.js @@ -51,7 +51,7 @@ Template.prototype.createPass = function(fields) { combined[k1] = this.fields[k1]; for (var k2 in fields) combined[k2] = fields[k2]; - return new Pass(this, combined, this.images); + return new Pass(this, combined, this.images, fields.mockSignature || undefined); }; From b9e4bc658f190db0990a284907bb47446aadc0ec Mon Sep 17 00:00:00 2001 From: Alexander Biskop Date: Wed, 9 Jul 2014 19:11:39 +0200 Subject: [PATCH 4/5] added optional parameter for setting file modification dates explicitly for testing purposes --- lib/pass.js | 23 ++++++++++++----------- lib/template.js | 5 +++-- 2 files changed, 15 insertions(+), 13 deletions(-) diff --git a/lib/pass.js b/lib/pass.js index 2db74f8..a4d17db 100644 --- a/lib/pass.js +++ b/lib/pass.js @@ -35,8 +35,9 @@ var REQUIRED_IMAGES = [ "icon", "logo" ]; // // tempplate - The template // fields - Pass fields (description, serialNumber, logoText) -function Pass(template, fields, images, mockSignature) { +function Pass(template, fields, images, mockSignature, mockModifiedDate) { this.mockSignature = mockSignature + this.mockModifiedDate = mockModifiedDate this.template = template; this.fields = cloneObject(fields); // Structure is basically reference to all the fields under a given style @@ -231,20 +232,20 @@ Pass.prototype.pipe = function(output) { // Construct manifest here var manifest = {}; // Add file to zip and it's SHA to manifest - function addFile(filename) { - var file = zip.addFile(filename); + function addFile(filename, modified) { + var file = zip.addFile(filename, modified); var sha = new SHAWriteStream(manifest, filename, file); return sha; } // Create pass.json var passJson = new Buffer(JSON.stringify(this.getPassJSON()), "utf-8"); - addFile("pass.json").end(passJson, "utf8"); + addFile("pass.json", self.mockModifiedDate).end(passJson, "utf8"); var pass = this async.eachSeries(Object.keys(pass.images), function (key, cb) { var filename = key.replace(/2x$/, "@2x") + ".png"; - writeFile(addFile(filename), pass.images[key], cb); + writeFile(addFile(filename, self.mockModifiedDate), pass.images[key], cb); }, function(err) { if (err) { lastError = err; @@ -252,7 +253,7 @@ Pass.prototype.pipe = function(output) { } else { if(!pass.localizations) return doneWithWriting(); async.eachSeries(Object.keys(pass.localizations), function (key, cb) { - writeFile(addFile(key), pass.localizations[key], cb); + writeFile(addFile(key, self.mockModifiedDate), pass.localizations[key], cb); }, function(err) { if (err) lastError = err; doneWithWriting(); @@ -273,7 +274,7 @@ Pass.prototype.pipe = function(output) { zip.on("error", function(error) { self.emit("error", error); }); - }, self.mockSignature); + }, self.mockSignature, self.mockModifiedDate); } } }; @@ -368,18 +369,18 @@ function addLocalFile(file, source, callback) { } // Add manifest.json and signature files. -Pass.prototype.signZip = function(zip, manifest, callback, mockSignature) { +Pass.prototype.signZip = function(zip, manifest, callback, mockSignature, mockModifiedDate) { var json = JSON.stringify(manifest); // Add manifest.json - zip.addFile("manifest.json").end(json, "utf-8"); + zip.addFile("manifest.json", mockModifiedDate).end(json, "utf-8"); // Create signature signManifest(this.template, json, function(error, signature) { if (!error) { // Write signature file if (mockSignature) { - zip.addFile("signature").end(mockSignature); + zip.addFile("signature", mockModifiedDate).end(mockSignature); } else { - zip.addFile("signature").end(signature); + zip.addFile("signature", mockModifiedDate).end(signature); } } callback(error); diff --git a/lib/template.js b/lib/template.js index de2416f..44ed891 100644 --- a/lib/template.js +++ b/lib/template.js @@ -44,14 +44,15 @@ Template.prototype.keys = function(path, password) { // Create a new pass from a template. -Template.prototype.createPass = function(fields) { +Template.prototype.createPass = function(fields, mocks) { // 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 Pass(this, combined, this.images, fields.mockSignature || undefined); + + return new Pass(this, combined, this.images, mocks && mocks.signature || undefined, mocks && mocks.modifiedDate || undefined); }; From e30295f84646f24df55773c743e2c7976fe6ab19 Mon Sep 17 00:00:00 2001 From: Ben John Date: Mon, 3 Aug 2015 18:34:02 +0200 Subject: [PATCH 5/5] Fixed for @3x images. --- lib/images.js | 25 +++++++++++++++++++------ lib/pass.js | 10 ++++++---- 2 files changed, 25 insertions(+), 10 deletions(-) diff --git a/lib/images.js b/lib/images.js index 36e8f5a..bca3d77 100644 --- a/lib/images.js +++ b/lib/images.js @@ -35,12 +35,22 @@ function applyImageMethods(constructor) { } }; - var retina = key + "2x"; - prototype[retina] = function(value) { + var retina2x = key + "2x"; + prototype[retina2x] = function(value) { if (arguments.length === 0) { - return this.images[retina]; + return this.images[retina2x]; } else { - this.images[retina] = value; + this.images[retina2x] = value; + return this; + } + }; + + var retina3x = key + "3x"; + prototype[retina3x] = function(value) { + if (arguments.length === 0) { + return this.images[retina3x]; + } else { + this.images[retina3x] = value; return this; } }; @@ -56,8 +66,11 @@ function applyImageMethods(constructor) { var files = File.readdirSync(path); files.forEach(function(filename) { var basename = Path.basename(filename, ".png"); - if (/@2x$/.test(basename) && ~IMAGES.indexOf(basename.slice(0, -3))) { - // High resolution + if (/@3x$/.test(basename) && ~IMAGES.indexOf(basename.slice(0, -3))) { + // High resolution 3x + self.images[basename.replace(/@3x$/, "3x")] = Path.resolve(path, filename); + } else if (/@2x$/.test(basename) && ~IMAGES.indexOf(basename.slice(0, -3))) { + // High resolution 2x self.images[basename.replace(/@2x$/, "2x")] = Path.resolve(path, filename); } else if (~IMAGES.indexOf(basename)) { // Normal resolution diff --git a/lib/pass.js b/lib/pass.js index a4d17db..d3562db 100644 --- a/lib/pass.js +++ b/lib/pass.js @@ -17,7 +17,7 @@ var async = require("async"); // Top-level pass fields. var TOP_LEVEL = [ "authenticationToken", "backgroundColor", "barcode", "description", "foregroundColor", "labelColor", "locations", "logoText", - "organizationName", "relevantDate", "serialNumber", + "organizationName", "relevantDate", "serialNumber", "suppressStripShine", "webServiceURL"]; // These top level fields are required for a valid pass. var REQUIRED_TOP_LEVEL = [ "description", "organizationName", "passTypeIdentifier", @@ -141,7 +141,7 @@ Fields.prototype.add = function(key, label, value, options) { // key - Field key // label - Field label (optional) // value - Field value -// Other field options (e.g. dateStyle) +// Other field options (e.g. dateStyle) Fields.prototype.get = function(key) { var fields = this.pass.structure[this.key]; if (fields) { @@ -244,7 +244,9 @@ Pass.prototype.pipe = function(output) { var pass = this async.eachSeries(Object.keys(pass.images), function (key, cb) { - var filename = key.replace(/2x$/, "@2x") + ".png"; + var filename = key.replace(/3x$/, "@3x"); + filename = filename.replace(/2x$/, "@2x"); + filename += ".png"; writeFile(addFile(filename, self.mockModifiedDate), pass.images[key], cb); }, function(err) { if (err) { @@ -257,7 +259,7 @@ Pass.prototype.pipe = function(output) { }, function(err) { if (err) lastError = err; doneWithWriting(); - }) + }) } });