diff --git a/src/fieldsArray.ts b/src/fieldsArray.ts index 5cbda83..2258701 100644 --- a/src/fieldsArray.ts +++ b/src/fieldsArray.ts @@ -11,6 +11,8 @@ const fieldsDebug = debug("passkit:fields"); const poolSymbol = Symbol("pool"); export default class FieldsArray extends Array { + private [poolSymbol]: Set; + constructor(pool: Set, ...args: any[]) { super(...args); this[poolSymbol] = pool; diff --git a/src/parser.ts b/src/parser.ts index 1a1748e..cc9821a 100644 --- a/src/parser.ts +++ b/src/parser.ts @@ -107,7 +107,7 @@ export async function getModelFolderContents(model: string): Promise & { signerKey: string; [key: string]: string }; + export async function readCertificatesFromOptions(options: Certificates): Promise { if (!(options && Object.keys(options).length && isValid(options, "certificatesSchema"))) { throw new Error(formatMessage("CP_NO_CERTS")); @@ -240,11 +242,13 @@ export async function readCertificatesFromOptions(options: Certificates): Promis // all the real contents and don't care of passphrase const flattenedDocs = Object.assign({}, options, { signerKey: ( - typeof options.signerKey === "string" - ? options.signerKey - : options.signerKey.keyFile + options.signerKey && typeof options.signerKey === "string" && + options.signerKey || ( + options.signerKey && + options.signerKey.keyFile + ) ) - }); + }) as flatCertificates; // We read the contents const rawContentsPromises = Object.keys(flattenedDocs) diff --git a/src/pass.ts b/src/pass.ts index f9a5e36..d874d42 100644 --- a/src/pass.ts +++ b/src/pass.ts @@ -30,13 +30,15 @@ export class Pass { private [passProps]: schema.ValidPass = {}; private type: keyof schema.ValidPassType; private fieldsKeys: Set = new Set(); - private passCore: schema.ValidPass = {}; + private passCore: schema.ValidPass; - public headerFields: FieldsArray; - public primaryFields: FieldsArray; - public secondaryFields: FieldsArray; - public auxiliaryFields: FieldsArray; - public backFields: FieldsArray; + // Setting these as possibly undefined because we set + // them all in an loop later + public headerFields: FieldsArray | undefined; + public primaryFields: FieldsArray | undefined; + public secondaryFields: FieldsArray | undefined; + public auxiliaryFields: FieldsArray | undefined; + public backFields: FieldsArray | undefined; private Certificates: schema.FinalCertificates; private [transitType]: string = ""; @@ -72,7 +74,8 @@ export class Pass { } // Parsing and validating pass.json keys - const validatedPassKeys = Object.keys(this.passCore).reduce((acc, current) => { + const passCoreKeys = Object.keys(this.passCore) as (keyof schema.ValidPass)[]; + const validatedPassKeys = passCoreKeys.reduce((acc, current) => { if (this.type === current) { // We want to exclude type keys (eventTicket, // boardingPass, ecc.) and their content @@ -86,10 +89,13 @@ export class Pass { return { ...acc, [current]: this.passCore[current] }; } - const currentSchema = propsSchemaMap.get(current); + const currentSchema = propsSchemaMap.get(current)!; if (Array.isArray(this.passCore[current])) { - const valid = getValidInArray(currentSchema, this.passCore[current]); + const valid = getValidInArray( + currentSchema, + this.passCore[current] as schema.ArrayPassSchema[] + ); return { ...acc, [current]: valid }; } else { return { @@ -201,7 +207,7 @@ export class Pass { * and returning the compiled manifest */ const archive = new ZipFile(); - const manifest = Object.keys(finalBundle).reduce((acc, current) => { + const manifest = Object.keys(finalBundle).reduce((acc, current) => { let hashFlow = forge.md.sha1.create(); hashFlow.update(finalBundle[current].toString("binary")); @@ -508,7 +514,7 @@ export class Pass { * @returns {Buffer} */ - private _sign(manifest: { [key: string]: string }): Buffer { + private _sign(manifest: schema.Manifest): Buffer { const signature = forge.pkcs7.createSignedData(); signature.content = forge.util.createBuffer(JSON.stringify(manifest), "utf8"); @@ -581,8 +587,8 @@ export class Pass { * and then delete it from the passFile. */ - ["backgroundColor", "foregroundColor", "labelColor"] - .filter(v => this[passProps][v] && !isValidRGB(this[passProps][v])) + const passColors = ["backgroundColor", "foregroundColor", "labelColor"] as Array; + passColors.filter(v => this[passProps][v] && !isValidRGB(this[passProps][v])) .forEach(v => delete this[passProps][v]); Object.assign(passFile, this[passProps]); @@ -634,7 +640,7 @@ function barcodesFromUncompleteData(message: string): schema.Barcode[] { "PKBarcodeFormatPDF417", "PKBarcodeFormatAztec", "PKBarcodeFormatCode128" - ].map(format => schema.getValidated({ format, message }, "barcode")); + ].map(format => schema.getValidated({ format, message }, "barcode") as schema.Barcode); } function processRelevancySet(key: string, data: T[]): T[] { diff --git a/src/schema.ts b/src/schema.ts index a4eec48..bbf57ac 100644 --- a/src/schema.ts +++ b/src/schema.ts @@ -3,6 +3,10 @@ import debug from "debug"; const schemaDebug = debug("Schema"); +export interface Manifest { + [key: string]: string; +} + export interface Certificates { wwdr?: string; signerCert?: string; @@ -71,7 +75,7 @@ export interface OverridesSupportedOptions { teamIdentifier?: string; appLaunchURL?: string; associatedStoreIdentifiers?: Array; - userInfo?: Object | Array; + userInfo?: { [key: string]: any }; webServiceURL?: string; authenticationToken?: string; sharingProhibited?: boolean; @@ -294,7 +298,7 @@ export interface ValidPassType { storeCard?: PassFields; } -export interface ValidPass extends OverridesSupportedOptions, ValidPassType { +interface PassInterfacesProps { barcode?: Barcode; barcodes?: Barcode[]; beacons?: Beacon[]; @@ -306,6 +310,12 @@ export interface ValidPass extends OverridesSupportedOptions, ValidPassType { voided?: boolean; } +type AllPassProps = PassInterfacesProps & ValidPassType & OverridesSupportedOptions; +export type ValidPass = { + [K in keyof AllPassProps]: AllPassProps[K]; +}; +export type PassColors = Pick; + export interface Barcode { altText?: string; messageEncoding?: string; @@ -464,6 +474,7 @@ const schemas = { }; export type Schema = keyof typeof schemas; +export type ArrayPassSchema = Beacon | Location | Barcode; function resolveSchemaName(name: Schema) { return schemas[name] || undefined; @@ -500,7 +511,7 @@ export function isValid(opts: any, schemaName: Schema): boolean { * @returns {object} the filtered value or empty object */ -export function getValidated(opts: any, schemaName: Schema): T { +export function getValidated(opts: any, schemaName: Schema): T | null { const resolvedSchema = resolveSchemaName(schemaName); if (!resolvedSchema) { diff --git a/src/utils.ts b/src/utils.ts index 610d3e2..539f471 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -11,7 +11,7 @@ import { sep } from "path"; * @returns {Boolean} True if valid rgb, false otherwise */ -export function isValidRGB(value: string): boolean { +export function isValidRGB(value?: string): boolean { if (!value || typeof value !== "string") { return false; } @@ -89,20 +89,21 @@ export function generateStringFile(lang: { [index: string]: string }): Buffer { * @param origin */ -export function splitBufferBundle(origin: Object): [PartitionedBundle["l10nBundle"], PartitionedBundle["bundle"]] { - const keys = Object.keys(origin); - return keys.reduce(([ l10n, bundle ], current) => { - if (current.includes(".lproj")) { - const pathComponents = current.split(sep); - const lang = pathComponents[0]; - const file = pathComponents.slice(1).join("/"); +type PartitionedBundleElements = [PartitionedBundle["l10nBundle"], PartitionedBundle["bundle"]]; - (l10n[lang] || (l10n[lang] = {}))[file] = origin[current]; - - return [ l10n, bundle ]; - } else { +export function splitBufferBundle(origin: any): PartitionedBundleElements { + return Object.keys(origin).reduce(([ l10n, bundle ], current) => { + if (!current.includes(".lproj")) { return [ l10n, { ...bundle, [current]: origin[current] }]; } + + const pathComponents = current.split(sep); + const lang = pathComponents[0]; + const file = pathComponents.slice(1).join("/"); + + (l10n[lang] || (l10n[lang] = {}))[file] = origin[current]; + + return [ l10n, bundle ]; }, [{},{}]); }