mirror of
https://github.com/marcogll/passkit-generator.git
synced 2026-03-15 23:25:26 +00:00
Added documentation
This commit is contained in:
549
API.md
Normal file
549
API.md
Normal file
@@ -0,0 +1,549 @@
|
||||
# API Reference
|
||||
|
||||
The flow of execution is really easy (once setted-up everything):
|
||||
|
||||
* You get your data from somewhere
|
||||
* You set the needed data in the pass through methods, overrides and data in fields
|
||||
* You generate the pass stream through `.generate()` method
|
||||
* Hooray 😄🎉
|
||||
|
||||
Some details:
|
||||
|
||||
* Every schema the properties will be checked against, is built to reflect Apple's specifications, that can be found on Apple Developer Portal, at [PassKit Package Format Reference](https://apple.co/2MUHsm0).
|
||||
|
||||
* Here below are listed all the available methods that library will let you use.
|
||||
|
||||
* In case of troubleshooting, you can start your project with "debug flag" as follows:
|
||||
|
||||
```sh
|
||||
$ # Bash terminal
|
||||
$ DEBUG=* node index.js
|
||||
```
|
||||
|
||||
For other OSs, see [Debug Documentation](https://www.npmjs.com/package/debug).
|
||||
|
||||
* Keep this as always valid for the reference:
|
||||
|
||||
```javascript
|
||||
const { Pass } = require("passkit-generator");
|
||||
```
|
||||
___
|
||||
|
||||
### Index:
|
||||
|
||||
* [Instance](#method:constructor)
|
||||
* Localize the pass
|
||||
* [.localize()](#method:localize)
|
||||
* Setting barcode
|
||||
* [.barcode()](#method:barcode)
|
||||
* [.backward()](#method:bBackward)
|
||||
* [.autocomplete()](#method:bAutocomplete)
|
||||
* Setting expiration / voiding the pass
|
||||
* [.expiration()](#method:expiration)
|
||||
* [.void()](#method:void)
|
||||
* Setting relevance
|
||||
* [.relevance()](#method:relevance)
|
||||
* Setting NFC
|
||||
* [.nfc()](#method:nfc)
|
||||
* Setting Pass Structure Keys (primaryFields, secondaryFields, ...)
|
||||
* [<field>.push()](#prop:fields-push)
|
||||
* [<field>.pop()](#prop:fields-pop)
|
||||
* [TransitType](#prop:transitType)
|
||||
* Generating the compiled pass.
|
||||
* [.generate()](#method:generate)
|
||||
|
||||
<br><br>
|
||||
___
|
||||
|
||||
<a name="method:constructor">
|
||||
#### constructor()
|
||||
</a>
|
||||
|
||||
```javascript
|
||||
var pass = new Pass(options);
|
||||
```
|
||||
|
||||
**Returns**:
|
||||
|
||||
`Object<Pass>`
|
||||
|
||||
**Arguments**:
|
||||
|
||||
| Key | Type | Description | Optional | Default Value |
|
||||
|-----|------|---------------|:-------------:|:-----------:|
|
||||
| options | Object | The options to create the pass | false | -
|
||||
| options.model | String/Path | The model path to be used to generate a new model. | false | -
|
||||
| options.certificates | Object | The certificate object containing the paths to certs files. | false | -
|
||||
| options.certificates.wwdr | String/Path | The path to Apple WWDR certificate. | false | -
|
||||
| options.certificates.signerCert | String/Path | The path to Developer certificate file. | false | -
|
||||
| options.certificates.signerKey | Object | The object containing developer certificate's key and passphrase. | false | -
|
||||
| options.certificates.signerKey.keyFile | String/Path | The path to developer certificate key. | false | -
|
||||
| options.certificates.signerKey.passphrase | String \| Number | The passphrase to use to unlock the key. | false | -
|
||||
| options.overrides | Object | Dictionary containing all the keys you can override in the pass.json file and does not have a method to get overridden. | true | { }
|
||||
| options.shouldOverwrite | Boolean | Setting this property to false, will make properties in `overrides` and fields to be pushed along with the ones added through methods to the existing ones in pass.json. | true | true
|
||||
|
||||
<br><br>
|
||||
___
|
||||
|
||||
**Localize the pass**:
|
||||
___
|
||||
|
||||
Following Apple Developer Documentation, localization (L10N) is done by creating a `.lproj` folder for each language you want to translate your pass, each named with the relative [ISO-3166-1 alpha-2](https://it.wikipedia.org/wiki/ISO_3166-1_alpha-2) code (e.g. `en.lproj`).
|
||||
|
||||
In this library, localization can be done in three ways: **media-only** (images), **translations-only** or both.
|
||||
The only differences stands in the way the only method below is used and how the model is designed.
|
||||
|
||||
> If you are designing your pass for a language only, you can directly replace the placeholders in `pass.json` with translation.
|
||||
|
||||
<br>
|
||||
<a name="method:localize">
|
||||
#### .localize()
|
||||
</a>
|
||||
|
||||
```javascript
|
||||
pass.localize(lang, options);
|
||||
```
|
||||
|
||||
**Returns**:
|
||||
|
||||
`Object<Pass> (this)`
|
||||
|
||||
**Description**:
|
||||
|
||||
You may want to create the folder and add translated media and no translations; else you may want to add only translations without different medias or maybe both.
|
||||
|
||||
In the first case, create the `.lproj` folder in the model root folder and add the translated medias inside. Then use the method by passing only the first parameters, the code.
|
||||
|
||||
In the other two cases, you'll need to specify also the second argument (the translations to be added to `pass.strings` file, which will be added later).
|
||||
|
||||
**Arguments**:
|
||||
|
||||
| Key | Type | Description | Optional | Default Value |
|
||||
|-----|------|-------------|----------|:-------------:|
|
||||
| lang | String | The ISO-3166-1 language code | false | -
|
||||
| options | Object | Translations in format PLACEHOLDER : TRANSLATED-VALUE. | true | undefined \| { }
|
||||
|
||||
**Example**:
|
||||
|
||||
```javascript
|
||||
pass
|
||||
.localize("it", {
|
||||
"EVENT": "Evento",
|
||||
"LOCATION": "Posizione"
|
||||
})
|
||||
.localize("de", {
|
||||
"EVENT": "Ereignis",
|
||||
"LOCATION": "Ort"
|
||||
})
|
||||
.localize("en")
|
||||
```
|
||||
|
||||
<br><br>
|
||||
___
|
||||
|
||||
**Setting barcodes**:
|
||||
___
|
||||
|
||||
<a name="method:barcode">
|
||||
#### .barcode()
|
||||
</a>
|
||||
|
||||
```javascript
|
||||
pass.barcode(data);
|
||||
```
|
||||
|
||||
**Returns**:
|
||||
|
||||
`Improved Object<Pass> (this with some "private" methods available to be called under aliases, as below)`
|
||||
|
||||
**Description**:
|
||||
|
||||
Each object in `data` will be filtered against a schema ([Apple reference](https://apple.co/2myAbst)) validation and used if correctly formed.
|
||||
|
||||
If the argument is an Object, it will be treated as one-element Array.
|
||||
|
||||
If the argument is a String or an Object with `format` parameter missing, but `message` available, the structure will be **autogenerated** complete of all the fallbacks (4 dictionaries).
|
||||
|
||||
To support versions prior to iOS 9, `barcode` key is automatically supported as the first valid value of the provided (or generated) barcode. To change the key, see below.
|
||||
|
||||
**Arguments**:
|
||||
|
||||
| Key | Type | Description | Optional | Default Value |
|
||||
|-----|------|-------------|----------|:-------------:|
|
||||
| data | String \| Array\<Object> \| Object | Data to be used in the barcode | false | -
|
||||
|
||||
**Examples**:
|
||||
|
||||
```javascript
|
||||
pass.barcode("11424771526");
|
||||
|
||||
// or
|
||||
|
||||
pass.barcode({
|
||||
message: "11424771526",
|
||||
format: "PKBarcodeFormatCode128"
|
||||
altText: "11424771526"
|
||||
});
|
||||
|
||||
// or
|
||||
|
||||
pass.barcode([{
|
||||
message: "11424771526",
|
||||
format: "PKBarcodeFormatCode128"
|
||||
altText: "11424771526"
|
||||
}, {
|
||||
message: "11424771526",
|
||||
format: "PKBarcodeFormatQR"
|
||||
altText: "11424771526"
|
||||
}, {
|
||||
message: "11424771526",
|
||||
format: "PKBarcodeFormatPDF417"
|
||||
altText: "11424771526"
|
||||
}]);
|
||||
```
|
||||
|
||||
**See**: [PassKit Package Format Reference # Barcode Dictionary](https://apple.co/2myAbst)
|
||||
<br>
|
||||
<a name="method:bBackward">
|
||||
#### .barcode().backward()
|
||||
</a>
|
||||
|
||||
```javascript
|
||||
pass.barcode(data).backward(format);
|
||||
```
|
||||
|
||||
**Returns**:
|
||||
|
||||
`Object<Pass> (this)`
|
||||
|
||||
**Description**:
|
||||
|
||||
Will let you choose the format to be used in barcode property as backward compatibility.
|
||||
Also will only work if `data` is provided to `barcode()` method and will fail if the selected format is not found among barcodes dictionaries array.
|
||||
|
||||
**Arguments**:
|
||||
|
||||
| Key | Type | Description | Optional | Default Value |
|
||||
|-----|------|-------------|----------|:-------------:|
|
||||
| format | String | Format to be used. Must be one of these types: *PKBarcodeFormatQR*, *PKBarcodeFormatPDF417*, *PKBarcodeFormatAztec* | false | -
|
||||
|
||||
**Example**:
|
||||
|
||||
```javascript
|
||||
// Based on the previous example
|
||||
pass
|
||||
.barcode(...)
|
||||
.backward("PKBarcodeFormatQR");
|
||||
|
||||
// This won't set the property since not found.
|
||||
pass
|
||||
.barcode(...)
|
||||
.backward("PKBarcodeFormatAztec");
|
||||
```
|
||||
|
||||
<br>
|
||||
<a name="method:bAutocomplete">
|
||||
#### .barcode().autocomplete()
|
||||
</a>
|
||||
|
||||
```javascript
|
||||
pass.barcode(data).autocomplete();
|
||||
```
|
||||
|
||||
**Returns**:
|
||||
|
||||
`Improved Object<Pass> ("this" with backward() support and length prop. reporting how many structs have been added).`
|
||||
|
||||
**Description**:
|
||||
|
||||
Will generate all the barcodes fallback starting from the first dictionary in `barcodes`.
|
||||
|
||||
<br><br>
|
||||
___
|
||||
|
||||
**Setting expiration / void the pass**:
|
||||
___
|
||||
|
||||
<a name="method:expiration">
|
||||
#### .expiration()
|
||||
</a>
|
||||
|
||||
```javascript
|
||||
pass.expiration(date [, format]);
|
||||
```
|
||||
|
||||
**Returns**:
|
||||
|
||||
`Object<Pass> (this)`
|
||||
|
||||
**Description**:
|
||||
|
||||
It sets the date of expiration to the passed argument. The date will be automatically parsed in order in the following formats:
|
||||
|
||||
* **MM-DD-YYYY hh:mm:ss**,
|
||||
* **DD-MM-YYYY hh:mm:ss**.
|
||||
|
||||
Otherwise you can specify a personal format to use.
|
||||
|
||||
Seconds are not optionals.
|
||||
If the parsing fails, the error will be emitted only in debug mode and the property won't be set.
|
||||
|
||||
**Arguments**:
|
||||
|
||||
| Key | Type | Description | Optional | Default Value |
|
||||
|-----|------|-------------|----------|:-------------:|
|
||||
| date | String/date | The date on which the pass will expire | false | -
|
||||
| format | String | A custom format to be used to parse the date | true | undefined
|
||||
|
||||
<a name="method:void">
|
||||
#### .void()
|
||||
</a>
|
||||
```javascript
|
||||
pass.void();
|
||||
```
|
||||
|
||||
**Returns**:
|
||||
|
||||
`Object<Pass> (this)`
|
||||
|
||||
**Description**:
|
||||
|
||||
Sets directly the pass as voided (void: true).
|
||||
|
||||
<br><br>
|
||||
___
|
||||
|
||||
**Setting relevance**:
|
||||
___
|
||||
|
||||
<a name="method:relevance">
|
||||
#### .relevance()
|
||||
</a>
|
||||
|
||||
```javascript
|
||||
pass.relevance(key, value [, relevanceDateFormat]);
|
||||
```
|
||||
|
||||
**Returns**:
|
||||
|
||||
`Improved Object<Pass> (this with length property)`
|
||||
|
||||
**Description**:
|
||||
|
||||
It sets the relevance key in the pass among four: **beacons**, **locations**, **relevantDate** and **maxDistance**.
|
||||
See [Apple Documentation dedicated page](https://apple.co/2QiE9Ds) for more.
|
||||
|
||||
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 *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.
|
||||
|
||||
|
||||
**Arguments**:
|
||||
|
||||
| Key | Type | Description | Optional | Default Value |
|
||||
|-----|------|-------------|----------|:-------------:|
|
||||
| key | String | The relevance key to be set, among **beacons**, **locations**, **relevantDate** and **maxDistance** | false | -
|
||||
| value | String \| Number \| Array\<Object> | Type depends on the key. Please refer to the description above for more details | false | -
|
||||
| relevanceDateFormat | String | Custom date format. Will be only used when using `relevanceDate` key | true | undefined
|
||||
|
||||
**Example**:
|
||||
|
||||
```javascript
|
||||
pass.relevance("location", [{
|
||||
longitude: "73.2943532945212",
|
||||
latitude: "-42.3088613015625",
|
||||
]);
|
||||
|
||||
pass.relevance("maxDistance", 150);
|
||||
|
||||
// DD-MM-YYYY -> April, 10th 2021
|
||||
pass.relevance("relevantDate", "10/04/2021", "DD-MM-YYYY");
|
||||
|
||||
// MM-DD-YYYY -> October, 4th 2021
|
||||
pass.relevance("relevantDate", "10/04/2021");
|
||||
```
|
||||
|
||||
<br><br>
|
||||
___
|
||||
|
||||
**NFC Support**:
|
||||
___
|
||||
|
||||
<a name="method:nfc">
|
||||
#### .nfc()
|
||||
</a>
|
||||
|
||||
```javascript
|
||||
pass.nfc([data, ...])
|
||||
```
|
||||
|
||||
**Returns**:
|
||||
|
||||
`Object<Pass> (this)`
|
||||
|
||||
**Description**:
|
||||
|
||||
It sets the property for nfc dictionary.
|
||||
An Object as argument will be treated as one-element array.
|
||||
|
||||
>*Notice*: **I had the possibility to test in no way this pass feature and, therefore, the implementation. If you need it and this won't work, feel free to contact me and we will investigate together 😄**
|
||||
|
||||
**Arguments**:
|
||||
|
||||
| Key | Type | Description | Optional | Default Value |
|
||||
|-----|------|-------------|----------|:-------------:|
|
||||
| data | Array\<Object> \| Object | The data regarding to be used for nfc | false | -
|
||||
|
||||
**See**: [PassKit Package Format Reference # NFC](https://apple.co/2wTxiaC)
|
||||
<br>
|
||||
<br>
|
||||
___
|
||||
|
||||
**Setting Pass Structure Keys (primaryFields, secondaryFields, ...)**:
|
||||
___
|
||||
|
||||
Unlike method-set properties or overrides, to set fields inside areas (*primaryFields*, *secondaryFields*, *auxiliaryFields*, *headerFields*, *backFields*), this library make available a dedicated array-like interface, with just the essential methods: `push()` and `pop()`.
|
||||
|
||||
<br>
|
||||
|
||||
<a name="prop:fields-push">
|
||||
#### <field>.push()
|
||||
</a>
|
||||
|
||||
```javascript
|
||||
pass.<field>.push(...fields);
|
||||
```
|
||||
|
||||
**Returns**:
|
||||
|
||||
`Number - the amount of valid fields added to area`
|
||||
|
||||
**Description**:
|
||||
|
||||
An argument of type "object" is considered as one-element array.
|
||||
Fields are filtered against a schema.
|
||||
|
||||
**Arguments**:
|
||||
|
||||
| Key | Type | Description | Optional | Default Value |
|
||||
|-----|------|-------------|----------|:-------------:|
|
||||
| fields | Array\<Object> \| Object | Field to be added to an area | false | -
|
||||
|
||||
**Examples**:
|
||||
|
||||
```javascript
|
||||
pass.headerFields.push({
|
||||
"key": "header1",
|
||||
"label": "Data",
|
||||
"value": "25 mag",
|
||||
"textAlignment": "PKTextAlignmentCenter"
|
||||
}, {
|
||||
"key": "header2",
|
||||
"label": "Volo",
|
||||
"value": "EZY997",
|
||||
"textAlignment": "PKTextAlignmentCenter"
|
||||
});
|
||||
|
||||
pass.primaryFields.push({
|
||||
key: "IATA-source",
|
||||
value: "NAP",
|
||||
label: "Napoli",
|
||||
textAlignment: "PKTextAlignmentLeft"
|
||||
}, {
|
||||
key: "IATA-destination",
|
||||
value: "VCE",
|
||||
label: "Venezia Marco Polo",
|
||||
textAlignment: "PKTextAlignmentRight"
|
||||
});
|
||||
```
|
||||
|
||||
**See**: [Passkit Package Format Reference # Field Dictionary Keys](https://apple.co/2NuDrUM)
|
||||
|
||||
<br>
|
||||
|
||||
<a name="prop:fields-pop">
|
||||
#### <field>.pop()
|
||||
</a>
|
||||
|
||||
```javascript
|
||||
pass.<field>.pop(amount);
|
||||
```
|
||||
|
||||
**Returns**:
|
||||
|
||||
`Number - the amount of fields removed.`
|
||||
|
||||
**Description**:
|
||||
|
||||
This method is a mix between `Array.prototype.pop` and `Array.prototype.slice`.
|
||||
In fact, passing this method an amount as parameter, will make it act as `slice`. Otherwise it will act as `pop`.
|
||||
|
||||
**Arguments**:
|
||||
|
||||
| Key | Type | Description | Optional | Default Value |
|
||||
|-----|------|-------------|----------|:-------------:|
|
||||
| amount | Number | Amount of fields to be removed from that area | true | -1
|
||||
|
||||
**Examples**:
|
||||
|
||||
```javascript
|
||||
pass.secondaryFields.pop(); // last element is popped out.
|
||||
|
||||
pass.backFields.pop(5); // last five elements are popped out.
|
||||
```
|
||||
|
||||
<br>
|
||||
|
||||
<a name="prop:transitType">
|
||||
#### .transitType
|
||||
</a>
|
||||
|
||||
```javascript
|
||||
pass.transitType = "PKTransitTypeAir";
|
||||
```
|
||||
|
||||
**Description**:
|
||||
|
||||
Since this property belongs to the "Structure Keys" but is not an "array of field dictionaries" like the other keys on the same level, a setter (and obv. also a getter) got included in this package to check it against a schema (which is like, "is a string and contains one of the following values: **PKTransitTypeAir**, **PKTransitTypeBoat**, **PKTransitTypeBus**, **PKTransitTypeGeneric**, **PKTransitTypeTrain**", as described in Passkit Package Format Reference).
|
||||
|
||||
<br><br>
|
||||
___
|
||||
|
||||
**Generating the compiled Pass**
|
||||
___
|
||||
|
||||
Generating the pass is the last step of the process (before enjoying 🎉).
|
||||
Since the file format is `.pkpass` (which is a `.zip` file with changed MIME), this method will return a `Stream`, which can be used to be piped to a webserver response or to be written in the server.
|
||||
As you can see in [examples folder](/examples), to send a .pkpass file, a basic webserver uses MIME-type `application/vnd.apple.pkpass`.
|
||||
|
||||
<br>
|
||||
|
||||
<a name="method:generate">
|
||||
#### .generate()
|
||||
</a>
|
||||
|
||||
```javascript
|
||||
pass.generate();
|
||||
```
|
||||
|
||||
**Returns**: `Promise`
|
||||
|
||||
**Description**:
|
||||
|
||||
The returned Promise will contain a stream or an error.
|
||||
|
||||
**Examples**:
|
||||
|
||||
```javascript
|
||||
...
|
||||
pass.generate()
|
||||
.then(stream => {
|
||||
doSomethingWithPassStream();
|
||||
})
|
||||
.catch(error => {
|
||||
doSomethingWithThrownError();
|
||||
});
|
||||
```
|
||||
___
|
||||
|
||||
Thanks for using this library. ❤️ Every contribution is welcome.
|
||||
120
README.md
Normal file
120
README.md
Normal file
@@ -0,0 +1,120 @@
|
||||
# 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.
|
||||
|
||||
|
||||
### Installation
|
||||
This generator has two sides: application and model creation.
|
||||
|
||||
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.
|
||||
|
||||
```sh
|
||||
$ npm install passkit-generator --save
|
||||
```
|
||||
|
||||
To see the API Reference, please refer to [API document](./API.md).
|
||||
Created under Node.js v10.8.0.
|
||||
|
||||
## Get Started
|
||||
|
||||
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)).
|
||||
|
||||
Following to this suggestion, each model is required to have a **.pass** extension (as suggested by Apple).
|
||||
|
||||
```bash
|
||||
$ cd yourProjectDir;
|
||||
$ mkdir passModels && mkdir $_/myFirstModel.pass && cd $_;
|
||||
```
|
||||
|
||||
Follow the [Apple Developer documentation](https://apple.co/2wuJLC1) (_Package Structure_) to build a correct pass model. The **icon is required** in order to make the pass work. *Manifest.json* and *signature* will be automatically ignored from the model and generated in runtime.
|
||||
|
||||
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.
|
||||
|
||||
##### Pass.json
|
||||
|
||||
Create a `pass.json` by taking example from examples folder models or the one provided by Apple for the [first tutorial](https://apple.co/2NA2nus) and fill it with the basic informations, that is `teamIdentifier`, `passTypeIdentifier` and all the other basic keys like pass type. Please refer to [Top-Level Keys/Standard Keys](https://apple.co/2PRfSnu) and [Top-Level Keys/Style Keys](https://apple.co/2wzyL5J).
|
||||
|
||||
```javascript
|
||||
{
|
||||
"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": {}
|
||||
}
|
||||
```
|
||||
|
||||
##### Certificates
|
||||
> Requirements: OpenSSL,
|
||||
|
||||
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.
|
||||
You'll need the following three elements:
|
||||
|
||||
* Apple WWDR (_Worldwide Developer Relationship_) certificate
|
||||
* Signer certificate
|
||||
* Signer key
|
||||
|
||||
While WWDR can be obtained from [Apple PKI Portal](https://www.apple.com/certificateauthority/), to get the `signer key` and the `certificate`, you'll have to get first a `Certificate Signing Request` (`.certSigningRequest` file) from your Apple Developers Portal page, at [Pass Types Identifiers](https://developer.apple.com/account/ios/identifier/passTypeId) (open it, it worth the pain).
|
||||
|
||||
1. Create a new pass type identifier and provide it with a Name and a reverse-domain bundle id (starting with "pass."). You will put this identifier as value for `passTypeIdentifier` in `pass.json` file.
|
||||
2. Confirm and register the new identifier.
|
||||
3. Go back to the pass type identifiers, click on your new pass id and Edit it.
|
||||
4. Click "Create Certificate" button and follow the instructions until you won't download a certificate like `pass.cer`.
|
||||
5. Open the downloaded certificate. Go in "Certificates" on left in macOS Keychain access and `right-click > Export "\<certname\>"`. Choose a password (and write it down) and you will get a PKCS#12 file (`.p12`).
|
||||
6. Open terminal, place where you want to save the files and insert the following commands changing the contents between angular brackets. You'll have to choose a secret passphrase (and write it down) that you'll use also in the application.
|
||||
|
||||
```sh
|
||||
$ mkdir "certs" && cd $_
|
||||
$ openssl pkcs12 -in <cert-name>.p12 -clcerts -nokeys -out signerCert.pem -passin pass:<your-password>
|
||||
$ openssl pkcs12 -in <cert-name>.p12 -nocerts -out signerKey.pem -passin pass:<your-password> -passout pass:<secret-passphrase>
|
||||
```
|
||||
7. Execute step 5 also for the WWDR certificate (`.cer`) you downloaded from Apple PKI portal (default name: *AppleWWDRCA.cer*) but instead exporting it as PKCS#12 (`.p12` - you'll also be unable to do that), export it as PEM (`.pem`) file.
|
||||
|
||||
|
||||
## Usage example
|
||||
|
||||
```javascript
|
||||
const Passkit = require("passkit-generator");
|
||||
|
||||
let pass = new Passkit.Pass({
|
||||
model: "./passModels/myFirstModel",
|
||||
certificates: {
|
||||
wwdr: "./certs/wwdr.pem",
|
||||
signerCert: "./certs/signercert.pem",
|
||||
signerKey: {
|
||||
keyFile: "./certs/signerkey.pem",
|
||||
passphrase: "123456"
|
||||
}
|
||||
},
|
||||
overrides: {
|
||||
// keys to be added or overridden
|
||||
serialNumber: "AAGH44625236dddaffbda"
|
||||
},
|
||||
// if true, existing keys added through methods get overwritten
|
||||
// pushed in queue otherwise.
|
||||
shouldOverwrite: true
|
||||
});
|
||||
|
||||
// Adding some settings to be written inside pass.json
|
||||
pass.localize("en", { ... });
|
||||
pass.barcode("12345");
|
||||
|
||||
// Generate the stream, which gets returned through a Promise
|
||||
pass.generate()
|
||||
.then(stream => {
|
||||
doSomethingWithTheStream(stream);
|
||||
})
|
||||
.catch(err => {
|
||||
doSomethingWithTheError(err);
|
||||
});
|
||||
```
|
||||
|
||||
## 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).
|
||||
Be sure to not include the certificates if you publish your project open to everybody.
|
||||
Any contribution is welcome ❤️
|
||||
17
examples/Examples.md
Normal file
17
examples/Examples.md
Normal file
@@ -0,0 +1,17 @@
|
||||
# Examples
|
||||
|
||||
This is examples folder. Each example is linked to webserver.js, which **requires express.js** to run.
|
||||
|
||||
Since just examples, Express.js was not inserted as dipendency. Therefore install it to test.
|
||||
|
||||
```sh
|
||||
git clone https://github.com/alexandercerutti/passkit-generator.git;
|
||||
npm install;
|
||||
npm install express;
|
||||
cd examples;
|
||||
node <the-example-you-want-to-execute>.js
|
||||
```
|
||||
|
||||
___
|
||||
|
||||
Every contribution is really appreciated. ❤️ Thank you!
|
||||
@@ -1,6 +1,7 @@
|
||||
/*
|
||||
* Generic webserver instance for the examples
|
||||
* @Author Alexander P. Cerutti
|
||||
* Requires express to run
|
||||
*/
|
||||
|
||||
const express = require("express");
|
||||
|
||||
Reference in New Issue
Block a user