New Case Study:See how Anthropic automated 95% of dependency reviews with Socket.Learn More
Socket
Sign inDemoInstall
Socket

passkit-generator

Package Overview
Dependencies
Maintainers
1
Versions
55
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 1.3.2 to 1.3.3

28

API.md

@@ -19,3 +19,2 @@ # API Reference

```sh
$ # Bash terminal
$ DEBUG=* node index.js

@@ -36,3 +35,3 @@ ```

* [Instance](#method_constructor)
* Localize the pass
* [Localizing Passes](#localizing_passes)
* [.localize()](#method_localize)

@@ -50,3 +49,3 @@ * Setting barcode

* [.nfc()](#method_nfc)
* Setting Pass Structure Keys (primaryFields, secondaryFields, ...)
* [Setting Pass Structure Keys (primaryFields, secondaryFields, ...)](#prop_fields)
* [<field>.push()](#prop_fields-push)

@@ -89,5 +88,6 @@ * [<field>.pop()](#prop_fields-pop)

<br><br>
<a name="localizing_passes"></a>
___
**Localize the pass**:
**Localizing Passes**:
___

@@ -341,3 +341,3 @@

For the first two keys, the argument 'value' (which will be of type **Array\<Object>**) will be checked and filtered against a schema (one for type).
For the first two keys, the argument 'value' (which will be of type **Array\<Object>**) will be checked and filtered against dedicated schema.

@@ -406,2 +406,3 @@ For *relevantDate*, the date is parsed in the same formats of [#expiration()](#method_expiration). For *maxDistance*, the value is simply converted as Number and pushed only with successful conversion.

<br>
<a name="prop_fields"></a>
___

@@ -443,11 +444,11 @@

pass.headerFields.push({
"key": "header1",
"label": "Data",
"value": "25 mag",
"textAlignment": "PKTextAlignmentCenter"
key: "header1",
label: "Data",
value: "25 mag",
textAlignment: "PKTextAlignmentCenter"
}, {
"key": "header2",
"label": "Volo",
"value": "EZY997",
"textAlignment": "PKTextAlignmentCenter"
key: "header2",
label: "Volo",
value: "EZY997",
textAlignment: "PKTextAlignmentCenter"
});

@@ -546,3 +547,2 @@

```javascript
...
pass.generate()

@@ -549,0 +549,0 @@ .then(stream => {

@@ -14,4 +14,8 @@ # Examples

Certificates paths in examples are linked to a folder `certificates` in the root of this project which is not provided.
To make them work, you'll have to edit both certificates and model path.
Generates pass will be generated at address [http://localhost:3000/gen/examplePass](http://localhost:3000/gen/examplePass);
___
Every contribution is really appreciated. ❤️ Thank you!
{
"name": "passkit-generator",
"version": "1.3.2",
"version": "1.3.3",
"description": "The easiest way to generate custom Apple Wallet passes in Node.js",

@@ -26,2 +26,5 @@ "main": "index.js",

},
"engines": {
"node": ">=8.1.0"
},
"devDependencies": {

@@ -28,0 +31,0 @@ "express": "^4.16.3",

# Node PassKit Generator
This is my implementation of a generator for [Apple Wallet Passes](https://developer.apple.com/wallet/). The idea was born during the Apple Developer Academy 17/18, in Naples, driven by the need to develop an iOS app component regarding passes generation for events.
Simple Node.js interface to generate customized [Apple Wallet Passes](https://developer.apple.com/wallet/) for iOS.
### Architecture
### Installation
This generator has two sides: application and model creation.
This package was created with a specific architecture in mind: **application** and **model**, to split as much as possible static objects (such as logo, background, icon, etc.) from dynamic ones (translations, barcodes, serialNumber, ...).
In fact, the pass template creation does not happen in the application. Instead you'll first have to create a folder containing all the static medias for a pass (logo, background, icon, etc.) while the dynamic info (such translations, barcodes, serialNumber and so on) will be applied in runtime.
In fact, pass template (model) creation and population doesn't happen within the application in runtime. Pass template is a folder in _your application directory_ (but nothing will stop you from putting it outside), that will contain all the needed objects (static medias) and structure to make a pass work.
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.
### Install
```sh

@@ -15,13 +20,17 @@ $ npm install passkit-generator --save

To see the API Reference, please refer to [API document](./API.md).
Created under Node.js v10.8.0.
### Compatibility
This package is compatible starting with Node v8.1.0+.
___
## Get Started
##### Model
The first thing you'll have to do, is to start creating a model. A model is a folder in your project directory, with inside the basic pass infos, like the thumbnails, the icon, and the background and **pass.json** containing all the static infos about the pass, like Team identifier, Pass type identifier, colors, etc.
> Using the .pass extension is a best practice, showing that the directory is a pass package.
> (cit. [Build your first pass - Apple Developer Portal](https://apple.co/2LYXWo3)).
> ([Build your first pass - Apple Developer Portal](https://apple.co/2LYXWo3)).
Following to this suggestion, each model is required to have a **.pass** extension (as suggested by Apple).
Following to this suggestion, each model is required to have a **.pass** extension.

@@ -35,3 +44,3 @@ ```bash

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 the API, [.localize()](./API.md#method_localize) method.
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.

@@ -42,10 +51,10 @@ ##### Pass.json

```javascript
```json
{
"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": {}
}

@@ -55,3 +64,3 @@ ```

##### Certificates
> Requirements: OpenSSL,
> Requirements: OpenSSL,

@@ -81,2 +90,3 @@ The third step is about the developer and WWDR certificates. I suggest you to create a certificate-dedicated folder inside your working directory (e.g. `./certs`) to contain everything concerning the certificates. This is a standard procedure: you would have to do it also without using this library.

___

@@ -121,8 +131,13 @@ ## Usage example

___
## Other
If you developed any projects using this library, open an issue topic and link it inside if open to all or just tell it. 😊 You'll make me feel like my time hasn't been wasted (it had not anyway, I learnt a lot of things by doing this).
If you developed any public projects using this library, open a topic in issues and link it inside if open to all or just tell it. 😊 You'll make me feel like my time hasn't been wasted (it had not anyway, I learnt a lot of things by doing this).
Be sure to not include the certificates if you publish your project open to everybody.
Any contribution is welcome ❤️
A big thanks to all the people and friends in the Apple Developer Academy that pushed me and helped me into realizing something like this and a big thanks to the ones that helped me to make technical choices.
Any contribution is welcome. ❤️
The idea to develop this package, was born during the Apple Developer Academy 17/18, in Naples, Italy, driven by the need to create an iOS app component regarding passes generation for events.
A big thanks to all the people and friends in the Apple Developer Academy (and not) that pushed me and helped me into realizing something like this and a big thanks to the ones that helped me to make technical choices.
const schema = require("./schema");
const debug = require("debug")("passkit:fields");

@@ -8,5 +9,6 @@ /**

let uniqueKeys = [];
class FieldsContainer {
constructor() {
this._uniqueKeys = [];
this.fields = [];

@@ -30,12 +32,17 @@ }

let validFields = fieldsData.filter(f => {
if (this._uniqueKeys.includes(f.key)) {
return false;
let validFields = fieldsData.reduce((acc, current) => {
if (!(typeof current === "object") || !schema.isValid(current, "field")) {
return acc;
}
this._uniqueKeys.push(f.key);
if (acc.some(e => e.key === current.key) || uniqueKeys.includes(current.key)) {
debug(`UNIQUE field key CONSTRAINT VIOLATED. Fields keys must be unique in pass scope. Field key: "${current.key}"`);
return acc;
}
return typeof f === "object" && schema.isValid(f, "field");
});
acc.push(current);
return acc;
}, []);
uniqueKeys.push(...validFields.map(v => v.key));
this.fields.push(...validFields);

@@ -71,4 +78,8 @@

}
static emptyUnique() {
uniqueKeys = [];
}
}
module.exports = FieldsContainer;
let errors = {
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.",
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.",
MANIFEST_TYPE: "Manifest content must be a string or an object. Unable to accept manifest of type %s",
REQS_NOT_MET: "The options passed to Pass constructor does not meet the requirements. Refer to the documentation to compile them correctly.",

@@ -6,0 +5,0 @@ MODEL_NOT_STRING: "A string model name must be provided in order to continue.",

@@ -152,2 +152,4 @@ const fs = require("fs");

FieldsContainer.emptyUnique();
return archive.finalize().then(() => passStream);

@@ -469,3 +471,3 @@ });

* @method _sign
* @params {String|Object} manifest - Manifest content.
* @params {Object} manifest - Manifest content.
* @returns {Buffer}

@@ -477,9 +479,3 @@ */

if (typeof manifest === "object") {
signature.content = forge.util.createBuffer(JSON.stringify(manifest), "utf8");
} else if (typeof manifest === "string") {
signature.content = manifest;
} else {
throw new Error(errors.MANIFEST_TYPE.replace("%s", typeof manifest));
}
signature.content = forge.util.createBuffer(JSON.stringify(manifest), "utf8");

@@ -489,6 +485,14 @@ signature.addCertificate(this.Certificates.wwdr);

/**
* 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: forge.pki.oids.sha1,
authenticatedAttributes: [{

@@ -500,3 +504,2 @@ type: forge.pki.oids.contentType,

}, {
// the value is autogenerated
type: forge.pki.oids.signingTime,

@@ -506,23 +509,23 @@ }]

signature.sign();
/**
* We are creating a detached signature because we don't need the signed content.
* Detached signature is a property of PKCS#7 cryptography standard.
*/
/*
* Signing creates in contentInfo a JSON object nested BER/TLV (X.690 standard) structure.
* Each object represents a component of ASN.1 (Abstract Syntax Notation)
* For a more complete reference, refer to: https://en.wikipedia.org/wiki/X.690#BER_encoding
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
* signed content as value.
*
* signature.contentInfo.type => SEQUENCE OF (16)
* signature.contentInfo.value[0].type => OBJECT IDENTIFIER (6)
* signature.contantInfo.value[1].type => END OF CONTENT (EOC - 0)
* In fact the previous approach was to generating a detached signature and the pull away the generated
* content.
*
* EOC are only present only in constructed indefinite-length methods
* Since `signature.contentInfo.value[1].value` contains an object whose value contains the content we passed,
* we have to pop the whole object away to avoid signature content invalidation.
*
* 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. ¯\_(ツ)_/¯
*/
signature.contentInfo.value.pop();
// Converting the JSON Structure into a DER (which is a subset of BER), ASN.1 valid structure
// Returning the buffer of the signature
return Buffer.from(forge.asn1.toDer(signature.toAsn1()).getBytes(), "binary");

@@ -529,0 +532,0 @@ }

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