mirror of
https://github.com/marcogll/passkit-generator.git
synced 2026-03-15 14:25:17 +00:00
Moved pass.json to typescript; Removed load method from pass implementation
This commit is contained in:
40
API.md
40
API.md
@@ -44,8 +44,6 @@ ___
|
||||
* [.relevance()](#method_relevance)
|
||||
* Setting NFC
|
||||
* [.nfc()](#method_nfc)
|
||||
* Getting remote resources
|
||||
* [.load()](#method_load)
|
||||
* [Setting Pass Structure Keys (primaryFields, secondaryFields, ...)](#prop_fields)
|
||||
* [TransitType](#prop_transitType)
|
||||
* Generating the compiled pass.
|
||||
@@ -402,44 +400,6 @@ ___
|
||||
**Getting remote resources**:
|
||||
___
|
||||
|
||||
<a name="method_load"></a>
|
||||
|
||||
#### .load()
|
||||
|
||||
```javascript
|
||||
pass.load(resource, name);
|
||||
```
|
||||
|
||||
**Returns**:
|
||||
|
||||
`Object<Pass> (this)`
|
||||
|
||||
**Description**:
|
||||
|
||||
Sets the resources to be downloaded in runtime to be pushed in the pass.
|
||||
Use `name` param to give your downloaded file a name or to provide the folder path it will be pushed into (with the name, _obv._).
|
||||
|
||||
Requests are not cached and load method can only load pictures right now (no other types should be required). In case of conflict between downloaded files and model files, downloaded files will have the priority and will be putted in the zip file.
|
||||
|
||||
When in debug mode, file header is shown.
|
||||
|
||||
**Arguments**:
|
||||
|
||||
| Key | Type | Description | Optional | Default Value |
|
||||
|-----|------|-------------|----------|:-------------:|
|
||||
| resource | String | The URL where to fetch the picture | false | -
|
||||
| name | String | The name / path to be used to call this | false | -
|
||||
|
||||
**Example**:
|
||||
|
||||
```javascript
|
||||
pass.load("http://...", "icon.png");
|
||||
pass.load("http://...", "en.lproj/icon.png");
|
||||
```
|
||||
|
||||
<br>
|
||||
<br>
|
||||
|
||||
<a name="prop_fields"></a>
|
||||
___
|
||||
|
||||
|
||||
@@ -18,7 +18,7 @@ This package was created with a specific architecture in mind: **application** a
|
||||
|
||||
Actually, pass creation and population doesn't fully happen within the application in runtime. Pass template is a folder in, for example, _your application directory_ (but nothing will stop you from putting it outside), that will contain all the objects needed (static medias) and structure to make a pass work.
|
||||
|
||||
Pass template will be read and pushed as is in the resulting .zip file along with web-fetched medias (also considered dynamic objects), while dynamic objects will be patched against `pass.json` or generated in runtime (`manifest.json`, `signature` and translation files).
|
||||
Pass template will be read and pushed as is in the resulting .zip file, while dynamic objects will be patched against `pass.json` or generated in runtime (`manifest.json`, `signature` and translation files).
|
||||
|
||||
This package comes with an [API documentation](./API.md), that makes available a series of methods to customize passes.
|
||||
|
||||
|
||||
@@ -21,7 +21,6 @@
|
||||
"dependencies": {
|
||||
"archiver": "^3.0.0",
|
||||
"debug": "^3.2.6",
|
||||
"got": "^9.6.0",
|
||||
"joi": "^13.7.0",
|
||||
"moment": "^2.24.0",
|
||||
"node-forge": "^0.7.6"
|
||||
@@ -32,7 +31,6 @@
|
||||
"devDependencies": {
|
||||
"@types/archiver": "^2.1.3",
|
||||
"@types/debug": "^4.1.4",
|
||||
"@types/got": "^9.4.4",
|
||||
"@types/joi": "^14.3.3",
|
||||
"@types/node": "^12.0.0",
|
||||
"@types/node-forge": "^0.8.2",
|
||||
|
||||
@@ -21,10 +21,7 @@ const debugMessages: MessageGroup = {
|
||||
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 a string or an object with no message field",
|
||||
BRC_BW_FORMAT_UNSUPPORTED: "This format is not supported (by Apple) for backward support. Please choose another one.",
|
||||
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"
|
||||
DATE_FORMAT_UNMATCH: "%s was not set due to incorrect date format."
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,24 +1,22 @@
|
||||
const fs = require("fs");
|
||||
const path = require("path");
|
||||
const { promisify } = require("util");
|
||||
const stream = require("stream");
|
||||
const forge = require("node-forge");
|
||||
const archiver = require("archiver");
|
||||
const debug = require("debug");
|
||||
const got = require("got");
|
||||
import fs from "fs";
|
||||
import path from "path";
|
||||
import { promisify } from "util";
|
||||
import stream from "stream";
|
||||
import forge from "node-forge";
|
||||
import archiver from "archiver";
|
||||
import debug from "debug";
|
||||
|
||||
const barcodeDebug = debug("passkit:barcode");
|
||||
const genericDebug = debug("passkit:generic");
|
||||
const loadDebug = debug("passkit:load");
|
||||
|
||||
const schema = require("./schema");
|
||||
const formatMessage = require("./messages");
|
||||
const FieldsArray = require("./fieldsArray");
|
||||
const {
|
||||
import * as schema from "./schema";
|
||||
import formatMessage from "./messages";
|
||||
import FieldsArray from "./fieldsArray";
|
||||
import {
|
||||
assignLength, generateStringFile,
|
||||
removeHidden, dateToW3CString,
|
||||
isValidRGB
|
||||
} = require("./utils");
|
||||
} from "./utils";
|
||||
|
||||
const barcodeDebug = debug("passkit:barcode");
|
||||
const genericDebug = debug("passkit:generic");
|
||||
|
||||
const readdir = promisify(fs.readdir);
|
||||
const readFile = promisify(fs.readFile);
|
||||
@@ -28,8 +26,23 @@ const transitType = Symbol("transitType");
|
||||
const barcodesFillMissing = Symbol("bfm");
|
||||
const barcodesSetBackward = Symbol("bsb");
|
||||
|
||||
class Pass {
|
||||
constructor(options) {
|
||||
interface PassIndexSignature {
|
||||
[key: string]: any;
|
||||
}
|
||||
|
||||
export class Pass implements PassIndexSignature {
|
||||
private model: string;
|
||||
private _fields: string[];
|
||||
private _props: { [key: string]: any };
|
||||
private type: string;
|
||||
private fieldsKeys: Set<string>;
|
||||
|
||||
Certificates: schema.Certificates;
|
||||
l10n: { [key: string]: { [key: string]: string } } = {};
|
||||
shouldOverwrite: boolean;
|
||||
[transitType]: string = "";
|
||||
|
||||
constructor(options: schema.PassInstance) {
|
||||
this.Certificates = {
|
||||
// Even if this assigning will fail, it will be captured below
|
||||
// in _parseSettings, since this won't match with the schema.
|
||||
@@ -38,8 +51,6 @@ class Pass {
|
||||
|
||||
options.overrides = options.overrides || {};
|
||||
|
||||
this.l10n = {};
|
||||
this._remoteResources = [];
|
||||
this.shouldOverwrite = !(options.hasOwnProperty("shouldOverwrite") && !options.shouldOverwrite);
|
||||
|
||||
this._fields = ["primaryFields", "secondaryFields", "auxiliaryFields", "backFields", "headerFields"];
|
||||
@@ -69,37 +80,10 @@ class Pass {
|
||||
// Reading the model
|
||||
const modelFilesList = await readdir(this.model);
|
||||
|
||||
/**
|
||||
* Getting the buffers for remote files
|
||||
*/
|
||||
|
||||
const buffersPromise = await this._remoteResources.reduce(async (acc, current) => {
|
||||
try {
|
||||
const response = await got(current[0], { encoding: null });
|
||||
loadDebug(formatMessage("LOAD_MIME", response.headers["content-type"]));
|
||||
|
||||
if (!Buffer.isBuffer(response.body)) {
|
||||
throw "LOADED_RESOURCE_NOT_A_BUFFER";
|
||||
}
|
||||
|
||||
if (!response.headers["content-type"].includes("image/")) {
|
||||
throw "LOADED_RESOURCE_NOT_A_PICTURE";
|
||||
}
|
||||
|
||||
return [...acc, response.body];
|
||||
} catch (err) {
|
||||
loadDebug(formatMessage("LOAD_NORES", current[1], err));
|
||||
return acc;
|
||||
}
|
||||
}, []);
|
||||
|
||||
const remoteFilesList = buffersPromise.length ? this._remoteResources.map(r => r[1]): [];
|
||||
|
||||
// list without dynamic components like manifest, signature or pass files (will be added later in the flow) and hidden files.
|
||||
const noDynList = removeHidden(modelFilesList).filter(f => !/(manifest|signature|pass)/i.test(f));
|
||||
const hasAssets = noDynList.length || remoteFilesList.length;
|
||||
|
||||
if (!hasAssets || ![...noDynList, ...remoteFilesList].some(f => f.toLowerCase().includes("icon"))) {
|
||||
if (!noDynList.length || !noDynList.some(f => f.toLowerCase().includes("icon"))) {
|
||||
let eMessage = formatMessage("MODEL_UNINITIALIZED", path.parse(this.model).name);
|
||||
throw new Error(eMessage);
|
||||
}
|
||||
@@ -132,12 +116,6 @@ class Pass {
|
||||
|
||||
/* Getting all bundle file buffers, pass.json included, and appending path */
|
||||
|
||||
if (remoteFilesList.length) {
|
||||
// Removing files in bundle that also exist in remoteFilesList
|
||||
// I'm giving priority to downloaded files
|
||||
bundle = bundle.filter(file => !remoteFilesList.includes(file));
|
||||
}
|
||||
|
||||
// Reading bundle files to buffers without pass.json - it gets read below
|
||||
// to use a different parsing process
|
||||
|
||||
@@ -145,7 +123,7 @@ class Pass {
|
||||
const passBuffer = this._extractPassDefinition();
|
||||
bundle.push("pass.json");
|
||||
|
||||
const buffers = await Promise.all([...bundleBuffers, passBuffer, ...buffersPromise]);
|
||||
const buffers = await Promise.all([...bundleBuffers, passBuffer]);
|
||||
|
||||
Object.keys(this.l10n).forEach(lang => {
|
||||
const strings = generateStringFile(this.l10n[lang]);
|
||||
@@ -183,9 +161,6 @@ class Pass {
|
||||
}
|
||||
});
|
||||
|
||||
// Pushing the remote files into the bundle
|
||||
bundle.push(...remoteFilesList);
|
||||
|
||||
/*
|
||||
* Parsing the buffers, pushing them into the archive
|
||||
* and returning the compiled manifest
|
||||
@@ -506,23 +481,6 @@ class Pass {
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads a web resource (image)
|
||||
* @param {string} resource
|
||||
* @param {string} name
|
||||
*/
|
||||
|
||||
load(resource, name) {
|
||||
if (typeof resource !== "string" && typeof name !== "string") {
|
||||
loadDebug(formatMessage("LOAD_TYPES_UNMATCH"));
|
||||
return;
|
||||
}
|
||||
|
||||
this._remoteResources.push([resource, name]);
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if pass model type is one of the supported ones
|
||||
*
|
||||
@@ -589,8 +547,9 @@ class Pass {
|
||||
*/
|
||||
|
||||
signature.addSigner({
|
||||
key: this.Certificates.signerKey,
|
||||
key: this.Certificates.signerKey.keyFile,
|
||||
certificate: this.Certificates.signerCert,
|
||||
digestAlgorithm: forge.pki.oids.sha1,
|
||||
authenticatedAttributes: [{
|
||||
type: forge.pki.oids.contentType,
|
||||
value: forge.pki.oids.data
|
||||
@@ -731,7 +690,7 @@ class Pass {
|
||||
* @returns {Object} - parsed certificates to be pushed to Pass.Certificates.
|
||||
*/
|
||||
|
||||
function readCertificates(certificates) {
|
||||
function readCertificates(certificates: schema.Certificates) {
|
||||
if (certificates.wwdr && certificates.signerCert && typeof certificates.signerKey === "object") {
|
||||
// Nothing must be added. Void object is returned.
|
||||
return Promise.resolve({});
|
||||
@@ -740,14 +699,14 @@ function readCertificates(certificates) {
|
||||
const raw = certificates._raw;
|
||||
const optCertsNames = Object.keys(raw);
|
||||
const certPaths = optCertsNames.map((val) => {
|
||||
const cert = raw[val];
|
||||
const cert: string | typeof certificates.signerKey = raw[val];
|
||||
// realRawValue exists as signerKey might be an object
|
||||
const realRawValue = !(cert instanceof Object) ? cert : cert["keyFile"];
|
||||
|
||||
// We are checking if the string is a path or a content
|
||||
if (!!path.parse(realRawValue).ext) {
|
||||
const resolvedPath = path.resolve(realRawValue);
|
||||
return readFile(resolvedPath);
|
||||
return readFile(resolvedPath, { encoding: "utf8" });
|
||||
} else {
|
||||
return Promise.resolve(realRawValue);
|
||||
}
|
||||
@@ -759,6 +718,7 @@ function readCertificates(certificates) {
|
||||
// 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);
|
||||
@@ -825,5 +785,3 @@ function barcodesFromUncompleteData(origin) {
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
module.exports = { Pass };
|
||||
Reference in New Issue
Block a user