From 9a9d883d3fb00716790ba785bbda1ffc5f7563ce Mon Sep 17 00:00:00 2001 From: alexandercerutti Date: Sat, 29 Dec 2018 02:00:57 +0100 Subject: [PATCH] Fixed problem in error message resolving on multiple %s; Added debug messages in messages.js; Added more comments; Moved literal debug messages to messages.js; Edited formatMessage (was formatError) to check also among debugMessages --- src/messages.js | 39 +++++++++++++++++++++++++++++++-------- src/pass.js | 47 ++++++++++++++++++++++++----------------------- 2 files changed, 55 insertions(+), 31 deletions(-) diff --git a/src/messages.js b/src/messages.js index 23fa5f8..0532ca4 100644 --- a/src/messages.js +++ b/src/messages.js @@ -1,28 +1,51 @@ -let errors = { +const errors = { PASSFILE_VALIDATION_FAILED: "Validation of pass type failed. Pass file is not a valid buffer or (more probabily) does not respect the schema. Refer to https://apple.co/2Nvshvn to build a correct pass.", REQUIR_VALID_FAILED: "The options passed to Pass constructor does not meet the requirements. Refer to the documentation to compile them correctly.", MODEL_UNINITIALIZED: "Provided model ( %s ) matched but unitialized or may not contain icon. Refer to https://apple.co/2IhJr0Q, https://apple.co/2Nvshvn and documentation to fill the model correctly.", MODEL_NOT_STRING: "A string model name must be provided in order to continue.", MODEL_NOT_FOUND: "Model %s not found. Provide a valid one to continue.", INVALID_CERTS: "Invalid certificate(s) loaded: %s. Please provide valid WWDR certificates and developer signer certificate and key (with passphrase). Refer to docs to obtain them.", - INVALID_CERT_PATH: "Invalid certificate loaded. %s does not exist." + INVALID_CERT_PATH: "Invalid certificate loaded. %s does not exist.", + TRSTYPE_REQUIRED: "Cannot proceed with pass creation. transitType field is required for boardingPasses.", }; -function format(errorName, ...values) { +const debugMessages = { + 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]", + BRC_NOT_SUPPORTED: "Format not found among barcodes. Cannot set backward compatibility.", + BRC_FORMATTYPE_UNMATCH: "Format must be a string or null. Cannot set backward compatibility.", + BRC_AUTC_MISSING_DATA: "Unable to autogenerate barcodes. Data is not an object or has not message field.", + DATE_FORMAT_UNMATCH: "%s was not set due to incorrect date format.", + LOAD_TYPES_UNMATCH: "Resource and name are not valid strings. No action will be taken for the specified medias.", + LOAD_MIME: "Picture MIME-type: %s", + LOAD_NORES: "Was not able to fetch resource %s. Error: %s" +}; + +/** + * Creates a message with replaced values + * @param {string} messageName + * @param {any[]} values + */ + +function format(messageName, ...values) { // reversing because it is better popping than shifting. let replaceValues = values.reverse(); - return resolveErrorName(errorName).replace(/%s/, () => { + return resolveMessageName(messageName).replace(/%s/g, () => { let next = replaceValues.pop(); return next !== undefined ? next : ""; }); } -function resolveErrorName(name) { - if (!errors[name]) { - return ``; +/** + * Looks among errors and debugMessages for the specified message name + * @param {string} name + */ + +function resolveMessageName(name) { + if (!errors[name] && !debugMessages[name]) { + return ``; } - return errors[name]; + return errors[name] || debugMessages[name]; } module.exports = format; diff --git a/src/pass.js b/src/pass.js index 16ea330..56a2fb7 100644 --- a/src/pass.js +++ b/src/pass.js @@ -13,7 +13,7 @@ const genericDebug = debug("passkit:generic"); const loadDebug = debug("passkit:load"); const schema = require("./schema"); -const formatError = require("./messages"); +const formatMessage = require("./messages"); const FieldsContainer = require("./fields"); const readdir = promisify(fs.readdir); @@ -58,7 +58,7 @@ class Pass { // May have not used this catch but ENOENT error is not enough self-explanatory // in the case of internal usage () if (err.code && err.code === "ENOENT") { - throw new Error(formatError("MODEL_NOT_FOUND", this.model)); + throw new Error(formatMessage("MODEL_NOT_FOUND", this.model)); } throw new Error(err); @@ -71,20 +71,20 @@ class Pass { let buffersPromise = this._remoteResources.map((r) => { return got(r[0], { encoding: null }) .then(response => { - loadDebug(`Picture MIME-type: ${response.headers["content-type"]}`); + loadDebug(formatMessage("LOAD_MIME", response.headers["content-type"])); if (!Buffer.isBuffer(response.body)) { - throw "NOTABUFFER"; + throw "LOADED_RESOURCE_NOT_A_BUFFER"; } if (!response.headers["content-type"].includes("image/")) { - throw "NOTAPICTURE"; + throw "LOADED_RESOURCE_NOT_A_PICTURE"; } return response.body; }) .catch(e => { - loadDebug(`Was not able to fetch resource ${r[1]}. Error: ${e}`); + loadDebug(formatMessage("LOAD_NORES", r[1], e)); // here we are adding undefined values, that will be removed later. return undefined; }); @@ -102,7 +102,7 @@ class Pass { let noDynList = removeHidden(modelFileList).filter(f => !/(manifest|signature|pass)/i.test(f)); if (!noDynList.length || ![...noDynList, ...remoteFilesList].some(f => f.toLowerCase().includes("icon"))) { - let eMessage = formatError("MODEL_UNINITIALIZED", path.parse(this.model).name); + let eMessage = formatMessage("MODEL_UNINITIALIZED", path.parse(this.model).name); throw new Error(eMessage); } @@ -123,7 +123,7 @@ class Pass { return readFile(path.resolve(this.model, "pass.json")) .then(passStructBuffer => { if (!this._validateType(passStructBuffer)) { - let eMessage = formatError("PASSFILE_VALIDATION_FAILED"); + let eMessage = formatMessage("PASSFILE_VALIDATION_FAILED"); throw new Error(eMessage); } @@ -251,7 +251,7 @@ class Pass { let dateParse = dateToW3CString(date, format); if (!dateParse) { - genericDebug("Expiration Date was not set due to invalid format."); + genericDebug(formatMessage("DATE_FORMAT_UNMATCH", "Expiration date")); } else { this._props.expirationDate = dateParse; } @@ -320,7 +320,7 @@ class Pass { let dateParse = dateToW3CString(data, relevanceDateFormat); if (!dateParse) { - genericDebug("Relevant Date was not set due to incorrect date format."); + genericDebug(formatMessage("DATE_FORMAT_UNMATCH", "Relevant Date")); } else { this._props[type] = dateParse; } @@ -402,7 +402,7 @@ class Pass { __barcodeAutogen(data) { if (!data || !(data instanceof Object) || !data.message) { - barcodeDebug("Unable to autogenerate barcodes. Data is not an object or has not message field."); + barcodeDebug(formatMessage("BRC_AUTC_MISSING_DATA")); return []; } @@ -459,7 +459,7 @@ class Pass { } if (typeof format !== "string") { - barcodeDebug("format must be a string or null. Cannot set backward compatibility."); + barcodeDebug(formatMessage("BRC_FORMAT_UNMATCH")); return this; } @@ -467,7 +467,7 @@ class Pass { let index = this._props["barcodes"].findIndex(b => b.format.toLowerCase().includes(format.toLowerCase())); if (index === -1) { - barcodeDebug("format not found among barcodes. Cannot set backward compatibility."); + barcodeDebug(formatMessage("BRC_NOT_SUPPORTED")); return this; } @@ -506,7 +506,7 @@ class Pass { load(resource, name) { if (typeof resource !== "string" && typeof name !== "string") { - loadDebug("resource and name are not valid strings. No action will be taken."); + loadDebug(formatMessage("LOAD_TYPES_UNMATCH")); return; } @@ -644,8 +644,8 @@ class Pass { } }); - if (!this.transitType && this.type === "boardingPass") { - throw new Error("Cannot proceed with pass creation. transitType field is required for boardingPasses."); + if (this.type === "boardingPass" && !this.transitType) { + throw new Error(formatMessage("TRSTYPE_REQUIRED")); } passFile[this.type]["transitType"] = this.transitType; @@ -662,15 +662,12 @@ class Pass { */ _parseSettings(options) { - let eMessage = null; if (!schema.isValid(options, "instance")) { - eMessage = formatError("REQUIR_VALID_FAILED"); - throw new Error(eMessage); + throw new Error(formatMessage("REQUIR_VALID_FAILED")); } if (!options.model || typeof options.model !== "string") { - eMessage = formatError("MODEL_NOT_STRING"); - throw new Error(eMessage); + throw new Error(formatMessage("MODEL_NOT_STRING")); } let modelPath = path.resolve(options.model) + (!!options.model && !path.extname(options.model) ? ".pass" : ""); @@ -687,6 +684,7 @@ class Pass { if (schema.isValid(v, "transitType")) { this._transitType = v; } else { + genericDebug(formatMessage("TRSTYPE_NOT_VALID", v)); this._transitType = this._transitType || ""; } } @@ -723,13 +721,16 @@ function readCertificates(certificates) { return Promise.all(certPaths) .then(contents => { + // Mapping each file content to a PEM structure, returned in form of one-key-object + // which is conjoint later with the other pems + return Object.assign( ...contents.map((file, index) => { const certName = optCertsNames[index]; const pem = parsePEM(certName, file, raw[certName].passphrase); if (!pem) { - throw new Error(formatError("INVALID_CERTS", certName)); + throw new Error(formatMessage("INVALID_CERTS", certName)); } return { [certName]: pem }; @@ -741,7 +742,7 @@ function readCertificates(certificates) { throw err; } - throw new Error(formatError("INVALID_CERT_PATH", path.parse(err.path).base)); + throw new Error(formatMessage("INVALID_CERT_PATH", path.parse(err.path).base)); }); }