From 158ee4221a0281b2df9422894350a294dc19b3fc Mon Sep 17 00:00:00 2001 From: Alexander Cerutti Date: Wed, 20 Oct 2021 00:28:49 +0200 Subject: [PATCH] Updated examples --- examples/PKPass.from.ts | 71 +++++++++++++++++++---------------- examples/PKPasses.ts | 70 +++++++++++++++++++++++++--------- examples/fields.ts | 21 ++++------- examples/localize.ts | 39 ++++--------------- examples/scratch.ts | 41 ++++++++++++-------- examples/setBarcodes.ts | 26 ++++--------- examples/setExpirationDate.ts | 25 ++++++------ examples/webserver.ts | 40 ++++++++++++++++++++ 8 files changed, 190 insertions(+), 143 deletions(-) diff --git a/examples/PKPass.from.ts b/examples/PKPass.from.ts index f10e01d..e180037 100644 --- a/examples/PKPass.from.ts +++ b/examples/PKPass.from.ts @@ -5,7 +5,7 @@ * examples, creation through templates is already shown */ -import app from "./webserver"; +import app, { getCertificates } from "./webserver"; import path from "path"; import { promises as fs } from "fs"; import { PKPass } from "passkit-generator"; @@ -62,7 +62,11 @@ async function readDirectory(filePath: string) { return dirContent.map(async (fileName) => { const content = await fs.readFile(path.resolve(filePath, fileName)); - return getObjectFromModelFile(filePath, content, 1); + return getObjectFromModelFile( + path.resolve(filePath, fileName), + content, + 2, + ); }); } @@ -70,42 +74,43 @@ async function readDirectory(filePath: string) { // *** EXAMPLE FROM NOW ON *** // // *************************** // -/** - * Reading model before answering. Maybe we need to do - * something else with it. - */ +const passTemplate = new Promise(async (resolve) => { + const modelPath = path.resolve(__dirname, `../models/examplePass.pass`); + const [modelFilesList, certificates] = await Promise.all([ + fs.readdir(modelPath), + getCertificates(), + ]); -const modelPath = path.resolve(__dirname, `../models/examplePass.pass`); + const modelRecords = ( + await Promise.all( + /** + * Obtaining flattened array of buffer records + * containing file name and the buffer itself. + * + * This goes also to read every nested l10n + * subfolder. + */ -const modelFilesList = await fs.readdir(modelPath); + modelFilesList.map((fileOrDirectoryPath) => { + const fullPath = path.resolve(modelPath, fileOrDirectoryPath); -const modelRecords = ( - await Promise.all( - /** - * Obtaining flattened array of buffer records - * containing file name and the buffer itself. - * - * This goes also to read every nested l10n - * subfolder. - */ - - modelFilesList.map((fileOrDirectoryPath) => { - const fullPath = path.resolve(modelPath, fileOrDirectoryPath); - - return readFileOrDirectory(fullPath); - }), + return readFileOrDirectory(fullPath); + }), + ) ) -) - .flat(1) - .reduce((acc, current) => ({ ...acc, ...current }), {}); + .flat(1) + .reduce((acc, current) => ({ ...acc, ...current }), {}); -/** Creating a PKPass Template */ + /** Creating a PKPass Template */ -const templatePass = new PKPass(modelRecords, { - wwdr: path.resolve(__dirname, "../../certificates/WWDR.pem"), - signerCert: path.resolve(__dirname, "../../certificates/signerCert.pem"), - signerKey: path.resolve(__dirname, "../../certificates/signerKey.pem"), - signerKeyPassphrase: "123456", + return resolve( + new PKPass(modelRecords, { + wwdr: certificates.wwdr, + signerCert: certificates.signerCert, + signerKey: certificates.signerKey, + signerKeyPassphrase: certificates.signerKeyPassphrase, + }), + ); }); app.all(async function manageRequest(request, response) { @@ -114,6 +119,8 @@ app.all(async function manageRequest(request, response) { "_" + new Date().toISOString().split("T")[0].replace(/-/gi, ""); + const templatePass = await passTemplate; + try { const pass = await PKPass.from( templatePass, diff --git a/examples/PKPasses.ts b/examples/PKPasses.ts index 5011642..1abda08 100644 --- a/examples/PKPasses.ts +++ b/examples/PKPasses.ts @@ -4,42 +4,78 @@ * Here it is showed manual model reading and * creating through another PKPass because in the other * examples, creation through templates is already shown + * + * PLEASE NOTE THAT, AT TIME OF WRITING, THIS EXAMPLE WORKS + * ONLY IF PASSES ARE DOWNLOADED FROM SAFARI, due to the + * support of PKPasses archives. To test this, you might + * need to open a tunnel through NGROK if you cannot access + * to your local machine (in my personal case, developing + * under WSL is a pretty big limitation sometimes). + * + * @TODO test again this example with next iOS 15 versions. + * Currently, pass viewer seems to be soooo bugged. + * + * https://imgur.com/bDTbcDg.jpg + * https://imgur.com/Y4GpuHT.jpg + * https://i.imgur.com/qbJMy1d.jpg + * + * Alberto, come to look at APPLE. + * + * MAMMA MIA! + * + * A feedback to Apple have been sent for this. */ -import app from "./webserver"; +import app, { getCertificates } from "./webserver"; import path from "path"; import { promises as fs } from "fs"; import { PKPass } from "passkit-generator"; -const iconFromModel = await fs.readFile( - path.resolve(__dirname, "models/exampleBooking.pass/icon.png"), -); - // *************************** // // *** EXAMPLE FROM NOW ON *** // // *************************** // +function getRandomColorPart() { + return Math.floor(Math.random() * 255); +} + async function generatePass(props: Object) { + const [iconFromModel, certificates] = await Promise.all([ + fs.readFile( + path.resolve(__dirname, "../models/exampleBooking.pass/icon.png"), + ), + getCertificates(), + ]); + const pass = new PKPass( {}, { - wwdr: path.resolve(__dirname, "../../certificates/WWDR.pem"), - signerCert: path.resolve( - __dirname, - "../../certificates/signerCert.pem", - ), - signerKey: path.resolve( - __dirname, - "../../certificates/signerKey.pem", - ), - signerKeyPassphrase: "123456", + wwdr: certificates.wwdr, + signerCert: certificates.signerCert, + signerKey: certificates.signerKey, + signerKeyPassphrase: certificates.signerKeyPassphrase, + }, + { + ...props, + description: "Example Apple Wallet Pass", + passTypeIdentifier: "pass.com.passkitgenerator", + serialNumber: "nmyuxofgna", + organizationName: `Test Organization ${Math.random()}`, + teamIdentifier: "F53WB8AE67", + foregroundColor: `rgb(${getRandomColorPart()}, ${getRandomColorPart()}, ${getRandomColorPart()})`, + labelColor: `rgb(${getRandomColorPart()}, ${getRandomColorPart()}, ${getRandomColorPart()})`, + backgroundColor: `rgb(${getRandomColorPart()}, ${getRandomColorPart()}, ${getRandomColorPart()})`, }, - props, ); pass.type = "boardingPass"; pass.transitType = "PKTransitTypeAir"; + pass.setBarcodes({ + message: "123456789", + format: "PKBarcodeFormatQR", + }); + pass.headerFields.push( { key: "header-field-test-1", @@ -93,7 +129,7 @@ app.all(async function manageRequest(request, response) { response.set({ "Content-type": pkpasses.mimeType, - "Content-disposition": `attachment; filename=${passName}.pkpass`, + "Content-disposition": `attachment; filename=${passName}.pkpasses`, }); const stream = pkpasses.getAsStream(); diff --git a/examples/fields.ts b/examples/fields.ts index 5e7003a..2c97ed6 100644 --- a/examples/fields.ts +++ b/examples/fields.ts @@ -9,7 +9,7 @@ * @Author: Alexander P. Cerutti */ -import app from "./webserver"; +import app, { getCertificates } from "./webserver"; import path from "path"; import { PKPass } from "passkit-generator"; @@ -19,24 +19,17 @@ app.all(async function manageRequest(request, response) { "_" + new Date().toISOString().split("T")[0].replace(/-/gi, ""); + const certificates = await getCertificates(); + try { const pass = await PKPass.from( { model: path.resolve(__dirname, "../models/exampleBooking"), certificates: { - wwdr: path.resolve( - __dirname, - "../../certificates/WWDR.pem", - ), - signerCert: path.resolve( - __dirname, - "../../certificates/signerCert.pem", - ), - signerKey: path.resolve( - __dirname, - "../../certificates/signerKey.pem", - ), - signerKeyPassphrase: "123456", + wwdr: certificates.wwdr, + signerCert: certificates.signerCert, + signerKey: certificates.signerKey, + signerKeyPassphrase: certificates.signerKeyPassphrase, }, }, request.body || request.params || request.query, diff --git a/examples/localize.ts b/examples/localize.ts index 4fd5d39..e18033b 100644 --- a/examples/localize.ts +++ b/examples/localize.ts @@ -4,7 +4,7 @@ * .pkpass file and check for .lproj folders */ -import app from "./webserver"; +import app, { getCertificates } from "./webserver"; import path from "path"; import { PKPass } from "passkit-generator"; /** Symbols are exported just for tests and examples. Replicate only if really needed. */ @@ -16,6 +16,8 @@ app.all(async function manageRequest(request, response) { "_" + new Date().toISOString().split("T")[0].replace(/-/gi, ""); + const certificates = await getCertificates(); + try { const pass = await PKPass.from( { @@ -24,42 +26,15 @@ app.all(async function manageRequest(request, response) { `../models/${request.params.modelName}`, ), certificates: { - wwdr: path.resolve( - __dirname, - "../../certificates/WWDR.pem", - ), - signerCert: path.resolve( - __dirname, - "../../certificates/signerCert.pem", - ), - signerKey: path.resolve( - __dirname, - "../../certificates/signerKey.pem", - ), - signerKeyPassphrase: "123456", + wwdr: certificates.wwdr, + signerCert: certificates.signerCert, + signerKey: certificates.signerKey, + signerKeyPassphrase: certificates.signerKeyPassphrase, }, }, request.body || request.params || request.query, ); - /** - * For each language you include, an .lproj folder in pass bundle - * is created or included. You may not want to add translations - * but only images for a specific language. So you create manually - * an .lproj folder in your pass model then add the language here - * below. If no translations does not get added, the folder is - * included or created but without pass.strings file. - * - * - * In this example, English does not have an .lproj folder yet and - * doesn't have nor receive translations. - * - * Text placeholders may not be showed for the english language - * (e.g. "Event" and "Location" as literal) and another language may be used instead - */ - - pass.localize("en"); - // Italian, already has an .lproj which gets included... pass.localize("it", { EVENT: "Evento", diff --git a/examples/scratch.ts b/examples/scratch.ts index 51f1d24..f6396dc 100644 --- a/examples/scratch.ts +++ b/examples/scratch.ts @@ -3,14 +3,14 @@ * by adding files later and not adding pass.json */ -import app from "./webserver"; +import app, { getCertificates } from "./webserver"; import path from "path"; import { promises as fs } from "fs"; import { PKPass } from "passkit-generator"; -const iconFromModel = await fs.readFile( - path.resolve(__dirname, "models/exampleBooking.pass/icon.png"), -); +function getRandomColorPart() { + return Math.floor(Math.random() * 255); +} app.all(async function manageRequest(request, response) { const passName = @@ -18,22 +18,33 @@ app.all(async function manageRequest(request, response) { "_" + new Date().toISOString().split("T")[0].replace(/-/gi, ""); + const [iconFromModel, certificates] = await Promise.all([ + fs.readFile( + path.resolve(__dirname, "../models/exampleBooking.pass/icon.png"), + ), + await getCertificates(), + ]); + try { const pass = new PKPass( {}, { - wwdr: path.resolve(__dirname, "../../certificates/WWDR.pem"), - signerCert: path.resolve( - __dirname, - "../../certificates/signerCert.pem", - ), - signerKey: path.resolve( - __dirname, - "../../certificates/signerKey.pem", - ), - signerKeyPassphrase: "123456", + wwdr: certificates.wwdr, + signerCert: certificates.signerCert, + signerKey: certificates.signerKey, + signerKeyPassphrase: certificates.signerKeyPassphrase, + }, + { + ...(request.body || request.params || request.query), + description: "Example Apple Wallet Pass", + passTypeIdentifier: "pass.com.passkitgenerator", + serialNumber: "nmyuxofgna", + organizationName: `Test Organization ${Math.random()}`, + teamIdentifier: "F53WB8AE67", + foregroundColor: `rgb(${getRandomColorPart()}, ${getRandomColorPart()}, ${getRandomColorPart()})`, + labelColor: `rgb(${getRandomColorPart()}, ${getRandomColorPart()}, ${getRandomColorPart()})`, + backgroundColor: `rgb(${getRandomColorPart()}, ${getRandomColorPart()}, ${getRandomColorPart()})`, }, - request.body || request.params || request.query, ); pass.type = "boardingPass"; diff --git a/examples/setBarcodes.ts b/examples/setBarcodes.ts index f784407..d7292ef 100644 --- a/examples/setBarcodes.ts +++ b/examples/setBarcodes.ts @@ -8,7 +8,7 @@ * by a string */ -import app from "./webserver"; +import app, { getCertificates } from "./webserver"; import { PKPass } from "passkit-generator"; import path from "path"; @@ -18,6 +18,8 @@ app.all(async function manageRequest(request, response) { "_" + new Date().toISOString().split("T")[0].replace(/-/gi, ""); + const certificates = await getCertificates(); + try { const pass = await PKPass.from( { @@ -26,19 +28,10 @@ app.all(async function manageRequest(request, response) { `../models/${request.params.modelName}`, ), certificates: { - wwdr: path.resolve( - __dirname, - "../../certificates/WWDR.pem", - ), - signerCert: path.resolve( - __dirname, - "../../certificates/signerCert.pem", - ), - signerKey: path.resolve( - __dirname, - "../../certificates/signerKey.pem", - ), - signerKeyPassphrase: "123456", + wwdr: certificates.wwdr, + signerCert: certificates.signerCert, + signerKey: certificates.signerKey, + signerKeyPassphrase: certificates.signerKeyPassphrase, }, }, request.body || request.params || request.query || {}, @@ -65,11 +58,6 @@ app.all(async function manageRequest(request, response) { message: "Thank you for using this package <3", format: "PKBarcodeFormatPDF417", }, - { - message: "Thank you for using this package <3", - // @ts-expect-error - format: "PKBarcodeFormatMock44617", - }, ); } diff --git a/examples/setExpirationDate.ts b/examples/setExpirationDate.ts index a42d11c..a981507 100644 --- a/examples/setExpirationDate.ts +++ b/examples/setExpirationDate.ts @@ -7,7 +7,7 @@ * have to wait two minutes. */ -import app from "./webserver"; +import app, { getCertificates } from "./webserver"; import path from "path"; import { PKPass } from "passkit-generator"; @@ -19,6 +19,8 @@ app.all(async function manageRequest(request, response) { return; } + const certificates = await getCertificates(); + const passName = request.params.modelName + "_" + @@ -32,19 +34,10 @@ app.all(async function manageRequest(request, response) { `../models/${request.params.modelName}`, ), certificates: { - wwdr: path.resolve( - __dirname, - "../../certificates/WWDR.pem", - ), - signerCert: path.resolve( - __dirname, - "../../certificates/signerCert.pem", - ), - signerKey: path.resolve( - __dirname, - "../../certificates/signerKey.pem", - ), - signerKeyPassphrase: "123456", + wwdr: certificates.wwdr, + signerCert: certificates.signerCert, + signerKey: certificates.signerKey, + signerKeyPassphrase: certificates.signerKeyPassphrase, }, }, Object.assign( @@ -62,6 +55,10 @@ app.all(async function manageRequest(request, response) { // setting the expiration pass.setExpirationDate(d); + console.log( + "EXPIRATION DATE EXPECTED:", + pass.props["expirationDate"], + ); } const stream = pass.getAsStream(); diff --git a/examples/webserver.ts b/examples/webserver.ts index af64e42..30fd9bf 100644 --- a/examples/webserver.ts +++ b/examples/webserver.ts @@ -5,6 +5,8 @@ */ import express from "express"; +import { promises as fs } from "fs"; +import path from "path"; export const app = express(); app.use(express.json()); @@ -25,3 +27,41 @@ app.route("/gen").all((req, res) => { }); export default app.route("/gen/:modelName"); +const certificatesCache: Partial<{ + signerCert: Buffer; + signerKey: Buffer; + wwdr: Buffer; + signerKeyPassphrase: string; +}> = {}; + +export async function getCertificates(): Promise { + if (Object.keys(certificatesCache).length) { + return certificatesCache; + } + + const [signerCert, signerKey, wwdr, signerKeyPassphrase] = + await Promise.all([ + fs.readFile( + path.resolve(__dirname, "../../certificates/signerCert.pem"), + "utf-8", + ), + fs.readFile( + path.resolve(__dirname, "../../certificates/signerKey.pem"), + "utf-8", + ), + fs.readFile( + path.resolve(__dirname, "../../certificates/WWDR.pem"), + "utf-8", + ), + Promise.resolve("123456"), + ]); + + Object.assign(certificatesCache, { + signerCert, + signerKey, + wwdr, + signerKeyPassphrase, + }); + + return certificatesCache; +}