Merge branch 'strict'

This commit is contained in:
Alexander Cerutti
2019-12-14 16:10:08 +01:00
5 changed files with 58 additions and 34 deletions

View File

@@ -11,6 +11,8 @@ const fieldsDebug = debug("passkit:fields");
const poolSymbol = Symbol("pool"); const poolSymbol = Symbol("pool");
export default class FieldsArray extends Array { export default class FieldsArray extends Array {
private [poolSymbol]: Set<string>;
constructor(pool: Set<string>, ...args: any[]) { constructor(pool: Set<string>, ...args: any[]) {
super(...args); super(...args);
this[poolSymbol] = pool; this[poolSymbol] = pool;

View File

@@ -107,7 +107,7 @@ export async function getModelFolderContents(model: string): Promise<Partitioned
if (!isModelInitialized) { if (!isModelInitialized) {
throw new Error(formatMessage( throw new Error(formatMessage(
"MODEL_UNINITIALIZED", "MODEL_UNINITIALIZED",
path.parse(this.model).name path.parse(model).name
)); ));
} }
@@ -231,6 +231,8 @@ export function getModelBufferContents(model: BundleUnit): PartitionedBundle {
* @param options * @param options
*/ */
type flatCertificates = Omit<Certificates, "signerKey"> & { signerKey: string; [key: string]: string };
export async function readCertificatesFromOptions(options: Certificates): Promise<FinalCertificates> { export async function readCertificatesFromOptions(options: Certificates): Promise<FinalCertificates> {
if (!(options && Object.keys(options).length && isValid(options, "certificatesSchema"))) { if (!(options && Object.keys(options).length && isValid(options, "certificatesSchema"))) {
throw new Error(formatMessage("CP_NO_CERTS")); 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 // all the real contents and don't care of passphrase
const flattenedDocs = Object.assign({}, options, { const flattenedDocs = Object.assign({}, options, {
signerKey: ( signerKey: (
typeof options.signerKey === "string" options.signerKey && typeof options.signerKey === "string" &&
? options.signerKey options.signerKey || (
: options.signerKey.keyFile options.signerKey &&
options.signerKey.keyFile
) )
}); )
}) as flatCertificates;
// We read the contents // We read the contents
const rawContentsPromises = Object.keys(flattenedDocs) const rawContentsPromises = Object.keys(flattenedDocs)

View File

@@ -30,13 +30,15 @@ export class Pass {
private [passProps]: schema.ValidPass = {}; private [passProps]: schema.ValidPass = {};
private type: keyof schema.ValidPassType; private type: keyof schema.ValidPassType;
private fieldsKeys: Set<string> = new Set<string>(); private fieldsKeys: Set<string> = new Set<string>();
private passCore: schema.ValidPass = {}; private passCore: schema.ValidPass;
public headerFields: FieldsArray; // Setting these as possibly undefined because we set
public primaryFields: FieldsArray; // them all in an loop later
public secondaryFields: FieldsArray; public headerFields: FieldsArray | undefined;
public auxiliaryFields: FieldsArray; public primaryFields: FieldsArray | undefined;
public backFields: FieldsArray; public secondaryFields: FieldsArray | undefined;
public auxiliaryFields: FieldsArray | undefined;
public backFields: FieldsArray | undefined;
private Certificates: schema.FinalCertificates; private Certificates: schema.FinalCertificates;
private [transitType]: string = ""; private [transitType]: string = "";
@@ -72,7 +74,8 @@ export class Pass {
} }
// Parsing and validating pass.json keys // 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) { if (this.type === current) {
// We want to exclude type keys (eventTicket, // We want to exclude type keys (eventTicket,
// boardingPass, ecc.) and their content // boardingPass, ecc.) and their content
@@ -86,10 +89,13 @@ export class Pass {
return { ...acc, [current]: this.passCore[current] }; return { ...acc, [current]: this.passCore[current] };
} }
const currentSchema = propsSchemaMap.get(current); const currentSchema = propsSchemaMap.get(current)!;
if (Array.isArray(this.passCore[current])) { if (Array.isArray(this.passCore[current])) {
const valid = getValidInArray(currentSchema, this.passCore[current]); const valid = getValidInArray<schema.ArrayPassSchema>(
currentSchema,
this.passCore[current] as schema.ArrayPassSchema[]
);
return { ...acc, [current]: valid }; return { ...acc, [current]: valid };
} else { } else {
return { return {
@@ -201,7 +207,7 @@ export class Pass {
* and returning the compiled manifest * and returning the compiled manifest
*/ */
const archive = new ZipFile(); const archive = new ZipFile();
const manifest = Object.keys(finalBundle).reduce((acc, current) => { const manifest = Object.keys(finalBundle).reduce<schema.Manifest>((acc, current) => {
let hashFlow = forge.md.sha1.create(); let hashFlow = forge.md.sha1.create();
hashFlow.update(finalBundle[current].toString("binary")); hashFlow.update(finalBundle[current].toString("binary"));
@@ -508,7 +514,7 @@ export class Pass {
* @returns {Buffer} * @returns {Buffer}
*/ */
private _sign(manifest: { [key: string]: string }): Buffer { private _sign(manifest: schema.Manifest): Buffer {
const signature = forge.pkcs7.createSignedData(); const signature = forge.pkcs7.createSignedData();
signature.content = forge.util.createBuffer(JSON.stringify(manifest), "utf8"); signature.content = forge.util.createBuffer(JSON.stringify(manifest), "utf8");
@@ -581,8 +587,8 @@ export class Pass {
* and then delete it from the passFile. * and then delete it from the passFile.
*/ */
["backgroundColor", "foregroundColor", "labelColor"] const passColors = ["backgroundColor", "foregroundColor", "labelColor"] as Array<keyof schema.PassColors>;
.filter(v => this[passProps][v] && !isValidRGB(this[passProps][v])) passColors.filter(v => this[passProps][v] && !isValidRGB(this[passProps][v]))
.forEach(v => delete this[passProps][v]); .forEach(v => delete this[passProps][v]);
Object.assign(passFile, this[passProps]); Object.assign(passFile, this[passProps]);
@@ -634,7 +640,7 @@ function barcodesFromUncompleteData(message: string): schema.Barcode[] {
"PKBarcodeFormatPDF417", "PKBarcodeFormatPDF417",
"PKBarcodeFormatAztec", "PKBarcodeFormatAztec",
"PKBarcodeFormatCode128" "PKBarcodeFormatCode128"
].map(format => schema.getValidated({ format, message }, "barcode")); ].map(format => schema.getValidated({ format, message }, "barcode") as schema.Barcode);
} }
function processRelevancySet<T>(key: string, data: T[]): T[] { function processRelevancySet<T>(key: string, data: T[]): T[] {

View File

@@ -3,6 +3,10 @@ import debug from "debug";
const schemaDebug = debug("Schema"); const schemaDebug = debug("Schema");
export interface Manifest {
[key: string]: string;
}
export interface Certificates { export interface Certificates {
wwdr?: string; wwdr?: string;
signerCert?: string; signerCert?: string;
@@ -71,7 +75,7 @@ export interface OverridesSupportedOptions {
teamIdentifier?: string; teamIdentifier?: string;
appLaunchURL?: string; appLaunchURL?: string;
associatedStoreIdentifiers?: Array<number>; associatedStoreIdentifiers?: Array<number>;
userInfo?: Object | Array<any>; userInfo?: { [key: string]: any };
webServiceURL?: string; webServiceURL?: string;
authenticationToken?: string; authenticationToken?: string;
sharingProhibited?: boolean; sharingProhibited?: boolean;
@@ -294,7 +298,7 @@ export interface ValidPassType {
storeCard?: PassFields; storeCard?: PassFields;
} }
export interface ValidPass extends OverridesSupportedOptions, ValidPassType { interface PassInterfacesProps {
barcode?: Barcode; barcode?: Barcode;
barcodes?: Barcode[]; barcodes?: Barcode[];
beacons?: Beacon[]; beacons?: Beacon[];
@@ -306,6 +310,12 @@ export interface ValidPass extends OverridesSupportedOptions, ValidPassType {
voided?: boolean; voided?: boolean;
} }
type AllPassProps = PassInterfacesProps & ValidPassType & OverridesSupportedOptions;
export type ValidPass = {
[K in keyof AllPassProps]: AllPassProps[K];
};
export type PassColors = Pick<OverridesSupportedOptions, "backgroundColor" | "foregroundColor" | "labelColor">;
export interface Barcode { export interface Barcode {
altText?: string; altText?: string;
messageEncoding?: string; messageEncoding?: string;
@@ -464,6 +474,7 @@ const schemas = {
}; };
export type Schema = keyof typeof schemas; export type Schema = keyof typeof schemas;
export type ArrayPassSchema = Beacon | Location | Barcode;
function resolveSchemaName(name: Schema) { function resolveSchemaName(name: Schema) {
return schemas[name] || undefined; return schemas[name] || undefined;
@@ -500,7 +511,7 @@ export function isValid(opts: any, schemaName: Schema): boolean {
* @returns {object} the filtered value or empty object * @returns {object} the filtered value or empty object
*/ */
export function getValidated<T extends Object>(opts: any, schemaName: Schema): T { export function getValidated<T extends Object>(opts: any, schemaName: Schema): T | null {
const resolvedSchema = resolveSchemaName(schemaName); const resolvedSchema = resolveSchemaName(schemaName);
if (!resolvedSchema) { if (!resolvedSchema) {

View File

@@ -11,7 +11,7 @@ import { sep } from "path";
* @returns {Boolean} True if valid rgb, false otherwise * @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") { if (!value || typeof value !== "string") {
return false; return false;
} }
@@ -89,10 +89,14 @@ export function generateStringFile(lang: { [index: string]: string }): Buffer {
* @param origin * @param origin
*/ */
export function splitBufferBundle(origin: Object): [PartitionedBundle["l10nBundle"], PartitionedBundle["bundle"]] { type PartitionedBundleElements = [PartitionedBundle["l10nBundle"], PartitionedBundle["bundle"]];
const keys = Object.keys(origin);
return keys.reduce(([ l10n, bundle ], current) => { export function splitBufferBundle(origin: any): PartitionedBundleElements {
if (current.includes(".lproj")) { return Object.keys(origin).reduce<PartitionedBundleElements>(([ l10n, bundle ], current) => {
if (!current.includes(".lproj")) {
return [ l10n, { ...bundle, [current]: origin[current] }];
}
const pathComponents = current.split(sep); const pathComponents = current.split(sep);
const lang = pathComponents[0]; const lang = pathComponents[0];
const file = pathComponents.slice(1).join("/"); const file = pathComponents.slice(1).join("/");
@@ -100,9 +104,6 @@ export function splitBufferBundle(origin: Object): [PartitionedBundle["l10nBundl
(l10n[lang] || (l10n[lang] = {}))[file] = origin[current]; (l10n[lang] || (l10n[lang] = {}))[file] = origin[current];
return [ l10n, bundle ]; return [ l10n, bundle ];
} else {
return [ l10n, { ...bundle, [current]: origin[current] }];
}
}, [{},{}]); }, [{},{}]);
} }