mirror of
https://github.com/marcogll/passkit-generator.git
synced 2026-03-15 22:25:24 +00:00
Added support for personalization / Rewards Enrollment passes
This commit is contained in:
@@ -2,10 +2,12 @@ import * as path from "path";
|
|||||||
import forge from "node-forge";
|
import forge from "node-forge";
|
||||||
import formatMessage from "./messages";
|
import formatMessage from "./messages";
|
||||||
import { FactoryOptions, PartitionedBundle, BundleUnit, Certificates, FinalCertificates, isValid } from "./schema";
|
import { FactoryOptions, PartitionedBundle, BundleUnit, Certificates, FinalCertificates, isValid } from "./schema";
|
||||||
import { removeHidden, splitBufferBundle } from "./utils";
|
import { removeHidden, splitBufferBundle, getAllFilesWithName, hasFilesWithName, deletePersonalization } from "./utils";
|
||||||
import { promisify } from "util";
|
import { promisify } from "util";
|
||||||
import { readFile as _readFile, readdir as _readdir } from "fs";
|
import { readFile as _readFile, readdir as _readdir } from "fs";
|
||||||
|
import debug from "debug";
|
||||||
|
|
||||||
|
const prsDebug = debug("Personalization");
|
||||||
const readDir = promisify(_readdir);
|
const readDir = promisify(_readdir);
|
||||||
const readFile = promisify(_readFile);
|
const readFile = promisify(_readFile);
|
||||||
|
|
||||||
@@ -38,9 +40,45 @@ export async function getModelContents(model: FactoryOptions["model"]) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const modelFiles = Object.keys(modelContents.bundle);
|
const modelFiles = Object.keys(modelContents.bundle);
|
||||||
|
const isModelInitialized = (
|
||||||
|
modelFiles.includes("pass.json") &&
|
||||||
|
hasFilesWithName("icon", modelFiles, "startsWith")
|
||||||
|
);
|
||||||
|
|
||||||
if (!(modelFiles.includes("pass.json") && modelContents.bundle["pass.json"].length && modelFiles.some(file => Boolean(file.includes("icon") && modelContents.bundle[file].length)))) {
|
if (!isModelInitialized) {
|
||||||
throw new Error("missing icon or pass.json");
|
// @TODO: set a good error message
|
||||||
|
throw new Error(formatMessage("MODEL_UNINITIALIZED", "parse result"));
|
||||||
|
}
|
||||||
|
|
||||||
|
// ======================= //
|
||||||
|
// *** Personalization *** //
|
||||||
|
// ======================= //
|
||||||
|
|
||||||
|
const personalizationJsonFile = "personalization.json";
|
||||||
|
|
||||||
|
if (!modelFiles.includes(personalizationJsonFile)) {
|
||||||
|
return modelContents;
|
||||||
|
}
|
||||||
|
|
||||||
|
const logoFullNames = getAllFilesWithName("personalizationLogo@", modelFiles, "startsWith");
|
||||||
|
if (!(logoFullNames.length && modelContents.bundle[personalizationJsonFile].length)) {
|
||||||
|
deletePersonalization(modelContents.bundle, logoFullNames);
|
||||||
|
return modelContents;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
const parsedPersonalization = JSON.parse(modelContents.bundle[personalizationJsonFile].toString("utf8"));
|
||||||
|
const isPersonalizationValid = isValid(parsedPersonalization, "personalizationDict");
|
||||||
|
|
||||||
|
if (!isPersonalizationValid) {
|
||||||
|
[...logoFullNames, personalizationJsonFile]
|
||||||
|
.forEach(file => delete modelContents.bundle[file]);
|
||||||
|
|
||||||
|
return modelContents;
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
prsDebug(formatMessage("PRS_INVALID", err));
|
||||||
|
deletePersonalization(modelContents.bundle, logoFullNames);
|
||||||
}
|
}
|
||||||
|
|
||||||
return modelContents;
|
return modelContents;
|
||||||
@@ -63,7 +101,7 @@ export async function getModelFolderContents(model: string): Promise<Partitioned
|
|||||||
|
|
||||||
const isModelInitialized = (
|
const isModelInitialized = (
|
||||||
filteredFiles.length &&
|
filteredFiles.length &&
|
||||||
filteredFiles.some(file => file.toLowerCase().includes("icon"))
|
hasFilesWithName("icon", filteredFiles, "startsWith")
|
||||||
);
|
);
|
||||||
|
|
||||||
// Icon is required to proceed
|
// Icon is required to proceed
|
||||||
@@ -171,7 +209,7 @@ export function getModelBufferContents(model: BundleUnit): PartitionedBundle {
|
|||||||
|
|
||||||
const isModelInitialized = (
|
const isModelInitialized = (
|
||||||
bundleKeys.length &&
|
bundleKeys.length &&
|
||||||
bundleKeys.some(file => file.toLowerCase().includes("icon"))
|
hasFilesWithName("icon", bundleKeys, "startsWith")
|
||||||
);
|
);
|
||||||
|
|
||||||
// Icon is required to proceed
|
// Icon is required to proceed
|
||||||
|
|||||||
17
src/pass.ts
17
src/pass.ts
@@ -7,7 +7,7 @@ import { ZipFile } from "yazl";
|
|||||||
import * as schema from "./schema";
|
import * as schema from "./schema";
|
||||||
import formatMessage from "./messages";
|
import formatMessage from "./messages";
|
||||||
import FieldsArray from "./fieldsArray";
|
import FieldsArray from "./fieldsArray";
|
||||||
import { generateStringFile, dateToW3CString, isValidRGB } from "./utils";
|
import { generateStringFile, dateToW3CString, isValidRGB, deletePersonalization, getAllFilesWithName } from "./utils";
|
||||||
|
|
||||||
const barcodeDebug = debug("passkit:barcode");
|
const barcodeDebug = debug("passkit:barcode");
|
||||||
const genericDebug = debug("passkit:generic");
|
const genericDebug = debug("passkit:generic");
|
||||||
@@ -134,6 +134,21 @@ export class Pass {
|
|||||||
// Editing Pass.json
|
// Editing Pass.json
|
||||||
this.bundle["pass.json"] = this._patch(this.bundle["pass.json"]);
|
this.bundle["pass.json"] = this._patch(this.bundle["pass.json"]);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checking Personalization, as this is available only with NFC
|
||||||
|
* @see https://apple.co/2SHfb22
|
||||||
|
*/
|
||||||
|
const currentBundleFiles = Object.keys(this.bundle);
|
||||||
|
|
||||||
|
if (!this[passProps].nfc && currentBundleFiles.includes("personalization.json")) {
|
||||||
|
genericDebug(formatMessage("PRS_REMOVED"));
|
||||||
|
deletePersonalization(this.bundle, getAllFilesWithName(
|
||||||
|
"personalizationLogo@",
|
||||||
|
currentBundleFiles,
|
||||||
|
"startsWith"
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
const finalBundle = { ...this.bundle } as schema.BundleUnit;
|
const finalBundle = { ...this.bundle } as schema.BundleUnit;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
Reference in New Issue
Block a user