Giter Club home page Giter Club logo

passkit-generator's Introduction



Passkit-generator logo for light mode

Simple Node.js interface to generate customized Apple Wallet Passes for iOS and WatchOS.


Financial Contributors on Open Collective


Architecture

This library was created with a specific architecture in mind: application and model (as preprocessed entity), to split as much as possible static objects (such as logo, background, icon, etc.) from dynamic ones (translations, barcodes, serialNumber, ...), while keeping an eye on the different possible execution contexts.

Pass creation and population might not fully happen in runtime. This library allows to create a pass from scratch, specify a folder model (template) or specify a set of buffers. In the last two cases, both should contain all the objects needed (static medias) and structure to make a pass work.

Whenever adding files, through scratch, template or buffer, these will be read and pushed as they are in the resulting .zip file, while dynamic data will be patched (pass.json with props) or generated in runtime (manifest.json, signature and translation files).

Installation

$ npm install passkit-generator --save

API Documentation

This package comes with an API Documentation Reference, available in wiki, that makes available a series of methods to create and customize passes.


Looking for the previous major version?

Check the v2 tag. That tag is kept for reference only.


Coming from the previous major version?

Look at the Migration Guide.


Integrating Apple Wallet Web services?

Give a look at another library I made: Passkit Webservice Toolkit and its integrations!


Getting Started

Model

Assuming that you don't have a model yet, the first thing you'll have to do, is creating one. A model contains all the basic pass data that compose the Pass identity. These data can be files (icon, thumbnails, ...), or pieces of information to be written in pass.json (Pass type identifier, Team Identifier, colors, ...) and whatever you know that likely won't be customized on runtime.

When starting from zero, the best suggested solution is to use a Template (folder) to start with, as it will allow an easier access to all the files and data. Nothing will prevent you using a buffer model or creating a pass from scratch, but they are meant for an advanced usage or different contexts (e.g. running a cloud function might require a scratch model for faster startup, without storing the model in a "data bucket").

Let's suppose you have a file model.zip stored somewhere: you unzip it in runtime and then get the access to its files as buffers. Those buffers should be available for the rest of your application run-time and you shouldn't be in need to read them every time you are going to create a pass.

To maintain a pass model available during the run-time, a PKPass instance can be created from whatever source, and then used as a template through PKPass.from.

Using the .pass extension is a best practice, showing that the directory is a pass package. (Build your first pass - Apple Developer Portal).

Following to this best practice, the package is set to require each folder-model to have a .pass extension.

If omitted in the configuration (as in Usage Example below), it will be forcefully added, possibly resulting in a folder reading error, if your model folder doesn't have it.


Model creation can be performed both manually or with the auxiliary of a web tool I developed, Passkit Visual Designer, which will let you design your model through a neat user interface. It will output a .zip file that you can decompress and use as source.


You can follow Create the Directory and add Files for the Pass at Apple Developer to build a correct pass model. The icon is required in order to make the pass work. Omitting an icon resolution, might make a pass work on a device (e.g. Mac) but not on another (e.g. iPhone). 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 Localizing Passes in the wiki API documentation.

To include a file that belongs to an .lproj folder in buffers, you'll just have to name a key like en.lproj/thumbnail.png.

Pass.json

Create a pass.json by taking example from examples folder models or the one provided by Apple for the first tutorial and fill it with the basic informations, that are teamIdentifier, passTypeIdentifier and all the other basic keys like pass type. Please refer to Pass interface documentation on Apple Developers.

{
	"formatVersion": 1,
	"passTypeIdentifier": "pass.<bundle id>",
	"teamIdentifier": "<your team identifier>",
	"organizationName": "<your organization name>",
	"description": "A localizable description of your pass. To do so, put here a placeholder.",
	"boardingPass": {}
}

Certificates

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. We'll use OpenSSL to complete our work (or to do it entirely, if only on terminal), so be sure to have it installed.

Follow the FULL GUIDE in wiki to get all the files you need to proceed.


Usage Examples

Importing:

/** CommonJS **/
const { PKPass } = require("passkit-generator");

/** Typescript **/
import { PKPass } from "passkit-generator";

/** ESM **/
import passkit from "passkit-generator";
const PKPass = passkit.PKPass;

Folder Model

try {
	/** Each, but last, can be either a string or a Buffer. See API Documentation for more */
	const { wwdr, signerCert, signerKey, signerKeyPassphrase } = getCertificatesContentsSomehow();

	const pass = await PKPass.from({
		/**
		 * Note: .pass extension is enforced when reading a
		 * model from FS, even if not specified here below
		 */
		model: "./passModels/myFirstModel.pass",
		certificates: {
			wwdr,
			signerCert,
			signerKey,
			signerKeyPassphrase
		},
	}, {
		// keys to be added or overridden
		serialNumber: "AAGH44625236dddaffbda"
	});

	// Adding some settings to be written inside pass.json
	pass.localize("en", { ... });
	pass.setBarcodes("36478105430"); // Random value

	// Generate the stream .pkpass file stream
	const stream = pass.getAsStream();
	doSomethingWithTheStream(stream);

	// or

	const buffer = pass.getAsBuffer();
	doSomethingWithTheBuffer(buffer);
} catch (err) {
	doSomethingWithTheError(err);
}

Buffer Model

try {
	/** Each, but last, can be either a string or a Buffer. See API Documentation for more */
	const { wwdr, signerCert, signerKey, signerKeyPassphrase } = getCertificatesContentsSomehow();

	const pass = new PKPass({
		"thumbnail.png": Buffer.from([ ... ]),
		"icon.png": Buffer.from([ ... ]),
		"pass.json": Buffer.from([ ... ]),
		"it.lproj/pass.strings": Buffer.from([ ... ])
	},
	{
		wwdr,
		signerCert,
		signerKey,
		signerKeyPassphrase,
	},
	{
		// keys to be added or overridden
		serialNumber: "AAGH44625236dddaffbda",
	});

	// Adding some settings to be written inside pass.json
	pass.localize("en", { ... });
	pass.setBarcodes("36478105430"); // Random value

	// Generate the stream .pkpass file stream
	const stream = pass.getAsStream();
	doSomethingWithTheStream(stream);

	// or

	const buffer = pass.getAsBuffer();
	doSomethingWithTheBuffer(buffer);
} catch (err) {
	doSomethingWithTheError(err);
}

For more complex usage examples, please refer to examples folder.


Other

If you used this package in any of your projects, feel free to open a topic in issues to tell me and include a project description or link (for companies). ๐Ÿ˜Š You'll make me feel like my time hasn't been wasted, even if it had not anyway because I learnt and keep learning a lot of things by creating this.

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 and to all the contributors.

Any contribution, is welcome. Made with โค๏ธ in Italy.


Contributors

A big thanks to all the people that contributed to improve this package. Any contribution is welcome. Do you have an idea to make this improve or something to say? Open a topic in the issues and we'll discuss together! Thank you โค๏ธ Also a big big big big thank you to all the financial contributors, which help me maintain the development of this package โค๏ธ!

Code Contributors

Financial Contributors

Become a financial contributor and help us sustain our community. [Contribute]

Individuals

Organizations

Support this project with your organization. Your logo will show up here with a link to your website. [Contribute]

passkit-generator's People

Contributors

aaliakseyenka avatar abdelrahmanhafez avatar alexandercerutti avatar billytrend avatar buren avatar ianbale avatar jennysharps avatar jensspanier avatar kristofkekesi avatar majuss avatar neogucky avatar nuts-n-bits avatar saim-khan1 avatar songkeys avatar wavemeup avatar zach-aries avatar zhenwenc avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

passkit-generator's Issues

Notifications not working when using "non-Mac-Steps"

I am having an issue getting notifications when using the steps in this link...

non-macOS-steps

Passes should be able to receive notifications if a device id and push token were generated when they first downloaded their pass (this is logic we have in our application to handle on the server and storage/ db level)

I have confirmed that if I update a pass in our database and then do a pull to refresh on a pass, it updates the data so I know it is not my webhooks that are a problem. The webhooks were implemented using these docs...

PassKit Web Service Reference

I continue to receive notification from apple's notification server that they have received my request but the devices registered never receive a notification

I think I have an idea why. I have read that when creating the certificate for a pass, you can select it to allow notification. I think that the instructions in the "non Mac steps" no not seem to have a way to make the certificate receive notifications. Is this correct?

I think in order to receive notifications I would have to re-create the certificate using Apple's developer dashboard, after creating the pass type id and then creating a production certificate to download

Please let me know if this is something you know to be true or if the steps in the "non Mac steps" somehow create a certificate that allows for push notifications

Thanks

Can't generate boarding pass

Hi,

I've hit a problem trying to generate a boarding pass.

I have managed to generate a sample event type pass with no problem at all. It's just the boarding pass that is giving me problems.

I'm seeing this error:

Schema validation failed due to error: "transitType" is not allowed +0ms

I do have transitType in the boadingPass object as you can see in my JSON

{
  "formatVersion": 1,
  "organizationName": "Hazardous Frog LTD",
  "passTypeIdentifier": "pass.com.hazardousfrog.xxxxx",
  "serialNumber": "placeholder",
  "teamIdentifier": "AAAAAAAAAAA",
  "description": "HF Rail Ticket",
  "relevantDate": "2019-12-08T13:00-08:00",
  "locations": [
    {
      "longitude": -122.3748889,
      "latitude": 37.6189722
    },
    {
      "longitude": -122.03118,
      "latitude": 37.33182
    }
  ],
  "barcodes": [{
    "message": "06FB3SHXG3Y00R1JTETQMAUZYHXLALMCRDZPWTFPFWKKBDSZSQEQTVYWSZZWWWNXSSUAXCDJDQTZMGODMFIRJCEWEKACPBNOUGZCDRESKGTKFTZNYDURPFILJFCVAHTQFHELJCXPYBCJJIIJPIRCVECCLQWFMGROBHRGFIRKPNJVKOOYCXTHRAIFSFXQQUVCARZROCACWBEGEWUVFKTDKNSQCACSGWUDBVDHMJMGH",
    "format": "PKBarcodeFormatAztec",
    "messageEncoding": "iso-8859-1"
  }],
  "logoText": "...Logo...",
  "foregroundColor": "rgb(0, 0, 0)",
  "backgroundColor": "rgb(255, 248, 242)",
  "boardingPass": {
    "transitType": "PKTransitTypeTrain",
    "headerFields": [
      {
        "label": "journey",
        "key": "journey",
        "value": "Field E0001",
        "textAlignment": "PKTextAlignmentLeft"
      }
    ],
    "primaryFields": [
      {
        "key": "depart",
        "label": "depart",
        "value": "27/11/2019",
        "textAlignment": "PKTextAlignmentLeft"
      },
      {
        "key": "arrive",
        "label": "arrive",
        "value": "27/11/2019",
        "textAlignment": "PKTextAlignmentRight"
      }
    ],
    "secondaryFields": [
      {
        "key": "status",
        "label": "status",
        "value": "ADULT",
        "textAlignment": "PKTextAlignmentLeft"
      },
      {
        "key": "validuntil",
        "label": "valid until",
        "value": "27/11/2019",
        "textAlignment": "PKTextAlignmentRight"
      }
    ],
    "auxiliaryFields": [
      {
        "key": "tickettype",
        "label": "ticket type",
        "value": "SOS",
        "textAlignment": "PKTextAlignmentLeft"
      },
      {
        "key": "route",
        "label": "route",
        "value": "Any Permitted",
        "textAlignment": "PKTextAlignmentRight"
      }
    ],
    "backFields": [
      {
        "key": "itinerary",
        "label": "itinerary",
        "value": "itinerary goes here..."
      },
      {
        "key": "freeinformation",
        "value": "Field E0044"
      },
      {
        "key": "contactinformation",
        "label": "Contact Details",
        "value": "Field E0022"
      }
    ]
  }
}

if I omit transitTyoe (as a test) I get this error instead:

UnhandledPromiseRejectionWarning: Error: Error: Cannot proceed with pass creation. transitType field is required for boardingPasses.

I'm using v 1.6.4 with Node 8.10.0

Do you have any idea what I am doing wrong here?

Add Buffer Model to README

Love this project! Super useful in the professional setting I'm working in :) The only thing that would have been helpful would be to have an example of the Buffer Model in the README or even the API docs as it took me a bit to find it in the Migration Guide! Again, thank you for all your work on this!

Question: how to open/handle the pkpass file in my ionic cordova app?

Hi there, I got the entire Node js generate service to work. When calling the url and it generates the .pkpass file. On a desktop it just downloads the file, on Android too .. and with a pkpass file app it will open automatically. But somehow in my iOS app (built in ionic cordova), when calling the url it jumps into the safari browser opening the generate url, but then does not download / open the file.
I've been searching the web for any answers on how to parse/handle the pkpass file in my ionic cordova project, but cannot find anything useful. Perhaps you have any thoughts? What should I be doing here?
Thanks!

Error validating model even though it is valid

I am getting the following error:

"Provided model ( ) 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."

After investigating a bit, it seems that the logic in pass.js is as follows:

if (!noDynList.length || !noDynList.some(f => f.toLowerCase().includes("icon"))
    || !remoteFilesList.some(f => f.toLowerCase().includes("icon"))) {
    let eMessage = formatError("MODEL_UNINITIALIZED", path.parse(this.model).name);
    throw new Error(eMessage);
}

This requires me to have an icon both in the noDynList AND the remoteFilesList; surely we only need 1 or the other rather than both?

When I change the code to this it works as I would expect, and I can open the generated pass on my phone:

if (![...noDynList, ...remoteFilesList].some(f => f.toLowerCase().includes("icon"))) {
    let eMessage = formatError("MODEL_UNINITIALIZED", path.parse(this.model).name);
    throw new Error(eMessage);
}

Is my understanding of the expected behavior here wrong? Is the icon actually needed in both lists for some reason?

NodeJS newbie: Can't get the Pass to be generated

Sorry for leaving a comment in the issue section, but I am not sure how to reach out otherwise.
I am new to NodeJS, but felt like this could be the best/easiest way to setup a web service for generating a Passbook Pass for an iOS (built in ionic) app that I work on.
I also apologise for the basic questions. I am not very good with this (yet).

I followed your documentation and all seems well. Got the certificates etc. sorted.
When I run your "usage example" straight out of the box (with of course my certificates and passphrase set), I get the error from node: pass is not defined.
I see that you define "let examplePass", but then run "pass.generate()".
Should it not be "let pass = new Pass({ ..." ?

When I change it to "let pass = new Pass " it does run, but I am not sure it actually generates anything.
I am testing it locally atm.

Since I am completely new to NodeJS (but having Javascript experience) I am not entirely sure how to run this module correctly so that it generates a pass that I can open from the app.

I am not too worried about the look/feel of the pass yet. Just wanted to test if this works.
Hope you can help a little!

Appreciate the effort you put into developing this module! By far the best documented version I found so far.
Cheers!

index.d.ts:67 and 74 have bad parameter types

line 67: beacons(...data: Schema.Beacon[] | null): this
line 74: locations(...data: Schema.Location[] | null): this

TSC complains, rightfully, that a rest parameter must be of array type. This seems fixable just by removing the | null part.

the commit I'm referencing to is 681d9d1.

BTW, thanks for writing this library :]

Error: Cannot read public key. OID is not RSA.

hi there
after executing the commands:
$ 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>
node barcode.js
I'm getting the error:
Error: Error: Cannot read public key. OID is not RSA. at _parseCertificates.then.catch (/Users/marcelocecin/node_modules/passkit-generator/src/pass.js:64:11)

Invalid PEM formatted message

Hi !

I'm trying to use your lib but I'm not able to get it working.

I try to run a basic example

const { Pass } = require("passkit-generator");
 
let pass = new Pass({
    model: "./passModels/myFirstModel",
    certificates: {
        wwdr: "./certs/wwdr.pem",
        signerCert: "./certs/signercert.pem",
        signerKey: {
            keyFile: "./certs/signerkey.pem",
            passphrase: "pass"
        }
    }
});
 
// Adding some settings to be written inside pass.json
pass.localize("fr");
pass.barcode("36478105430"); // Random value
 
// Generate the stream, which gets returned through a Promise
pass.generate()
    .then(stream => {
        console.log(stream);
    })
    .catch(err => {
        console.log(err);
    });

I get the following error :

Error: Error: Invalid PEM formatted message.
at readCertificates.then.then.catch (/Users/aflalo/node_modules/passkit-generator/src/pass.js:68:11)

I tried to log the Certificate object created before readind :

{ _raw: { wwdr: './certs/wwdr.pem', signerCert: './certs/signercert.pem', signerKey: { keyFile: './certs/signerkey.pem', passphrase: 'pass' } } }

Any clue ? Thanks

Cannot receive notifications on pass content update

@figuerb @alexandercerutti Thanks for all the info.
I am facing a slightly different but relating to not getting notifications issue.

I have setup PK WebServices as per docs. Im able to update my pass Ie: Touch to pull on back of pass says "Updated just now" and shows the changes. But dont get notifications of changes.

In "Get Pass" api call I have this header
"Last-Modified": new Date().toUTCString() set.

On Get Serial function, I am returning in the body like below:

body: {
      serialNumbers: ["12312312", "123123"],
      lastUpdated : new Date().toUTCString()
}

Using Node APN for push
https://github.com/node-apn/node-apn

Created a token from Apple Dev portal. https://developer.apple.com/account/resources/authkeys/list

var apnProvider = new apn.Provider({
    token: {
      key: AuthKey_xxx.p8", // Path to the key p8 file
      keyId: "xxx", // The Key ID of the p8 file
      teamId: "nnn", // The Team ID of your Apple Developer Account
    },
    production: true,
  });

var notification = new apn.Notification();
notification.topic = passTypeIdentifier;
notification.payload = { };

I get this response:

{
    "sent": [
        {
            "device": "8cxxx4"
        }
    ],
    "failed": []
}

So Apple sent it successfully I dont get any notifications.
I have all fields with ChangeMessage set

{
    "key": "aux1",
    "label": "Aux1",
    "value": "Value",
    "row":0,
    "textAlignment": "PKTextAlignmentLeft",
    "changeMessage": "This changed to %@"
}

Now the logs call says there is an error in Get Serial function. Logs only show when there was an error, dont have any logs on success. Dont get any logs during device register, Pass Get or update.

Get serial #s task (for device xxx, pass type pass.com.xxx.xxx, last updated (null); with web service url https://xxx ) encountered error: Unexpected response code 502

"Get serial" call was getting / couldnt read "last updated (null)".
Am I missing some thing very obvious!

Originally posted by @Dicondur in #33 (comment)

Error on regex of type /(\$.[^ \n]*)/ in changeMessage field

I have a pass the respects the schema outlined on the Apple Developer website and which I can successfully create with ./signpass -p <file> and also successfully verify with ./signpass -v <file>

Yet still when I try to generate this pass after following all the steps in the README I get this error when I try to generate the pass.

Error: 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.
    at readFile.then.passStructBuffer (~/node_modules/passkit-generator/src/pass.js:135:15)

This even happens with some of the Sample passes from the Apple website (Tutorial), e.g. the BoardingPass.pass.

I tried looking into the code but I can not determine at which step or part of the JSON file it fails and also the error message is not very specific. Is there any chance you know where this comes from or how I could fix this or determine where the error comes from?

Use this server on lambda

Hi bumped into this repo today.. quickly setup and all working awesome stuff!.. Wondering what will it take to host this as a service on a AWS lambda? Where would you suggest will be agood place to start to look for? Thanks!

Deploying script on Heroku not working

Hey there! I got my tweaked example version of your script working just fine locally.. very happy about that! But when I deploy on Heroku (for real world testing) I keep getting this error

Cannot GET /gen/examplePass

Any ideas?

The pass could not be opened

This is more of a "what am I doing wrong" than an issue. I'm running this package on AWS lamdba and it works fine when I save the file to S3 (a typical filesystem). However when I use express, as the example has it, I get The pass could not be opened.

Running express locally in the examples directory gives me the same error. It seems that express is manipulating the data. One other thing I tried is using Apple's signpass program to make sure my pass was valid and that worked.

When I can get the pass to work, simply changing the .pkpass to .zip works. However when I download the .pkpass file from express, Mac OS does not like it.
screenshot 2019-07-14 at 8 43 57 PM

Let me know if I can provide any more additional information. Btw, thank you for making this! Once I get this working it will help me out a lot!

Pass localization not working after fields push

Hi,
I am setting the pass fields dynamically from code and then trying to localize the labels. I do not have lproj directory created as the media is still the same.
My pass.json has passtype as
generic : {}

I am setting values as

examplePass.primaryFields.push({
        "key" : "coupID",
        "label" : "CoupId_localized",
        "value" : "testid"
      });

Then localize as follows for french

examplePass.localize("fr", {
      "CoupId_localized": "Copon num_FR"
    });

examplePass.localize("en", {
      "CoupId_localized": "Copon num"
    });

The file gets dowloaded but its corrupted.

File not found error when following createPass example

I apologize if this issue seems simple but I've honestly spent hours trying to debug it.

I followed the getting started instructions and everything is working fine until I specify the path for the "model" required for createPass. I am currently using a relative path from the file (express route) in which I am calling createPass, i.e. "./passModels/Lollipop.pass" (I have verified that this relative path is not broken) , however this results in the error:

"Create Pass error: Error: Something went really bad in the pass initialization! Look at the log below this message. It should contain all the infos about the problem: Error: File Lollipop.pass not found."

What kind of path does createModel expect? Is it fine to use a path like this that is relative to the location it is being called from in my node project? If not, where in my project is the createPass actually looking and how should I fix this?

Any help would be much appreciated, this library is the only legit way that I have found to generate PassKit passes from my server. Thanks!

.pkpass file and ios simulator

Hello, i'm having some troubles, the .pkpass file is generated correctly, but i'm using ios simulator to test, so, when i drag the file to simulator, doesn't show nothing :(

Cannot generate passes in parallel

Reference #25

fieldsArray.js defined fieldsKeys outside of the class. This means they are shared across all class instances.

Whilst the data is populated for a single instance, the static function emptyUnique clears this data for all instances.

The symptoms of this are that it is impossible to generate multiple passes in parallel (using promises).

Node 14.13.1 package is broken

Hi

Package seems to be incompatible with latest version of node

TypeError: Cannot destructure property `readdir` of 'undefined' or 'null'.
    at Object.<anonymous> (~/node_modules/passkit-generator/src/parser.js:34:53)
    at Module._compile (module.js:653:30)
    at Object.Module._extensions..js (module.js:664:10)
    at Module.load (module.js:566:32)
    at tryModuleLoad (module.js:506:12)
    at Function.Module._load (module.js:498:3)
    at Module.require (module.js:597:17)
    at require (internal/module.js:11:18)
    at Object.<anonymous> (~/node_modules/passkit-generator/src/factory.js:9:18)
    at Module._compile (module.js:653:30)

Invalid stream generated

I have following pass structure in my code:
examplepass.pass (folder)

icon.png
[email protected]
logo.png
[email protected]
pass.json

keys (folder)

signerCert.pem
signerKey.pem
wwdr.pem

const Passkit = require("passkit-generator");
const fs = require('fs');
let pass = new Passkit.Pass({
model: "./examplepass",
certificates: {
wwdr: "./keys/wwdr.pem",
signerCert: "./keys/signerCert.pem",
signerKey: {
keyFile: "./keys/signerKey.pem",
passphrase: "mac001"
}
},
overrides: {},
shouldOverwrite: true
});
pass.generate()
.then(stream => {
var file = fs.createWriteStream("examplepass.pkpass")
stream.on('finish', () => {
console.log('done')
})
stream.on("error", function (error) {
console.error(error);
process.exit(1);
})
stream.pipe(file);
})
.catch(err => {
console.log("Error: " + err)
});

Everything is working fine and I am not getting any error. But when i try to open the pass it says unable to open the pass.

Same example structure, If I try with utility here then it is working fine and pass is created.

pass generate api stream is undefined

Hi,
I am getting undefined stream on using the following code. I dont see any error in my catch either. Please help as I am relatively new to this.
The stream is undefined.

app.get('/downloadpass', async (req, res, next) => {
 let examplePass = new Pass({
     model: "./passModels/Coupon",
     certificates: {
         wwdr: "./certs/wwdr.pem",
         signerCert: "./certs/signerCert.pem",
         signerKey: {
             keyFile: "./certs/passkey.pem",
             passphrase: "12345"
         }
     },
     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
 examplePass.barcode("36478105430"); // Random value
  
 // Generate the stream, which gets returned through a Promise
 try {
  let stream = await examplePass.generate();
  stream.pipe(res)
  
} catch (e) {
  //this will eventually be handled by your error handling middleware
  console.log(e) 
}
})

Passes not showing within apple wallet

Hi,
I've ran into a problem trying to add passes to apple wallet.
I'm able to successfully generate a pass(.pkpass file). I can double click on the file and it displays in the Pass Viewer app.
The issue i'm having is that when I try to add it to apple wallet via Simulator (it hangs - nothing happens) or Iphone (pass error - invalid pass). Not sure if you've ran into this issue before, but any help will be appreciated.

Side Note: I'm able to manually create a pass following Apple Doc Building Your First Pass
.

I am using the generic sample pass - The only thing I've change is the "passTypeIdentifier" & "teamIdentifier"
Any help will be much appreciated - I have to admit, this is the first time i'm developing anything regarding Apple ecosystem.

my pass.json file:

{
  "formatVersion" : 1,
  "passTypeIdentifier" : "pass.com.testwallet",
  "serialNumber" : "8j23fm3",
  "webServiceURL" : "https://example.com/passes/",
  "authenticationToken" : "vxwxd7J8AlNNFPS8k0a0FfUFtq0ewzFdc",
  "teamIdentifier" : "PLACEHOLDER",
  "locations" : [
    {
      "longitude" : -122.3748889,
      "latitude" : 37.6189722
    },
    {
      "longitude" : -122.03118,
      "latitude" : 37.33182
    }
  ],
  "barcode" : {
    "message" : "123456789",
    "format" : "PKBarcodeFormatPDF417",
    "messageEncoding" : "iso-8859-1"
  },
  "organizationName" : "Toy Town",
  "description" : "Toy Town Membership",
  "logoText" : "Toy Town",
  "foregroundColor" : "rgb(255, 255, 255)",
  "backgroundColor" : "rgb(197, 31, 31)",
  "generic" : {
    "primaryFields" : [
      {
        "key" : "member",
        "value" : "Johnny Appleseed"
      }
    ],
    "secondaryFields" : [
      {
        "key" : "subtitle",
        "label" : "MEMBER SINCE",
        "value" : "2012"
      }
    ],
    "auxiliaryFields" : [
      {
        "key" : "level",
        "label" : "LEVEL",
        "value" : "Platinum"
      },
      {
        "key" : "favorite",
        "label" : "FAVORITE TOY",
        "value" : "Bucky Ball Magnets",
        "textAlignment" : "PKTextAlignmentRight"
      }
    ],
    "backFields" : [
      {
        "numberStyle" : "PKNumberStyleSpellOut",
        "label" : "spelled out",
        "key" : "numberStyle",
        "value" : 200
      },
      {
        "label" : "in Reals",
        "key" : "currency",
        "value" : 200,
        "currencyCode" : "BRL"
      },
      {
        "dateStyle" : "PKDateStyleFull",
        "label" : "full date",
        "key" : "dateFull",
        "value" : "1980-05-07T10:00-05:00"
      },
      {
        "label" : "full time",
        "key" : "timeFull",
        "value" : "1980-05-07T10:00-05:00",
        "timeStyle" : "PKDateStyleFull"
      },
      {
        "dateStyle" : "PKDateStyleShort",
        "label" : "short date and time",
        "key" : "dateTime",
        "value" : "1980-05-07T10:00-05:00",
        "timeStyle" : "PKDateStyleShort"
      },
      {
        "dateStyle" : "PKDateStyleShort",
        "label" : "relative date",
        "key" : "relStyle",
        "value" : "2013-04-24T10:00-05:00",
        "isRelative" : true
      }
    ]
  }
}

Code I'm Using:

	try {
		const examplePass = await createPass({
			model: "./testwallet",
			certificates: {
				wwdr: "./certs/wwdr.pem",
				signerCert: "./certs/signerCert.pem",
				signerKey: {
					keyFile: "./certs/signerKey.pem",
					passphrase: "PlaceHolder"
				}
           },
			/* overrides: {
				// keys to be added or overridden
				serialNumber: "AAGH44625236dddaffbda"
			} */
		});
	
	     //Adding some settings to be written inside pass.json
		//examplePass.localize("en", { ... });
		//examplePass.barcode("36478105430"); // Random value 
	 
		// Generate the stream, which gets returned through a Promise
		 var stream = examplePass.generate();
		
		 // Create a write stream to a file
		pkpass = fs.createWriteStream('genCardTest.pkpass');

		stream.pipe(pkpass);
	
		doSomethingWithTheStream(stream);
	} catch (err) {
		doSomethingWithTheError(err);
	}

Multi ticket creation

Hey.
Is it possible to use your lib for multi ticket creation?
I would like to create a pkpass file with two or more tickets in it.

Thanks

Row field in auxiliaryFields

...

I noticed that in typedefinition for auxiliaryFields there is requirement of adding row property. I do not see anything about it in Apple docs. Moreover, if I add it I do not see auxiliaryFields on my pass.

Originally posted by @aaliakseyenka in #40 (comment)

Set Relevance maxDistance?

Hi - Thank you so much for this repo. I was happy to support your great work.

I am using locations in my implementation, but cannot find in the docs of this repo where to add the maxDistance for locations value?

Any help would be appreciated! Thanks!

Coupon Card

First of all, thank you for your hard work on this package, it is just awesome!

Im trying to create coupon card how can i do it?
I have [email protected] image it is not pickup up.
im missing something ? in documentation i did not find anything.

Thank you

would be nice to use real dates

It would be nice if we could pass real dare objects for relevant date and expiry date rather than creating strings from date that just get parsed again before being reformatted.

This is hinted at in the docs which say: the type of the date value must be String/date which I read as string OR date, rather than "date string".

The docs also say:

The date will be automatically parsed in order in the following formats:

MM-DD-YYYY hh:mm:ss,
DD-MM-YYYY hh:mm:ss.

I'm not sure this is a great idea...

Without actually thinking it through, I took that as being able to use either format without specifying that format. Which if course, only partly works as expected.

If you use UK format (DD-MM) then if your date can only be parsed as a UK date (eg. 31-05) then it works as expected. However if your date can be parsed as a US date (MM-DD) as well, (eg. 01-05 1st May) then it gets parsed as a US date instead, so you end up with 5th January instead.

Far too easy to do some test with dates that parse as expected thinking it's all working ok, then hit a problem later when a wider range of dates are used. Using Date objects exclusively is the safer option.

Pull request to follow

WordPress plugin

Hey,
Is it possible to rewrite the code for a WordPress plugin?

Lg max

Storing PEM Certificates on Heroku

I am trying to deploy the express server on heroku. Can anyone suggest how do I store my certificates? Should I directly store the .pem files on Heroku or should I add these .pem files and env variables.

P.S: I tried adding these .pem files as environment variables but I am getting error like this

"Error: Invalid certificate loaded. 04GpZnMBxRpVzscYqC tGwPDBUf -----END CERTIFICATE----- does not exist."

Dynamic images

Hi @alexandercerutti!
First of all, thank you for your hard work on this package, it is just awesome!

I'm in a situation where the thumbnail image has to be loaded dynamically, because it is the image of the person that has the card. I saw that on previous versions there was a .load function that downloaded an image resource.

Is there any substitution for this now? Could you attach an example in that case?

Thank you!

Fail to serve pass to iOS

This maybe a stupid issue..
I built a pass successfully but it fail to pop up when I accessing the URL form my iPhone. However, the pass is loaded correct on MAcOS's Safari... Any idea any steps I have messed up? I am working with the example code with only updated the certs path & some pass content..
Thanks for the awesome work!

image

node-forge - dependency update needed

npm audit reports a high priority issue with node-forge (one of your dependencies).

High โ”‚ Prototype Pollution in node-forge
Package โ”‚ node-forge
Patched in โ”‚ >= 0.10.0
Dependency of โ”‚ passkit-generator
Path โ”‚ passkit-generator > node-forge
More info โ”‚ https://npmjs.com/advisories/1561

Could you update and deploy a new version please?

Extracting key and cert from pkcs12

Hi Alexander,
first of all let me say what an extraordinary and well documented job you and code contributors have done here!

I'm writing because while compiling I'm having some issue with pem file creation:
wwdr.pem - created by exporting from key chain (no problem)
thenameofmyfile.p12 - created by exporting from key chain the pass.cer downloaded from apple dev site (no problem)
now I'm using thenameofmyfile.p12 to create the signerCert.pem and the signerKey.pem using the command as in the readme document:

# Extracting key and cert from pkcs12
$ openssl pkcs12 -in thenameofmyfile.p12 -clcerts -nokeys -out signerCert.pem -passin pass:mypassword
$ openssl pkcs12 -in thenameofmyfile.p12 -nocerts -out signerKey.pem -passin pass:mypassword -passout pass:mypasspassphrase

now the two file are correctly created but the signerCert.pem is working and signerKey.pem is like it's empty

and obviously trying to compile running the command rpm run test I receive the error below

Error: Something went really bad in the pass initialization! Look at the log below this message. It should contain all the infos about the problem: 
Error: Invalid certificate(s) loaded: signerKey. Please provide valid WWDR certificates and developer signer certificate and key (with passphrase).
    Refer to docs to obtain them.

any idea on what I'm doing wrong?

Error: TypeError: buffersPromise is not iterable

Hello @alexandercerutti,
First I'd like to thank you for putting this package together, it has been a great help!

I am trying to use the pass.load() function to bring in some dynamic resources.
But when I call the code you've used in your download.js examples file:

pass.load("https://s.gravatar.com/avatar/83cd11399b7ea79977bc302f3931ee52?size=32&default=retro", "icon.png");
pass.load("https://s.gravatar.com/avatar/83cd11399b7ea79977bc302f3931ee52?size=64&default=retro", "[email protected]");

I get the error: Error: TypeError: buffersPromise is not iterable

This happens with custom image resources and names as well.

I have a fix working by overwriting the pass.js file in the node_modules folder by adding the following:
line 71: const buffersPromise = await this._remoteResources.reduce(async (acc, current) =>
line 103: let bundle = noDynList.filter((f) => !f.includes('.lproj'));

I was going to create a pull request, but the git repo is on versions 1.6.1 where the npm package is on 1.6.2

Could you update the repo to version 1.6.2 or add a next branch?

Cannot find module 'passkit-generator'. Did you mean to set the 'moduleResolution' option to 'node', or to add aliases to the 'paths' option?

Dear Alexander,
just try to set up you passkit-generator but I always get the above Error (Cannot find module 'passkit-generator'. Did you mean to set the 'moduleResolution' option to 'node', or to add aliases to the 'paths' option?), even with your example in the README.md File

import { createPass, Pass } from "passkit-generator";

import path from "path";

import { createWriteStream } from "fs";

Did you have any idea, what the problem might be?

best regards

jtuttas

Push new update

im new wallet world could you give me URL or example how to push new updates to wallet card.
Thank you

Issue with TypeScript 3.7.2

Hey @alexandercerutti thank you for your passkit-generator project! I currently tried running your project but receive the following error when transpiling:

node_modules/passkit-generator/index.d.ts:67:10 - error TS2370: A rest parameter must be of an array type.

67  beacons(...data: Schema.Beacon[] | null): this;
            ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

node_modules/passkit-generator/index.d.ts:74:12 - error TS2370: A rest parameter must be of an array type.

74  locations(...data: Schema.Location[] | null): this;
              ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Getting error when deploying to a aws lambda for serverless usage.

I am getting an error on line 41 of pass.js - Object.assign(this, this._parseSettings(options));

TypeError: Cannot read property 'reduce' of undefined
    at Object.filter (/var/task/node_modules/passkit-generator/src/schema.js:133:14)
    at Pass._parseSettings (/var/task/node_modules/passkit-generator/src/pass.js:676:31)
    at new Pass (/var/task/node_modules/passkit-generator/src/pass.js:41:28)
    at exports.handler (/var/task/index.js:13:20)

Any suggestions on how to debug?
The same code works when I run it locally.

Adding pkpass file from barcode example does not work

I tried to add the downloaded file from the barcode example and send it via email.
This actually did not work - the file is recognized as Apple wallet file but if I press on it nothing happens. Same when I download the file and try to open it via iCloud.
Any idea? Does this work for you?

Allow characters such as dashes and dots in authenticationToken

In current implementation only alphanumerical characters and underscores are allowed in authenticationToken field of a pass, as far as I understand. Is it possible to allow some other characters such as dashes, dots, slashes, and plus signs? Those are fairly common because of base64 and base64url encodings, and JWT tokens. Moreover, in Apple's PassKit I think there is no restriction on authenticationToken except being a string. Thanks for providing this useful library, thank you for your time and efforts.

Can't open example

Hi alexander
Sorry for leaving issue here.
I was just trying to run the pass example, but I can not open http://localhost:8080/gen/examplePass.
Do you have idea about this $ node <the-example-you-want-to-execute>.js? And which js file I should execute.
If you can give me some instruction, it would be great.
I am looking forward to your reply.
Best regards,
Quentin

Use strings instead of pem file for passkit

Hi,
We are trying to inject the private key and certificates to the node service for creating passes. This implementation however requires us to provide a path to the key and certificate pem files. Is there a way to pass encoded string instead? That way we can store the certs and keys in application memory and inject at run time.

Model in memory

At the moment the library requires physical folder to be on the disk. It would be great to allow buffer/zip archive as an input. Issue is similar to certificates. When you working with serverless we are getting images from s3 bucket and now have to copy files to local drive. Would be great improvement to allow buffers/zip

Missing certificate conversion cross-platform procedure

Even if Apple Wallet Passes are made to be opened only under macOS, I found myself in the following situation: I'm with a Windows PC (no mac available) and want to test a new feature or fix.

So, under Windows, I don't have a way to convert PEM .cer certificates to PKCS#12 and to extract PEM files of key and certificate.
I'm going to search a way that may also involve the usage of WSL (Windows Subsystem for Linux) and OpenSSL.

It would be good to have a shared process.
I'll update this issue once found something.

If someone is reading this and has an idea, please answer here below. Thank you!

logoText as override Option

Hi Alex,

Is there any way to override the logoText?

As far as i can see it might work through the override-options, but is not declared in schema.js. Am i on the right path?

Best, Gernot

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.