Updated examples

This commit is contained in:
Alexander Cerutti
2021-10-20 00:28:49 +02:00
parent 1735a3824a
commit 158ee4221a
8 changed files with 190 additions and 143 deletions

View File

@@ -5,7 +5,7 @@
* examples, creation through templates is already shown * examples, creation through templates is already shown
*/ */
import app from "./webserver"; import app, { getCertificates } from "./webserver";
import path from "path"; import path from "path";
import { promises as fs } from "fs"; import { promises as fs } from "fs";
import { PKPass } from "passkit-generator"; import { PKPass } from "passkit-generator";
@@ -62,7 +62,11 @@ async function readDirectory(filePath: string) {
return dirContent.map(async (fileName) => { return dirContent.map(async (fileName) => {
const content = await fs.readFile(path.resolve(filePath, 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 *** // // *** EXAMPLE FROM NOW ON *** //
// *************************** // // *************************** //
/** const passTemplate = new Promise<PKPass>(async (resolve) => {
* Reading model before answering. Maybe we need to do const modelPath = path.resolve(__dirname, `../models/examplePass.pass`);
* something else with it. 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 = ( return readFileOrDirectory(fullPath);
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);
}),
) )
) .flat(1)
.flat(1) .reduce((acc, current) => ({ ...acc, ...current }), {});
.reduce((acc, current) => ({ ...acc, ...current }), {});
/** Creating a PKPass Template */ /** Creating a PKPass Template */
const templatePass = new PKPass(modelRecords, { return resolve(
wwdr: path.resolve(__dirname, "../../certificates/WWDR.pem"), new PKPass(modelRecords, {
signerCert: path.resolve(__dirname, "../../certificates/signerCert.pem"), wwdr: certificates.wwdr,
signerKey: path.resolve(__dirname, "../../certificates/signerKey.pem"), signerCert: certificates.signerCert,
signerKeyPassphrase: "123456", signerKey: certificates.signerKey,
signerKeyPassphrase: certificates.signerKeyPassphrase,
}),
);
}); });
app.all(async function manageRequest(request, response) { 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, ""); new Date().toISOString().split("T")[0].replace(/-/gi, "");
const templatePass = await passTemplate;
try { try {
const pass = await PKPass.from( const pass = await PKPass.from(
templatePass, templatePass,

View File

@@ -4,42 +4,78 @@
* Here it is showed manual model reading and * Here it is showed manual model reading and
* creating through another PKPass because in the other * creating through another PKPass because in the other
* examples, creation through templates is already shown * 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 path from "path";
import { promises as fs } from "fs"; import { promises as fs } from "fs";
import { PKPass } from "passkit-generator"; import { PKPass } from "passkit-generator";
const iconFromModel = await fs.readFile(
path.resolve(__dirname, "models/exampleBooking.pass/icon.png"),
);
// *************************** // // *************************** //
// *** EXAMPLE FROM NOW ON *** // // *** EXAMPLE FROM NOW ON *** //
// *************************** // // *************************** //
function getRandomColorPart() {
return Math.floor(Math.random() * 255);
}
async function generatePass(props: Object) { 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( const pass = new PKPass(
{}, {},
{ {
wwdr: path.resolve(__dirname, "../../certificates/WWDR.pem"), wwdr: certificates.wwdr,
signerCert: path.resolve( signerCert: certificates.signerCert,
__dirname, signerKey: certificates.signerKey,
"../../certificates/signerCert.pem", signerKeyPassphrase: certificates.signerKeyPassphrase,
), },
signerKey: path.resolve( {
__dirname, ...props,
"../../certificates/signerKey.pem", description: "Example Apple Wallet Pass",
), passTypeIdentifier: "pass.com.passkitgenerator",
signerKeyPassphrase: "123456", 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.type = "boardingPass";
pass.transitType = "PKTransitTypeAir"; pass.transitType = "PKTransitTypeAir";
pass.setBarcodes({
message: "123456789",
format: "PKBarcodeFormatQR",
});
pass.headerFields.push( pass.headerFields.push(
{ {
key: "header-field-test-1", key: "header-field-test-1",
@@ -93,7 +129,7 @@ app.all(async function manageRequest(request, response) {
response.set({ response.set({
"Content-type": pkpasses.mimeType, "Content-type": pkpasses.mimeType,
"Content-disposition": `attachment; filename=${passName}.pkpass`, "Content-disposition": `attachment; filename=${passName}.pkpasses`,
}); });
const stream = pkpasses.getAsStream(); const stream = pkpasses.getAsStream();

View File

@@ -9,7 +9,7 @@
* @Author: Alexander P. Cerutti * @Author: Alexander P. Cerutti
*/ */
import app from "./webserver"; import app, { getCertificates } from "./webserver";
import path from "path"; import path from "path";
import { PKPass } from "passkit-generator"; import { PKPass } from "passkit-generator";
@@ -19,24 +19,17 @@ app.all(async function manageRequest(request, response) {
"_" + "_" +
new Date().toISOString().split("T")[0].replace(/-/gi, ""); new Date().toISOString().split("T")[0].replace(/-/gi, "");
const certificates = await getCertificates();
try { try {
const pass = await PKPass.from( const pass = await PKPass.from(
{ {
model: path.resolve(__dirname, "../models/exampleBooking"), model: path.resolve(__dirname, "../models/exampleBooking"),
certificates: { certificates: {
wwdr: path.resolve( wwdr: certificates.wwdr,
__dirname, signerCert: certificates.signerCert,
"../../certificates/WWDR.pem", signerKey: certificates.signerKey,
), signerKeyPassphrase: certificates.signerKeyPassphrase,
signerCert: path.resolve(
__dirname,
"../../certificates/signerCert.pem",
),
signerKey: path.resolve(
__dirname,
"../../certificates/signerKey.pem",
),
signerKeyPassphrase: "123456",
}, },
}, },
request.body || request.params || request.query, request.body || request.params || request.query,

View File

@@ -4,7 +4,7 @@
* .pkpass file and check for .lproj folders * .pkpass file and check for .lproj folders
*/ */
import app from "./webserver"; import app, { getCertificates } from "./webserver";
import path from "path"; import path from "path";
import { PKPass } from "passkit-generator"; import { PKPass } from "passkit-generator";
/** Symbols are exported just for tests and examples. Replicate only if really needed. */ /** 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, ""); new Date().toISOString().split("T")[0].replace(/-/gi, "");
const certificates = await getCertificates();
try { try {
const pass = await PKPass.from( const pass = await PKPass.from(
{ {
@@ -24,42 +26,15 @@ app.all(async function manageRequest(request, response) {
`../models/${request.params.modelName}`, `../models/${request.params.modelName}`,
), ),
certificates: { certificates: {
wwdr: path.resolve( wwdr: certificates.wwdr,
__dirname, signerCert: certificates.signerCert,
"../../certificates/WWDR.pem", signerKey: certificates.signerKey,
), signerKeyPassphrase: certificates.signerKeyPassphrase,
signerCert: path.resolve(
__dirname,
"../../certificates/signerCert.pem",
),
signerKey: path.resolve(
__dirname,
"../../certificates/signerKey.pem",
),
signerKeyPassphrase: "123456",
}, },
}, },
request.body || request.params || request.query, 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... // Italian, already has an .lproj which gets included...
pass.localize("it", { pass.localize("it", {
EVENT: "Evento", EVENT: "Evento",

View File

@@ -3,14 +3,14 @@
* by adding files later and not adding pass.json * by adding files later and not adding pass.json
*/ */
import app from "./webserver"; import app, { getCertificates } from "./webserver";
import path from "path"; import path from "path";
import { promises as fs } from "fs"; import { promises as fs } from "fs";
import { PKPass } from "passkit-generator"; import { PKPass } from "passkit-generator";
const iconFromModel = await fs.readFile( function getRandomColorPart() {
path.resolve(__dirname, "models/exampleBooking.pass/icon.png"), return Math.floor(Math.random() * 255);
); }
app.all(async function manageRequest(request, response) { app.all(async function manageRequest(request, response) {
const passName = const passName =
@@ -18,22 +18,33 @@ app.all(async function manageRequest(request, response) {
"_" + "_" +
new Date().toISOString().split("T")[0].replace(/-/gi, ""); 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 { try {
const pass = new PKPass( const pass = new PKPass(
{}, {},
{ {
wwdr: path.resolve(__dirname, "../../certificates/WWDR.pem"), wwdr: certificates.wwdr,
signerCert: path.resolve( signerCert: certificates.signerCert,
__dirname, signerKey: certificates.signerKey,
"../../certificates/signerCert.pem", signerKeyPassphrase: certificates.signerKeyPassphrase,
), },
signerKey: path.resolve( {
__dirname, ...(request.body || request.params || request.query),
"../../certificates/signerKey.pem", description: "Example Apple Wallet Pass",
), passTypeIdentifier: "pass.com.passkitgenerator",
signerKeyPassphrase: "123456", 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"; pass.type = "boardingPass";

View File

@@ -8,7 +8,7 @@
* by a string * by a string
*/ */
import app from "./webserver"; import app, { getCertificates } from "./webserver";
import { PKPass } from "passkit-generator"; import { PKPass } from "passkit-generator";
import path from "path"; import path from "path";
@@ -18,6 +18,8 @@ app.all(async function manageRequest(request, response) {
"_" + "_" +
new Date().toISOString().split("T")[0].replace(/-/gi, ""); new Date().toISOString().split("T")[0].replace(/-/gi, "");
const certificates = await getCertificates();
try { try {
const pass = await PKPass.from( const pass = await PKPass.from(
{ {
@@ -26,19 +28,10 @@ app.all(async function manageRequest(request, response) {
`../models/${request.params.modelName}`, `../models/${request.params.modelName}`,
), ),
certificates: { certificates: {
wwdr: path.resolve( wwdr: certificates.wwdr,
__dirname, signerCert: certificates.signerCert,
"../../certificates/WWDR.pem", signerKey: certificates.signerKey,
), signerKeyPassphrase: certificates.signerKeyPassphrase,
signerCert: path.resolve(
__dirname,
"../../certificates/signerCert.pem",
),
signerKey: path.resolve(
__dirname,
"../../certificates/signerKey.pem",
),
signerKeyPassphrase: "123456",
}, },
}, },
request.body || request.params || request.query || {}, 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", message: "Thank you for using this package <3",
format: "PKBarcodeFormatPDF417", format: "PKBarcodeFormatPDF417",
}, },
{
message: "Thank you for using this package <3",
// @ts-expect-error
format: "PKBarcodeFormatMock44617",
},
); );
} }

View File

@@ -7,7 +7,7 @@
* have to wait two minutes. * have to wait two minutes.
*/ */
import app from "./webserver"; import app, { getCertificates } from "./webserver";
import path from "path"; import path from "path";
import { PKPass } from "passkit-generator"; import { PKPass } from "passkit-generator";
@@ -19,6 +19,8 @@ app.all(async function manageRequest(request, response) {
return; return;
} }
const certificates = await getCertificates();
const passName = const passName =
request.params.modelName + request.params.modelName +
"_" + "_" +
@@ -32,19 +34,10 @@ app.all(async function manageRequest(request, response) {
`../models/${request.params.modelName}`, `../models/${request.params.modelName}`,
), ),
certificates: { certificates: {
wwdr: path.resolve( wwdr: certificates.wwdr,
__dirname, signerCert: certificates.signerCert,
"../../certificates/WWDR.pem", signerKey: certificates.signerKey,
), signerKeyPassphrase: certificates.signerKeyPassphrase,
signerCert: path.resolve(
__dirname,
"../../certificates/signerCert.pem",
),
signerKey: path.resolve(
__dirname,
"../../certificates/signerKey.pem",
),
signerKeyPassphrase: "123456",
}, },
}, },
Object.assign( Object.assign(
@@ -62,6 +55,10 @@ app.all(async function manageRequest(request, response) {
// setting the expiration // setting the expiration
pass.setExpirationDate(d); pass.setExpirationDate(d);
console.log(
"EXPIRATION DATE EXPECTED:",
pass.props["expirationDate"],
);
} }
const stream = pass.getAsStream(); const stream = pass.getAsStream();

View File

@@ -5,6 +5,8 @@
*/ */
import express from "express"; import express from "express";
import { promises as fs } from "fs";
import path from "path";
export const app = express(); export const app = express();
app.use(express.json()); app.use(express.json());
@@ -25,3 +27,41 @@ app.route("/gen").all((req, res) => {
}); });
export default app.route("/gen/:modelName"); export default app.route("/gen/:modelName");
const certificatesCache: Partial<{
signerCert: Buffer;
signerKey: Buffer;
wwdr: Buffer;
signerKeyPassphrase: string;
}> = {};
export async function getCertificates(): Promise<typeof certificatesCache> {
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;
}