Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

passkit-generator

Package Overview
Dependencies
Maintainers
1
Versions
53
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

passkit-generator - npm Package Compare versions

Comparing version 2.0.6 to 2.0.7

lib/schemas/barcode.d.ts

18

lib/abstract.d.ts

@@ -1,12 +0,12 @@

import { Certificates, FinalCertificates, PartitionedBundle, OverridesSupportedOptions, FactoryOptions } from "./schema";
import * as Schemas from "./schemas";
declare const abmCertificates: unique symbol;
declare const abmModel: unique symbol;
declare const abmOverrides: unique symbol;
export interface AbstractFactoryOptions extends Omit<FactoryOptions, "certificates"> {
certificates?: Certificates;
export interface AbstractFactoryOptions extends Omit<Schemas.FactoryOptions, "certificates"> {
certificates?: Schemas.Certificates;
}
interface AbstractModelOptions {
bundle: PartitionedBundle;
certificates: FinalCertificates;
overrides?: OverridesSupportedOptions;
bundle: Schemas.PartitionedBundle;
certificates: Schemas.CertificatesSchema;
overrides?: Schemas.OverridesSupportedOptions;
}

@@ -24,6 +24,6 @@ /**

constructor(options: AbstractModelOptions);
get certificates(): FinalCertificates;
get bundle(): PartitionedBundle;
get overrides(): OverridesSupportedOptions;
get certificates(): Schemas.CertificatesSchema;
get bundle(): Schemas.PartitionedBundle;
get overrides(): Schemas.OverridesSupportedOptions;
}
export {};

@@ -6,3 +6,3 @@ "use strict";

const parser_1 = require("./parser");
const messages_1 = tslib_1.__importDefault(require("./messages"));
const messages_1 = tslib_1.__importStar(require("./messages"));
const abmCertificates = Symbol("certificates");

@@ -18,3 +18,3 @@ const abmModel = Symbol("model");

if (!(options && Object.keys(options).length)) {
throw new Error(messages_1.default("CP_NO_OPTS"));
throw new Error(messages_1.default(messages_1.ERROR.CP_NO_OPTS));
}

@@ -33,3 +33,3 @@ try {

catch (err) {
throw new Error(messages_1.default("CP_INIT_ERROR", "abstract model", err));
throw new Error(messages_1.default(messages_1.ERROR.CP_INIT, "abstract model", err));
}

@@ -36,0 +36,0 @@ }

import { Pass } from "./pass";
import { FactoryOptions, BundleUnit } from "./schema";
import * as Schemas from "./schemas";
import { AbstractModel, AbstractFactoryOptions } from "./abstract";

@@ -11,2 +11,2 @@ /**

*/
export declare function createPass(options: FactoryOptions | InstanceType<typeof AbstractModel>, additionalBuffers?: BundleUnit, abstractMissingData?: Omit<AbstractFactoryOptions, "model">): Promise<Pass>;
export declare function createPass(options: Schemas.FactoryOptions | InstanceType<typeof AbstractModel>, additionalBuffers?: Schemas.BundleUnit, abstractMissingData?: Omit<AbstractFactoryOptions, "model">): Promise<Pass>;

@@ -6,3 +6,3 @@ "use strict";

const pass_1 = require("./pass");
const messages_1 = tslib_1.__importDefault(require("./messages"));
const messages_1 = tslib_1.__importStar(require("./messages"));
const parser_1 = require("./parser");

@@ -21,3 +21,3 @@ const utils_1 = require("./utils");

(options instanceof abstract_1.AbstractModel || Object.keys(options).length))) {
throw new Error(messages_1.default("CP_NO_OPTS"));
throw new Error(messages_1.default(messages_1.ERROR.CP_NO_OPTS));
}

@@ -52,3 +52,3 @@ try {

catch (err) {
throw new Error(messages_1.default("CP_INIT_ERROR", "pass", err));
throw new Error(messages_1.default(messages_1.ERROR.CP_INIT, "pass", err));
}

@@ -55,0 +55,0 @@ }

@@ -1,2 +0,2 @@

import * as schema from "./schema";
import * as Schemas from "./schemas";
/**

@@ -14,3 +14,3 @@ * Class to represent lower-level keys pass fields

*/
push(...fieldsData: schema.Field[]): number;
push(...fieldsData: Schemas.Field[]): number;
/**

@@ -20,3 +20,3 @@ * Like `Array.prototype.pop`, but will alter

*/
pop(): schema.Field;
pop(): Schemas.Field;
/**

@@ -26,5 +26,5 @@ * Like `Array.prototype.splice` but will alter

*/
splice(start: number, deleteCount: number, ...items: schema.Field[]): schema.Field[];
splice(start: number, deleteCount: number, ...items: Schemas.Field[]): Schemas.Field[];
get length(): number;
}
export {};
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const tslib_1 = require("tslib");
const schema = tslib_1.__importStar(require("./schema"));
const Schemas = tslib_1.__importStar(require("./schemas"));
const debug_1 = tslib_1.__importDefault(require("debug"));

@@ -24,3 +24,3 @@ const fieldsDebug = debug_1.default("passkit:fields");

if (!(typeof current === "object") ||
!schema.isValid(current, "field")) {
!Schemas.isValid(current, Schemas.Field)) {
return acc;

@@ -27,0 +27,0 @@ }

@@ -1,30 +0,30 @@

declare const errors: {
CP_INIT_ERROR: string;
CP_NO_OPTS: string;
CP_NO_CERTS: string;
PASSFILE_VALIDATION_FAILED: string;
REQUIR_VALID_FAILED: string;
MODEL_UNINITIALIZED: string;
MODEL_NOT_VALID: string;
MODELF_NOT_FOUND: string;
MODELF_FILE_NOT_FOUND: string;
INVALID_CERTS: string;
INVALID_CERT_PATH: string;
TRSTYPE_REQUIRED: string;
OVV_KEYS_BADFORMAT: string;
NO_PASS_TYPE: string;
export declare const ERROR: {
readonly CP_INIT: "Something went really bad in the %s initialization! Look at the log below this message. It should contain all the infos about the problem: \n%s";
readonly CP_NO_OPTS: "Cannot initialize the pass or abstract model creation: no options were passed.";
readonly CP_NO_CERTS: "Cannot initialize the pass creation: no valid certificates were passed.";
readonly PASSFILE_VALIDATION_FAILED: "Validation of pass type failed. Pass file is not a valid buffer or (more probably) does not respect the schema.\nRefer to https://apple.co/2Nvshvn to build a correct pass.";
readonly REQUIR_VALID_FAILED: "The options passed to Pass constructor does not meet the requirements.\nRefer to the documentation to compile them correctly.";
readonly MODEL_UNINITIALIZED: "Provided model ( %s ) matched but unitialized or may not contain icon or a valid pass.json.\nRefer to https://apple.co/2IhJr0Q, https://apple.co/2Nvshvn and documentation to fill the model correctly.";
readonly MODEL_NOT_VALID: "A model must be provided in form of path (string) or object { 'fileName': Buffer } in order to continue.";
readonly MODELF_NOT_FOUND: "Model %s not found. Provide a valid one to continue.";
readonly MODELF_FILE_NOT_FOUND: "File %s not found.";
readonly INVALID_CERTS: "Invalid certificate(s) loaded: %s. Please provide valid WWDR certificates and developer signer certificate and key (with passphrase).\nRefer to docs to obtain them.";
readonly INVALID_CERT_PATH: "Invalid certificate loaded. %s does not exist.";
readonly TRSTYPE_REQUIRED: "Cannot proceed with pass creation. transitType field is required for boardingPasses.";
readonly OVV_KEYS_BADFORMAT: "Cannot proceed with pass creation due to bad keys format in overrides.";
readonly NO_PASS_TYPE: "Cannot proceed with pass creation. Model definition (pass.json) has no valid type in it.\nRefer to https://apple.co/2wzyL5J to choose a valid pass type.";
};
declare const debugMessages: {
TRSTYPE_NOT_VALID: string;
BRC_NOT_SUPPORTED: string;
BRC_FORMATTYPE_UNMATCH: string;
BRC_AUTC_MISSING_DATA: string;
BRC_BW_FORMAT_UNSUPPORTED: string;
BRC_NO_POOL: string;
DATE_FORMAT_UNMATCH: string;
NFC_INVALID: string;
PRS_INVALID: string;
PRS_REMOVED: string;
export declare const DEBUG: {
readonly TRSTYPE_NOT_VALID: "Transit type changing rejected as not compliant with Apple Specifications. Transit type would become \"%s\" but should be in [PKTransitTypeAir, PKTransitTypeBoat, PKTransitTypeBus, PKTransitTypeGeneric, PKTransitTypeTrain]";
readonly BRC_NOT_SUPPORTED: "Format not found among barcodes. Cannot set backward compatibility.";
readonly BRC_FORMATTYPE_UNMATCH: "Format must be a string or null. Cannot set backward compatibility.";
readonly BRC_AUTC_MISSING_DATA: "Unable to autogenerate barcodes. Data is not a string.";
readonly BRC_BW_FORMAT_UNSUPPORTED: "This format is not supported (by Apple) for backward support. Please choose another one.";
readonly BRC_NO_POOL: "Cannot set barcode: no barcodes found. Please set barcodes first. Barcode is for retrocompatibility only.";
readonly DATE_FORMAT_UNMATCH: "%s was not set due to incorrect date format.";
readonly NFC_INVALID: "Unable to set NFC properties: data not compliant with schema.";
readonly PRS_INVALID: "Unable to parse Personalization.json. File is not a valid JSON. Error: %s";
readonly PRS_REMOVED: "Personalization has been removed as it requires an NFC-enabled pass to work.";
};
declare type AllMessages = keyof (typeof debugMessages & typeof errors);
declare type ERROR_OR_DEBUG_MESSAGE = typeof ERROR[keyof typeof ERROR] | typeof DEBUG[keyof typeof DEBUG];
/**

@@ -35,3 +35,3 @@ * Creates a message with replaced values

*/
export default function format(messageName: AllMessages, ...values: any[]): string;
export default function format(messageName: ERROR_OR_DEBUG_MESSAGE, ...values: any[]): string;
export {};
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const errors = {
CP_INIT_ERROR: "Something went really bad in the %s initialization! Look at the log below this message. It should contain all the infos about the problem: \n%s",
exports.DEBUG = exports.ERROR = void 0;
exports.ERROR = {
CP_INIT: "Something went really bad in the %s initialization! Look at the log below this message. It should contain all the infos about the problem: \n%s",
CP_NO_OPTS: "Cannot initialize the pass or abstract model creation: no options were passed.",

@@ -19,3 +20,3 @@ CP_NO_CERTS: "Cannot initialize the pass creation: no valid certificates were passed.",

};
const debugMessages = {
exports.DEBUG = {
TRSTYPE_NOT_VALID: 'Transit type changing rejected as not compliant with Apple Specifications. Transit type would become "%s" but should be in [PKTransitTypeAir, PKTransitTypeBoat, PKTransitTypeBus, PKTransitTypeGeneric, PKTransitTypeTrain]',

@@ -40,3 +41,3 @@ BRC_NOT_SUPPORTED: "Format not found among barcodes. Cannot set backward compatibility.",

let replaceValues = values.reverse();
return resolveMessageName(messageName).replace(/%s/g, () => {
return messageName.replace(/%s/g, () => {
let next = replaceValues.pop();

@@ -47,12 +48,2 @@ return next !== undefined ? next : "<passedValueIsUndefined>";

exports.default = format;
/**
* Looks among errors and debugMessages for the specified message name
* @param {string} name
*/
function resolveMessageName(name) {
if (!errors[name] && !debugMessages[name]) {
return `<ErrorName "${name}" is not linked to any error messages>`;
}
return errors[name] || debugMessages[name];
}
//# sourceMappingURL=messages.js.map

@@ -1,2 +0,2 @@

import { FactoryOptions, PartitionedBundle, BundleUnit, Certificates, FinalCertificates } from "./schema";
import * as Schemas from "./schemas";
/**

@@ -7,3 +7,3 @@ * Performs checks on the passed model to

*/
export declare function getModelContents(model: FactoryOptions["model"]): Promise<PartitionedBundle>;
export declare function getModelContents(model: Schemas.FactoryOptions["model"]): Promise<Schemas.PartitionedBundle>;
/**

@@ -14,3 +14,3 @@ * Reads and model contents and creates a splitted

*/
export declare function getModelFolderContents(model: string): Promise<PartitionedBundle>;
export declare function getModelFolderContents(model: string): Promise<Schemas.PartitionedBundle>;
/**

@@ -21,3 +21,3 @@ * Analyzes the passed buffer model and splits it to

*/
export declare function getModelBufferContents(model: BundleUnit): PartitionedBundle;
export declare function readCertificatesFromOptions(options: Certificates): Promise<FinalCertificates>;
export declare function getModelBufferContents(model: Schemas.BundleUnit): Schemas.PartitionedBundle;
export declare function readCertificatesFromOptions(options: Schemas.Certificates): Promise<Schemas.CertificatesSchema>;

@@ -7,4 +7,4 @@ "use strict";

const node_forge_1 = tslib_1.__importDefault(require("node-forge"));
const messages_1 = tslib_1.__importDefault(require("./messages"));
const schema_1 = require("./schema");
const messages_1 = tslib_1.__importStar(require("./messages"));
const Schemas = tslib_1.__importStar(require("./schemas"));
const utils_1 = require("./utils");

@@ -29,3 +29,3 @@ const fs_1 = tslib_1.__importDefault(require("fs"));

else {
throw new Error(messages_1.default("MODEL_NOT_VALID"));
throw new Error(messages_1.default(messages_1.ERROR.MODEL_NOT_VALID));
}

@@ -36,3 +36,3 @@ const modelFiles = Object.keys(modelContents.bundle);

if (!isModelInitialized) {
throw new Error(messages_1.default("MODEL_UNINITIALIZED", "parse result"));
throw new Error(messages_1.default(messages_1.ERROR.MODEL_UNINITIALIZED, "parse result"));
}

@@ -54,3 +54,3 @@ // ======================= //

const parsedPersonalization = JSON.parse(modelContents.bundle[personalizationJsonFile].toString("utf8"));
const isPersonalizationValid = schema_1.isValid(parsedPersonalization, "personalizationDict");
const isPersonalizationValid = Schemas.isValid(parsedPersonalization, Schemas.Personalization);
if (!isPersonalizationValid) {

@@ -62,3 +62,3 @@ [...logoFullNames, personalizationJsonFile].forEach((file) => delete modelContents.bundle[file]);

catch (err) {
prsDebug(messages_1.default("PRS_INVALID", err));
prsDebug(messages_1.default(messages_1.DEBUG.PRS_INVALID, err));
utils_1.deletePersonalization(modelContents.bundle, logoFullNames);

@@ -85,3 +85,3 @@ }

if (!isModelInitialized) {
throw new Error(messages_1.default("MODEL_UNINITIALIZED", path.parse(model).name));
throw new Error(messages_1.default(messages_1.ERROR.MODEL_UNINITIALIZED, path.parse(model).name));
}

@@ -131,3 +131,3 @@ // Splitting files from localization folders

// file opening failed
throw new Error(messages_1.default("MODELF_NOT_FOUND", err.path));
throw new Error(messages_1.default(messages_1.ERROR.MODELF_NOT_FOUND, err.path));
}

@@ -137,3 +137,3 @@ else if (err.syscall === "scandir") {

const pathContents = err.path.split(/(\/|\\\?)/);
throw new Error(messages_1.default("MODELF_FILE_NOT_FOUND", pathContents[pathContents.length - 1]));
throw new Error(messages_1.default(messages_1.ERROR.MODELF_FILE_NOT_FOUND, pathContents[pathContents.length - 1]));
}

@@ -163,3 +163,3 @@ }

if (!isModelInitialized) {
throw new Error(messages_1.default("MODEL_UNINITIALIZED", "Buffers"));
throw new Error(messages_1.default(messages_1.ERROR.MODEL_UNINITIALIZED, "Buffers"));
}

@@ -178,4 +178,4 @@ // separing localization folders from bundle files

Object.keys(options).length &&
schema_1.isValid(options, "certificatesSchema"))) {
throw new Error(messages_1.default("CP_NO_CERTS"));
Schemas.isValid(options, Schemas.CertificatesSchema))) {
throw new Error(messages_1.default(messages_1.ERROR.CP_NO_CERTS));
}

@@ -211,7 +211,8 @@ let signerKey;

const certName = Object.keys(options)[index];
const passphrase = (typeof options.signerKey === "object" && ((_a = options.signerKey) === null || _a === void 0 ? void 0 : _a.passphrase)) ||
const passphrase = (typeof options.signerKey === "object" &&
((_a = options.signerKey) === null || _a === void 0 ? void 0 : _a.passphrase)) ||
undefined;
const pem = parsePEM(certName, file, passphrase);
if (!pem) {
throw new Error(messages_1.default("INVALID_CERTS", certName));
throw new Error(messages_1.default(messages_1.ERROR.INVALID_CERTS, certName));
}

@@ -226,3 +227,3 @@ return { [certName]: pem };

}
throw new Error(messages_1.default("INVALID_CERT_PATH", path.parse(err.path).base));
throw new Error(messages_1.default(messages_1.ERROR.INVALID_CERT_PATH, path.parse(err.path).base));
}

@@ -229,0 +230,0 @@ }

/// <reference types="node" />
import { Stream } from "stream";
import * as schema from "./schema";
import * as Schemas from "./schemas";
import FieldsArray from "./fieldsArray";

@@ -15,11 +15,11 @@ declare const transitType: unique symbol;

private passCore;
headerFields: FieldsArray | undefined;
primaryFields: FieldsArray | undefined;
secondaryFields: FieldsArray | undefined;
auxiliaryFields: FieldsArray | undefined;
backFields: FieldsArray | undefined;
headerFields: FieldsArray;
primaryFields: FieldsArray;
secondaryFields: FieldsArray;
auxiliaryFields: FieldsArray;
backFields: FieldsArray;
private Certificates;
private [transitType];
private l10nTranslations;
constructor(options: schema.PassInstance);
constructor(options: Schemas.PassInstance);
/**

@@ -68,3 +68,3 @@ * Generates the pass Stream

beacons(resetFlag: null): this;
beacons(...data: schema.Beacon[]): this;
beacons(...data: Schemas.Beacon[]): this;
/**

@@ -76,3 +76,3 @@ * Sets current pass' relevancy through locations

locations(resetFlag: null): this;
locations(...data: schema.Location[]): this;
locations(...data: Schemas.Location[]): this;
/**

@@ -96,3 +96,3 @@ * Sets current pass' relevancy through a date

barcodes(message: string): this;
barcodes(...data: schema.Barcode[]): this;
barcodes(...data: Schemas.Barcode[]): this;
/**

@@ -107,3 +107,3 @@ * Given an index <= the amount of already set "barcodes",

*/
barcode(chosenFormat: schema.BarcodeFormat | null): this;
barcode(chosenFormat: Schemas.BarcodeFormat | null): this;
/**

@@ -117,3 +117,3 @@ * Sets nfc fields in properties

*/
nfc(data: schema.NFC | null): this;
nfc(data: Schemas.NFC | null): this;
/**

@@ -126,12 +126,4 @@ * Allows to get the current inserted props;

*/
get props(): Readonly<schema.ValidPass>;
get props(): Readonly<Schemas.ValidPass>;
/**
* Generates the PKCS #7 cryptografic signature for the manifest file.
*
* @method _sign
* @params {Object} manifest - Manifest content.
* @returns {Buffer}
*/
private _sign;
/**
* Edits the buffer of pass.json based on the passed options.

@@ -138,0 +130,0 @@ *

@@ -11,6 +11,7 @@ "use strict";

const yazl_1 = require("yazl");
const schema = tslib_1.__importStar(require("./schema"));
const messages_1 = tslib_1.__importDefault(require("./messages"));
const Schemas = tslib_1.__importStar(require("./schemas"));
const messages_1 = tslib_1.__importStar(require("./messages"));
const fieldsArray_1 = tslib_1.__importDefault(require("./fieldsArray"));
const utils_1 = require("./utils");
const Signature = tslib_1.__importStar(require("./signature"));
const barcodeDebug = debug_1.default("passkit:barcode");

@@ -21,10 +22,17 @@ const genericDebug = debug_1.default("passkit:generic");

const propsSchemaMap = new Map([
["barcodes", "barcode"],
["barcode", "barcode"],
["beacons", "beaconsDict"],
["locations", "locationsDict"],
["nfc", "nfcDict"],
["barcodes", Schemas.Barcode],
["barcode", Schemas.Barcode],
["beacons", Schemas.Beacon],
["locations", Schemas.Location],
["nfc", Schemas.NFC],
]);
class Pass {
constructor(options) {
this._fields = [
"primaryFields",
"secondaryFields",
"auxiliaryFields",
"backFields",
"headerFields",
];
this[_a] = {};

@@ -34,4 +42,4 @@ this.fieldsKeys = new Set();

this.l10nTranslations = {};
if (!schema.isValid(options, "instance")) {
throw new Error(messages_1.default("REQUIR_VALID_FAILED"));
if (!Schemas.isValid(options, Schemas.PassInstance)) {
throw new Error(messages_1.default(messages_1.ERROR.REQUIR_VALID_FAILED));
}

@@ -45,12 +53,12 @@ this.Certificates = options.certificates;

catch (err) {
throw new Error(messages_1.default("PASSFILE_VALIDATION_FAILED"));
throw new Error(messages_1.default(messages_1.ERROR.PASSFILE_VALIDATION_FAILED));
}
// Parsing the options and extracting only the valid ones.
const validOverrides = schema.getValidated(options.overrides || {}, "supportedOptions");
const validOverrides = Schemas.getValidated(options.overrides || {}, Schemas.OverridesSupportedOptions);
if (validOverrides === null) {
throw new Error(messages_1.default("OVV_KEYS_BADFORMAT"));
throw new Error(messages_1.default(messages_1.ERROR.OVV_KEYS_BADFORMAT));
}
this.type = Object.keys(this.passCore).find((key) => /(boardingPass|eventTicket|coupon|generic|storeCard)/.test(key));
if (!this.type) {
throw new Error(messages_1.default("NO_PASS_TYPE"));
throw new Error(messages_1.default(messages_1.ERROR.NO_PASS_TYPE));
}

@@ -74,3 +82,6 @@ // Parsing and validating pass.json keys

const valid = getValidInArray(currentSchema, this.passCore[current]);
return { ...acc, [current]: valid };
return {
...acc,
[current]: valid,
};
}

@@ -80,3 +91,3 @@ else {

...acc,
[current]: (schema.isValid(this.passCore[current], currentSchema) &&
[current]: (Schemas.isValid(this.passCore[current], currentSchema) &&
this.passCore[current]) ||

@@ -97,11 +108,4 @@ undefined,

}
this._fields = [
"primaryFields",
"secondaryFields",
"auxiliaryFields",
"backFields",
"headerFields",
];
this._fields.forEach((fieldName) => {
this[fieldName] = new fieldsArray_1.default(this.fieldsKeys, ...(this.passCore[this.type][fieldName] || []).filter((field) => schema.isValid(field, "field")));
this[fieldName] = new fieldsArray_1.default(this.fieldsKeys, ...(this.passCore[this.type][fieldName] || []).filter((field) => Schemas.isValid(field, Schemas.Field)));
});

@@ -116,2 +120,4 @@ }

generate() {
var _c;
var _d;
// Editing Pass.json

@@ -126,3 +132,3 @@ this.bundle["pass.json"] = this._patch(this.bundle["pass.json"]);

currentBundleFiles.includes("personalization.json")) {
genericDebug(messages_1.default("PRS_REMOVED"));
genericDebug(messages_1.default(messages_1.DEBUG.PRS_REMOVED));
utils_1.deletePersonalization(this.bundle, utils_1.getAllFilesWithName("personalizationLogo", currentBundleFiles, "startsWith"));

@@ -134,5 +140,6 @@ }

*/
Object.keys(this.l10nTranslations).forEach((lang) => {
const translationsLanguageCodes = Object.keys(this.l10nTranslations);
for (let langs = translationsLanguageCodes.length, lang; (lang = translationsLanguageCodes[--langs]);) {
const strings = utils_1.generateStringFile(this.l10nTranslations[lang]);
const langInBundles = `${lang}.lproj`;
const languageBundleDirname = `${lang}.lproj`;
if (strings.length) {

@@ -144,14 +151,11 @@ /**

*/
if (!this.l10nBundles[langInBundles]) {
this.l10nBundles[langInBundles] = {};
}
this.l10nBundles[langInBundles]["pass.strings"] = Buffer.concat([
this.l10nBundles[langInBundles]["pass.strings"] ||
Buffer.alloc(0),
const languageBundleUnit = ((_c = (_d = this.l10nBundles)[languageBundleDirname]) !== null && _c !== void 0 ? _c : (_d[languageBundleDirname] = {}));
languageBundleUnit["pass.strings"] = Buffer.concat([
languageBundleUnit["pass.strings"] || Buffer.alloc(0),
strings,
]);
}
if (!(this.l10nBundles[langInBundles] &&
Object.keys(this.l10nBundles[langInBundles]).length)) {
return;
if (!this.l10nBundles[languageBundleDirname] ||
!Object.keys(this.l10nBundles[languageBundleDirname]).length) {
continue;
}

@@ -165,11 +169,13 @@ /**

*/
Object.assign(finalBundle, ...Object.keys(this.l10nBundles[langInBundles]).map((fileName) => {
const bundleRelativeL10NPaths = Object.entries(this.l10nBundles[languageBundleDirname]).reduce((acc, [fileName, fileContent]) => {
const fullPath = path_1.default
.join(langInBundles, fileName)
.join(languageBundleDirname, fileName)
.replace(/\\/, "/");
return {
[fullPath]: this.l10nBundles[langInBundles][fileName],
...acc,
[fullPath]: fileContent,
};
}));
});
}, {});
Object.assign(finalBundle, bundleRelativeL10NPaths);
}
/*

@@ -180,10 +186,12 @@ * Parsing the buffers, pushing them into the archive

const archive = new yazl_1.ZipFile();
const manifest = Object.keys(finalBundle).reduce((acc, current) => {
const manifest = Object.entries(finalBundle).reduce((acc, [fileName, buffer]) => {
let hashFlow = node_forge_1.default.md.sha1.create();
hashFlow.update(finalBundle[current].toString("binary"));
archive.addBuffer(finalBundle[current], current);
acc[current] = hashFlow.digest().toHex();
return acc;
hashFlow.update(buffer.toString("binary"));
archive.addBuffer(buffer, fileName);
return {
...acc,
[fileName]: hashFlow.digest().toHex(),
};
}, {});
const signatureBuffer = this._sign(manifest);
const signatureBuffer = Signature.create(manifest, this.Certificates);
archive.addBuffer(signatureBuffer, "signature");

@@ -249,3 +257,3 @@ archive.addBuffer(Buffer.from(JSON.stringify(manifest)), "manifest.json");

}
const valid = processRelevancySet("beacons", data);
const valid = getValidInArray(Schemas.Beacon, data);
if (valid.length) {

@@ -261,3 +269,3 @@ this[passProps]["beacons"] = valid;

}
const valid = processRelevancySet("locations", data);
const valid = getValidInArray(Schemas.Location, data);
if (valid.length) {

@@ -292,3 +300,3 @@ this[passProps]["locations"] = valid;

if (!autogen.length) {
barcodeDebug(messages_1.default("BRC_AUTC_MISSING_DATA"));
barcodeDebug(messages_1.default(messages_1.DEBUG.BRC_AUTC_MISSING_DATA));
return this;

@@ -309,3 +317,3 @@ }

}
const validated = schema.getValidated(current, "barcode");
const validated = Schemas.getValidated(current, Schemas.Barcode);
if (!(validated &&

@@ -340,11 +348,11 @@ validated instanceof Object &&

if (typeof chosenFormat !== "string") {
barcodeDebug(messages_1.default("BRC_FORMATTYPE_UNMATCH"));
barcodeDebug(messages_1.default(messages_1.DEBUG.BRC_FORMATTYPE_UNMATCH));
return this;
}
if (chosenFormat === "PKBarcodeFormatCode128") {
barcodeDebug(messages_1.default("BRC_BW_FORMAT_UNSUPPORTED"));
barcodeDebug(messages_1.default(messages_1.DEBUG.BRC_BW_FORMAT_UNSUPPORTED));
return this;
}
if (!(barcodes && barcodes.length)) {
barcodeDebug(messages_1.default("BRC_NO_POOL"));
barcodeDebug(messages_1.default(messages_1.DEBUG.BRC_NO_POOL));
return this;

@@ -355,3 +363,3 @@ }

if (index === -1) {
barcodeDebug(messages_1.default("BRC_NOT_SUPPORTED"));
barcodeDebug(messages_1.default(messages_1.DEBUG.BRC_NOT_SUPPORTED));
return this;

@@ -378,4 +386,4 @@ }

!Array.isArray(data) &&
schema.isValid(data, "nfcDict"))) {
genericDebug(messages_1.default("NFC_INVALID"));
Schemas.isValid(data, Schemas.NFC))) {
genericDebug(messages_1.default(messages_1.DEBUG.NFC_INVALID));
return this;

@@ -397,59 +405,2 @@ }

/**
* Generates the PKCS #7 cryptografic signature for the manifest file.
*
* @method _sign
* @params {Object} manifest - Manifest content.
* @returns {Buffer}
*/
_sign(manifest) {
const signature = node_forge_1.default.pkcs7.createSignedData();
signature.content = node_forge_1.default.util.createBuffer(JSON.stringify(manifest), "utf8");
signature.addCertificate(this.Certificates.wwdr);
signature.addCertificate(this.Certificates.signerCert);
/**
* authenticatedAttributes belong to PKCS#9 standard.
* It requires at least 2 values:
* • content-type (which is a PKCS#7 oid) and
* • message-digest oid.
*
* Wallet requires a signingTime.
*/
signature.addSigner({
key: this.Certificates.signerKey,
certificate: this.Certificates.signerCert,
digestAlgorithm: node_forge_1.default.pki.oids.sha1,
authenticatedAttributes: [
{
type: node_forge_1.default.pki.oids.contentType,
value: node_forge_1.default.pki.oids.data,
},
{
type: node_forge_1.default.pki.oids.messageDigest,
},
{
type: node_forge_1.default.pki.oids.signingTime,
},
],
});
/**
* We are creating a detached signature because we don't need the signed content.
* Detached signature is a property of PKCS#7 cryptography standard.
*/
signature.sign({ detached: true });
/**
* Signature here is an ASN.1 valid structure (DER-compliant).
* Generating a non-detached signature, would have pushed inside signature.contentInfo
* (which has type 16, or "SEQUENCE", and is an array) a Context-Specific element, with the
* signed content as value.
*
* In fact the previous approach was to generating a detached signature and the pull away the generated
* content.
*
* That's what happens when you copy a fu****g line without understanding what it does.
* Well, nevermind, it was funny to study BER, DER, CER, ASN.1 and PKCS#7. You can learn a lot
* of beautiful things. ¯\_(ツ)_/¯
*/
return Buffer.from(node_forge_1.default.asn1.toDer(signature.toAsn1()).getBytes(), "binary");
}
/**
* Edits the buffer of pass.json based on the passed options.

@@ -483,3 +434,3 @@ *

if (this.type === "boardingPass" && !this[transitType]) {
throw new Error(messages_1.default("TRSTYPE_REQUIRED"));
throw new Error(messages_1.default(messages_1.ERROR.TRSTYPE_REQUIRED));
}

@@ -490,4 +441,4 @@ passFile[this.type]["transitType"] = this[transitType];

set transitType(value) {
if (!schema.isValid(value, "transitType")) {
genericDebug(messages_1.default("TRSTYPE_NOT_VALID", value));
if (!Schemas.isValid(value, Schemas.TransitType)) {
genericDebug(messages_1.default(messages_1.DEBUG.TRSTYPE_NOT_VALID, value));
this[transitType] = this[transitType] || "";

@@ -520,9 +471,6 @@ return;

"PKBarcodeFormatCode128",
].map((format) => schema.getValidated({ format, message }, "barcode"));
].map((format) => Schemas.getValidated({ format, message }, Schemas.Barcode));
}
function processRelevancySet(key, data) {
return getValidInArray(`${key}Dict`, data);
}
function getValidInArray(schemaName, contents) {
return contents.filter((current) => Object.keys(current).length && schema.isValid(current, schemaName));
return contents.filter((current) => Object.keys(current).length && Schemas.isValid(current, schemaName));
}

@@ -535,3 +483,3 @@ function processDate(key, date) {

if (!dateParse) {
genericDebug(messages_1.default("DATE_FORMAT_UNMATCH", key));
genericDebug(messages_1.default(messages_1.DEBUG.DATE_FORMAT_UNMATCH, key));
return null;

@@ -538,0 +486,0 @@ }

/// <reference types="node" />
import { PartitionedBundle, BundleUnit } from "./schema";
import type * as Schemas from "./schemas";
/**

@@ -45,10 +45,10 @@ * Checks if an rgb value is compliant with CSS-like syntax

declare type PartitionedBundleElements = [
PartitionedBundle["l10nBundle"],
PartitionedBundle["bundle"]
Schemas.PartitionedBundle["l10nBundle"],
Schemas.PartitionedBundle["bundle"]
];
export declare function splitBufferBundle(origin: BundleUnit): PartitionedBundleElements;
export declare function splitBufferBundle(origin: Schemas.BundleUnit): PartitionedBundleElements;
declare type StringSearchMode = "includes" | "startsWith" | "endsWith";
export declare function getAllFilesWithName(name: string, source: string[], mode?: StringSearchMode, forceLowerCase?: boolean): string[];
export declare function hasFilesWithName(name: string, source: string[], mode?: StringSearchMode, forceLowerCase?: boolean): boolean;
export declare function deletePersonalization(source: BundleUnit, logosNames?: string[]): void;
export declare function deletePersonalization(source: Schemas.BundleUnit, logosNames?: string[]): void;
export {};
{
"name": "passkit-generator",
"version": "2.0.6",
"version": "2.0.7",
"description": "The easiest way to generate custom Apple Wallet passes in Node.js",

@@ -29,5 +29,5 @@ "main": "lib/index.js",

"debug": "^4.3.1",
"joi": "^17.3.0",
"joi": "^17.4.0",
"node-forge": "^0.10.0",
"tslib": "^2.1.0",
"tslib": "^2.3.0",
"yazl": "^2.5.1"

@@ -40,10 +40,10 @@ },

"@types/debug": "^4.1.5",
"@types/jasmine": "^3.6.3",
"@types/node": "^14.14.25",
"@types/node-forge": "^0.9.7",
"@types/jasmine": "^3.7.7",
"@types/node": "^14.17.3",
"@types/node-forge": "^0.10.0",
"@types/yazl": "^2.4.2",
"jasmine": "^3.6.4",
"prettier": "^2.2.1",
"jasmine": "^3.7.0",
"prettier": "^2.3.1",
"rimraf": "^3.0.2",
"typescript": "^4.1.3"
"typescript": "^4.3.4"
},

@@ -50,0 +50,0 @@ "files": [

@@ -29,2 +29,3 @@ <div align="center">

### Install
```sh

@@ -34,3 +35,3 @@ $ npm install passkit-generator --save

___
---

@@ -41,3 +42,3 @@ ### API Documentation

___
---

@@ -48,3 +49,3 @@ ### Looking for the previous major version?

___
---

@@ -55,3 +56,3 @@ ### Coming from the previous major version?

___
---

@@ -71,3 +72,3 @@ ## Get Started

___
---

@@ -80,4 +81,9 @@ > Using the .pass extension is a best practice, showing that the directory is a pass package.

___
---
Model creation can be performed both manually or with the auxiliary of a web tool I developed, [Passkit Visual Designer](https://pkvd.app), which will let you design your model through a neat user interface.
It will output a .zip file that you can decompress and use it as both file model and buffer model.
Since `.pass` extension is required, **it will be up to you to unzip the generated model in a .pass folder**.
```bash

@@ -88,5 +94,5 @@ $ cd yourProjectDir;

Follow the [Apple Developer documentation](https://apple.co/2wuJLC1) (_Package Structure_) to build a correct pass model. The **icon is required** in order to make the pass work. *Manifest.json* and *signature* will be automatically ignored from the model and generated in runtime.
Follow the [Apple Developer documentation](https://apple.co/2wuJLC1) (_Package Structure_) to build a correct pass model. The **icon is required** in order to make the pass work. _Manifest.json_ and _signature_ will be automatically ignored from the model and generated in runtime.
You can also create `.lproj` folders (e.g. *en.lproj* or *it.lproj*) containing localized media. To include a folder or translate texts inside the pass, please refer to [Localizing Passes](./API.md#method_localize) in the API documentation.
You can also create `.lproj` folders (e.g. _en.lproj_ or _it.lproj_) containing localized media. To include a folder or translate texts inside the pass, please refer to [Localizing Passes](./API.md#method_localize) in the API documentation.

@@ -101,10 +107,11 @@ To include a file that belongs to an `.lproj` folder in buffers, you'll just have to name a key like `en.lproj/thumbnail.png`.

{
"formatVersion": 1,
"passTypeIdentifier": "pass.<bundle id>",
"teamIdentifier": "<here your team identifier>",
"organizationName": "<your organization name>",
"description": "A localizable description of your pass. To do so, put here a placeholder.",
"boardingPass": {}
"formatVersion": 1,
"passTypeIdentifier": "pass.<bundle id>",
"teamIdentifier": "<here your team identifier>",
"organizationName": "<your organization name>",
"description": "A localizable description of your pass. To do so, put here a placeholder.",
"boardingPass": {}
}
```
<a name="certificates"></a>

@@ -119,5 +126,5 @@

* Apple WWDR (_Worldwide Developer Relationship_) certificate
* Signer certificate
* Signer key
- Apple WWDR (_Worldwide Developer Relationship_) certificate
- Signer certificate
- Signer key

@@ -130,5 +137,5 @@ While WWDR can be obtained from [Apple PKI Portal](https://www.apple.com/certificateauthority/), to get the `signer key` and the `certificate`, you'll have to get first a `Certificate Signing Request` (`.certSigningRequest` file) and upload it to Apple Developers Portal, at [Pass Types Identifiers](https://developer.apple.com/account/ios/identifier/passTypeId) (open it, it's worth it 😜).

> **If you don't have access to macOS** (or you are a terminal enthusiast), **follow [these steps](./non-macOS-steps.md) instead.**
<hr>
1. Create a new pass type identifier and provide it with a Name and a reverse-domain bundle id (starting with "pass."). You will put this identifier as value for `passTypeIdentifier` in `pass.json` file.

@@ -142,16 +149,19 @@ 2. Confirm and register the new identifier.

```sh
# Creating and changing dir
# Creating and changing dir
$ mkdir "certs" && cd $_
# Extracting key and cert from pkcs12
# Extracting key and cert from pkcs12
$ openssl pkcs12 -in <cert-name>.p12 -clcerts -nokeys -out signerCert.pem -passin pass:<your-password>
$ openssl pkcs12 -in <cert-name>.p12 -nocerts -out signerKey.pem -passin pass:<your-password> -passout pass:<secret-passphrase>
```
7. Execute step 5 also for the WWDR certificate (`.cer`) you downloaded from Apple PKI portal (default name: *AppleWWDRCA.cer*) but instead exporting it as PKCS#12 (`.p12` - you'll also be unable to do that), export it as PEM (`.pem`) file.
___
7. Execute step 5 also for the WWDR certificate (`.cer`) you downloaded from Apple PKI portal (default name: _AppleWWDRCA.cer_) but instead exporting it as PKCS#12 (`.p12` - you'll also be unable to do that), export it as PEM (`.pem`) file.
---
<a name="usage_example"></a>
## Usage example
## Usage Examples
#### Folder Model
```typescript

@@ -186,3 +196,3 @@ /**

// Generate the stream, which gets returned through a Promise
// Generate the stream .pkpass file stream
const stream: Stream = examplePass.generate();

@@ -196,5 +206,51 @@

#### Buffer Model
```typescript
/**
* Use `const { createPass } = require("passkit-generator");`
* for usage in pure Node.js. Please note that `Pass` is only exported
* as Typescript type.
*/
import { createPass, Pass } from "passkit-generator";
try {
const examplePass = await createPass({
model: {
"thumbnail": Buffer.from([ ... ]),
"icon": Buffer.from([ ... ]),
"pass.json": Buffer.from([ ... ]),
"it.lproj/pass.strings": Buffer.from([ ... ])
},
certificates: {
wwdr: "./certs/wwdr.pem",
signerCert: "./certs/signercert.pem",
signerKey: {
keyFile: "./certs/signerkey.pem",
passphrase: "123456"
}
},
overrides: {
// keys to be added or overridden
serialNumber: "AAGH44625236dddaffbda"
}
});
// Adding some settings to be written inside pass.json
examplePass.localize("en", { ... });
examplePass.barcode("36478105430"); // Random value
// Generate the stream .pkpass file stream
const stream: Stream = examplePass.generate();
doSomethingWithTheStream(stream);
} catch (err) {
doSomethingWithTheError(err);
}
```
For more complex usage examples, please refer to [examples](https://github.com/alexandercerutti/passkit-generator/tree/master/examples) folder.
___
---

@@ -212,3 +268,3 @@ ## Other

___
---

@@ -215,0 +271,0 @@ ## Contributors

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc