Giter Site home page Giter Site logo

tomasmcguinness / dotnet-passbook Goto Github PK

View Code? Open in Web Editor NEW
301.0 29.0 113.0 15.61 MB

A .Net Library for generating Apple Passbook (Wallet) files for iOS. Please get involved by creating pull requests and opening issues!

License: MIT License

C# 100.00%
c-sharp passbook dotnet passkit apple dotnet-standard

dotnet-passbook's Introduction

dotnet-passbook

A .NET Standard Library for generating Passbook packages for iOS Wallet (formerly Passbook)

.NET Core

Supporting the project

If you use dotnet-passbook, please consider buying me a cup of coffee

Buy Me a Coffee at ko-fi.com

Installing

dotnet-passbook is also available to download from NuGet

Install-Package dotnet-passbook

Why

Creating passes for Apple's Passbook is pretty simple, but requires the use of PKI for signing manifest files, which isn't so simple! During the course of building PassVerse.com (no longer available), I created a .Net library that performs all the steps. I decided to open source this library for other .NET developers.

Requirements

The solution requires Visual Studio 2017 or higher. The library is built for .NET Standard 2.0.

Certificates

Before you run the PassGenerator, you need to ensure you have all the necessary certificates installed. There are two required.

Firstly, you need to your Passbook certificate, which you get from the Developer Portal. You must have an iOS developer account.

Secondly, you need the Apple WWDR (WorldWide Developer Relations) certificate. You can download that from here http://www.apple.com/certificateauthority/.

Depending on when you generated your Passbook certificate you'll need either the G1 or G4 certificate. If you generated your passbook certificate on or before the January 27, 2022, use G1. Otherwise use G4.

The other "Worldwide Developer Relations" certificates listed here won't work with Apple Wallet. ("Sorry, your Pass cannot be installed to Passbook at this time.")

There are instructions on my blog for generating a certificate using IIS if you're using a Windows machine

If you're on Linux/macOS or would prefer to use OpenSSL on Windows, check out using-openssl.md for instructions on how to create the necessary certificates using OpenSSL.

When moving certificates around, be sure that your Passbook certificate always includes the private key component, else the signing will fail.

Technical Stuff

To generate a pass, start by declaring a PassGenerator.

PassGenerator generator = new PassGenerator();

Next, create a PassGeneratorRequest. This is a raw request that gives you the full power to add all the fields necessary for the pass you wish to create. Each pass is broken down into several sections. Each section is rendered in a different way, based on the style of the pass you are trying to produce. For more information on this, please consult Apple's Passbook Programming Guide. The example below here will show how to create a very basic boarding pass.

Since each pass has a set of mandatory data, fill that in first.

PassGeneratorRequest request = new PassGeneratorRequest();
request.PassTypeIdentifier = "pass.tomsamcguinness.events";   
request.TeamIdentifier = "RW121242";
request.SerialNumber = "121212";
request.Description = "My first pass";
request.OrganizationName = "Tomas McGuinness";
request.LogoText = "My Pass";

Colours can be specified in HTML format or in RGB format.

request.BackgroundColor = "#FFFFFF";
request.LabelColor = "#000000";
request.ForegroundColor = "#000000";

request.BackgroundColor = "rgb(255,255,255)";
request.LabelColor = "rgb(0,0,0)";
request.ForegroundColor = "rgb(0,0,0)";

You must provide both the Apple WWDR and your Passbook certificate as X509Certificate instances. NOTE: This is a change from previous versions.

request.AppleWWDRCACertificate = new X509Certificate(...);
request.PassbookCertificate = new X509Certificate(...);

When you are creating the X509Certificate instances in the cloud, you may experience issues with the signing process. I recommend you use the MachineKeySet and Exportable X509KeyStorageFlags.

X509KeyStorageFlags flags = X509KeyStorageFlags.MachineKeySet | X509KeyStorageFlags.Exportable;
X509Certificate2 certificate = new X509Certificate2(bytes, password, flags);

Next, define the images you with to use. You must always include both standard and retina sized images. Images are supplied as byte[].

request.Images.Add(PassbookImage.Icon, System.IO.File.ReadAllBytes(Server.MapPath("~/Icons/icon.png")));
request.Images.Add(PassbookImage.Icon2X, System.IO.File.ReadAllBytes(Server.MapPath("~/Icons/[email protected]")));
request.Images.Add(PassbookImage.Icon3X, System.IO.File.ReadAllBytes(Server.MapPath("~/Icons/[email protected]")));

You can now provide more pass specific information. The Style must be set and then all information is then added to fields to the required sections. For a boarding pass, the fields are add to three sections; primary, secondary and auxiliary.

request.Style = PassStyle.BoardingPass;

request.AddPrimaryField(new StandardField("origin", "San Francisco", "SFO"));
request.AddPrimaryField(new StandardField("destination", "London", "LDN"));

request.AddSecondaryField(new StandardField("boarding-gate", "Gate", "A55"));

request.AddAuxiliaryField(new StandardField("seat", "Seat", "G5" ));
request.AddAuxiliaryField(new StandardField("passenger-name", "Passenger", "Thomas Anderson"));

request.TransitType = TransitType.PKTransitTypeAir;

You can add a BarCode.

request.AddBarcode(BarcodeType.PKBarcodeFormatPDF417, "01927847623423234234", "ISO-8859-1", "01927847623423234234");

Starting with iOS 9, multiple barcodes are now supported. This helper method supports this new feature. If you wanted to support iOS 8 and earlier, you can use the method SetBarcode().

To link the pass to an existing app, you can add the app's Apple ID to the AssociatedStoreIdentifiers array.

request.AssociatedStoreIdentifiers.Add(551768478);

Finally, generate the pass by passing the request into the instance of the Generator. This will create the signed manifest and package all the the image files into zip.

byte[] generatedPass = generator.Generate(request);

If you are using ASP.NET MVC for example, you can return this byte[] as a Passbook package

return new FileContentResult(generatedPass, "application/vnd.apple.pkpass");

iOS 15 introduced the ability to bundle and distribute multiple passes using a singular .pkpasses file. You can generate pass bundles as well by passing in a dictionary of requests values and string keys that represent the filename for each individual request.

PassGeneratorRequest myFirstRequest = new PassGeneratorRequest();
PassGeneratorRequest mySecondRequest = new PassGeneratorRequest();

// Build out your requests

List<PassGeneratorRequest> requests = new List<PassGeneratorRequest>;

requests.Add(myFirstRequest);
request.Add(mySecondRequest);

byte[] generatedBundle = generator.Generate(requests);

The resulting byte array is treated almost identically to a singular .pkpass file, but with a different extension and MIME type (pkpasses)

return new FileContentResult(generatedBundle, "application/vnd.apple.pkpasses")
{
    FileDownloadName = "tickets.pkpasses.zip"
};

Troubleshooting Passes

If the passes you create don't seem to open on iOS or in the simulator, the payload is probably invalid. To aid troubleshooting, I've created this simple tool - https://pkpassvalidator.azurewebsites.net - just run your pkpass file through this and it might give some idea what's wrong. The tool is new (Jul'18) and doesn't check absolutely everything. I'll try and add more validation to the generator itself.

IIS Security

If you're running the signing code within an IIS application, you might run into some issues accessing the private key of your certificates. To resolve this open MMC => Add Certificates (Local computer) snap-in => Certificates (Local Computer) => Personal => Certificates => Right click the certificate of interest => All tasks => Manage private key => Add IIS AppPool\AppPoolName and grant it Full control. Replace "AppPoolName" with the name of the application pool that your app is running under. (sometimes IIS_IUSRS)

Updating passes

To be able to update your pass, you must provide it with a callback. When generating your request, you must provide it with an AuthenticationToken and a WebServiceUrl. Both of these values are required. The WebServiceUrl must be HTTPS by default, but you can disable this requirement in the iOS developer options on any device you're testing on.

The authentication token is a string that will be included in the header of all requests made to your API. It's your responsibility to validate this token.

request.AuthenticationToken = "<a secret to ensure authorized access>";
request.WebServiceUrl = "https://<your api>";

The web service you point to must support Apple's protocol, outlined in the PassKit Web Service Reference

NFC Support

As of version 2.0.1, the NFC keys are now supported. To use them, just set the Nfc property with a new NFC object. Both the message and encoded public key values are mandatory.

PassGeneratorRequest request = new PassGeneratorRequest();
request.Nfc = new Nfc("THE NFC Message", "<encoded private key>");

Unfortunately, I cannot supply any information as to the values required since it's not available publically. If anyone knows what goes here, I'd be more than happy to add changes to my library to support this key.

Contribute

All pull requests are welcomed! If you come across an issue you cannot fix, please raise an issue or drop me an email at [email protected] or follow me on twitter @tomasmcguinness

License

dotnet-passbook is distributed under the MIT license: http://tomasmcguinness.mit-license.org/

dotnet-passbook's People

Contributors

arusanov avatar ashleymedway avatar averagecakeslice avatar balexandre avatar bitcoinbrisbane avatar brantburnett avatar carlosjimenezd avatar chadmichel avatar dependabot[bot] avatar dylanbeattie avatar fa18swiss avatar jiggak avatar joe-keane avatar kevm avatar ricky-g avatar the-darkvoid avatar tomasmcguinness avatar tuler avatar wilmerferreira 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  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

dotnet-passbook's Issues

Validate Request

Hi.. how to pass a valid validationHash, in the method
ValidateRequestHash(string passTypeIdentifier, string serialNumber, string validity, string validationHash)
on PassbookController

the comparison string.Equals(hash, validationHash, StringComparison.OrdinalIgnoreCase) never is true on my debugs..

Thank you

Unable to open pkpass on an iOS device

Hi,

I am able to generate a .pkpass file using C# code (thanks to the tutorials available). The pass which I generated works correct on Android device(installed an application Pass2U Wallet to open the pass) and MAC OS (through mail).

But, the same pass does not open on an iOS device. There isn't any error message that pops up when I try to open the pass from the iPhone. It simply does not open up (it is probably treating the attachment as unrecognized file).

Kindly help me.

I have also attached the generated pkpass file for reference.

Regards,
Vyas

IndyCar.zip

Feature request: A charge card example and implementation?

You have two great examples here:

  • /Pass/EventTicket will generate an event based Pass (not fully functional).
  • /Pass/BoardingPass will generate simple baording card.

I'd like to see an example for creating a "charge" card. Something like the Starbucks Passbook card.

Is this something available?

12 10 03-starbucks

Thoughts

DateTime fields should not be formatted with zzz

Two DateTime fields, ExpirationDate and RelevantDate, are being formatted with zzz, but zzz should not be used with DateTime because it does not reflect the Datime.Kind property.

https://msdn.microsoft.com/en-us/library/8kb3ddd4(v=vs.110).aspx#zzzSpecifier

"It does not reflect the value of an instance's DateTime.Kind property. For this reason, the "zzz" format specifier is not recommended for use with DateTime values."

The correct is to use the "o" standard format, which will work with DateTime or DateTimeOffset values.

https://msdn.microsoft.com/en-us/library/az4se3k1(v=vs.110).aspx#Anchor_8

Implementing POST method

Hi Tom,

We have written wcf webservices(REST) for methods as per web api refrence as per passbook standard. we are able to create passes and install succefully on passbook with webservice url and token fields(your code was very helpful). however there is no communication back to provider server. Can you please provide working refernce in WCF REST for POST method alone used for registartion. also like to know if do we need to install certificate in .pem instead of p12 in IIS(production).

Validation error

Hello,

I'm getting an error using the Simulator and console:

The passTypeIdentifier or teamIdentifier provided may not match your certificate, or the certificate trust chain could not be verified

Probably the certificates are wrong, but I want to make sure that I'm building the object using the PassGenerator method correctly, some other fields are missing since they are not that important.

// Request to send
            var request = new PassGeneratorRequest()
            {
                PassTypeIdentifier = "pass.com.SOMECOMPANY",
                TeamIdentifier = "SOMETEAMIDENTIFIER",
                Certificate = File.ReadAllBytes(HttpContext.Current.Server.MapPath("~/App_Data/somecertificate.pfx")),
                CertificatePassword = ConfigurationManager.AppSettings["PassBookCertificatePassword"],
                AppleWWDRCACertificate = File.ReadAllBytes(HttpContext.Current.Server.MapPath("~/App_Data/AppleWWDRCA.cer")),
                SerialNumber = Guid.NewGuid().ToString(),
                Description = data.Description,
                OrganizationName = "Tickets to Enjoy",
                BackgroundColor = ColorHexToPassBookColor("#00517c"),
                ForegroundColor = ColorHexToPassBookColor("#f68700"),
                LabelColor = ColorHexToPassBookColor("#ffffff"),
                LogoText = data.LogoText,
                GroupingIdentifier = data.EventCode
            };

As you can see I'm using:

Certificate = File.ReadAllBytes(HttpContext.Current.Server.MapPath("~/App_Data/somecertificate.pfx"))

which the certificate is a file ending with .pfx and I don't know if that certificate is valid, this project contains quite old code so maybe that's wrong.

Also I already updated the AppleWWDRCA.cer just in case it was outdated.

Since the pass is trying to be loaded in the simulator I guess everything else is working fine, the request, headers, etc.

Also just in case I'll add the pass.json, you might see errors that I don't.

{
  "passTypeIdentifier": "pass.com.SOMECOMPANY",
  "formatVersion": 1,
  "serialNumber": "d3ec680a-c41e-4640-8c24-dfd21bc7c920",
  "description": "SOMEDESCRIPTION",
  "organizationName": "SOMEORGANIZATION",
  "teamIdentifier": "SOMETEAM",
  "sharingProhibited": false,
  "logoText": "SOMTEXT",
  "relevantDate": "2018-07-19T13:03:53+00:00",
  "locations": [
    {
      "latitude": 28.0721,
      "longitude": 16.7256
    }
  ],
  "foregroundColor": "rgb(246,135,0)",
  "backgroundColor": "rgb(0,81,124)",
  "labelColor": "rgb(255,255,255)",
  "groupingIdentifier": "XXXXXX",
  "barcodes": [
    {
      "format": "PKBarcodeFormatQR",
      "message": "XXXXXX",
      "messageEncoding": "UTF-8"
    }
  ],
  "generic": {
    "headerFields": [
      {
        "key": "test",
        "label": "Test",
        "value": "TEST"
      }
    ],
    "primaryFields": [
      {
        "key": "type",
        "label": "Type",
        "value": "XXX"
      }
    ],
    "secondaryFields": [
      {
        "key": "code",
        "label": "Booking code",
        "value": "XX"
      },
      {
        "key": "adult",
        "label": "Adult",
        "value": "1"
      },
      {
        "key": "children",
        "label": "Children",
        "value": "1"
      },
      {
        "key": "valid",
        "label": "Valid from",
        "value": "2018/07/20"
      }
    ],
    "auxiliaryFields": [
      {
        "key": "description",
        "label": "Description",
        "value": "XXXX"
      }
    ],
    "backFields": [
      {
        "key": "back_bought",
        "label": "Name",
        "value": "XXX"
      },
      {
        "key": "back_type",
        "label": "Type",
        "value": "XX"
      },
      {
        "key": "back_code",
        "label": "Booking code",
        "value": "XX"
      },
      {
        "key": "back_adult",
        "label": "Adult",
        "value": "1"
      },
      {
        "key": "back_children",
        "label": "Children",
        "value": "1"
      },
      {
        "key": "back_valid",
        "label": "Valid from",
        "value": "2018/07/20"
      }
    ]
  }
}

Thank you very much.

No Content

Hey. I thought I'd mention one line in your code should change (imho)
Status code 204 should not send back any payload. Apple will send a log message showing that's an error (and tools such as postman yell at you).

In you method
[Route("api/v1/devices/{deviceLibraryIdentifier}/registrations/{passTypeIdentifier}/{passesUpdatedSince?}")]

Your code
return Content<Serialization.ApiResult>(HttpStatusCode.NoContent, new Serialization.ApiResult("No updated device passes available."));

should be changed to
return ResponseMessage(new HttpResponseMessage(HttpStatusCode.NoContent));

in order to silence apple's balking at ya

Percentage fields not supported --> need decimal value param

Consider the following code:
request.AddPrimaryField(new NumberField("MyPercentageField", "My Percentage Field", 5, FieldNumberStyle.PKNumberStylePercent));

On the pass this will be displayed as 500%.

You should specify 0.05M, but this is not possible since the NumberField ctor value parameter is an int --> needs to be changed to decimal.

Unable to Add pass in Wallet

Hello,

I've been trying to add a pass to my wallet, we are following all the steps from Apple developer portal and as well from your library. But, when we are try to sign the pass locally and add it to a device it works well, but when we are trying to generate a pass from your library we are facing an issue as,

Invalid data error reading pass pass.com../7122575087. The passTypeIdentifier or teamIdentifier provided may not match your certificate, or the certificate trust chain could not be verified.

Am sure that I've set the passTypeIdentifier and teamIdentifier properly in our pass.json. Also have tried regenerating the pass certificate from Apple developer portal, still no progress.

Have attached the pass.json file and the signature file and the signed .pkpass file we are generating for the same.

Can you please look at them and help me in resolving the issue? If any further details you need from my side, I'd be happy to send. Awaiting your response.

PassFiles.zip

bug for PassGenerator.cs line 195

a bug in PassGenerator.cs line 195, Cause join passbook to fail.

bug

                    string hash = GetHashForBytes(request.Images[PassbookImage.Icon]);
                    jsonWriter.WritePropertyName(@"icon.png");
                    jsonWriter.WriteValue(hash.ToLower());

                    hash = GetHashForBytes(request.Images[PassbookImage.IconRetina]);
                    jsonWriter.WritePropertyName(@"icon.png");
                    jsonWriter.WriteValue(hash.ToLower());

fix

                    string hash = GetHashForBytes(request.Images[PassbookImage.Icon]);
                    jsonWriter.WritePropertyName(@"icon.png");
                    jsonWriter.WriteValue(hash.ToLower());

                    hash = GetHashForBytes(request.Images[PassbookImage.IconRetina]);
                    jsonWriter.WritePropertyName(@"[email protected]");
                    jsonWriter.WriteValue(hash.ToLower());

Grenerate OK.

HTTP DELETE

Hi,

I was testing with this implementation and I don't have much experience with MVC, but I realized that this code does not implement HTTP Delete requests from device when the pass is deleted from passbook. Do you have some guidance how this could be implemented, do we need to add something to IIS? I also realized that, Apple sends delete requests to server continuously when it does not receive a response to the HTTP delete request.

Regards,
Turan

How enable Lockscreen Notification?

Using passbook for boarding pass, what fields am i missing to make relevant pass immediately accessible on lock screen 3 hours before departure time? ANy example?

Passbook install fails on Chrome for iOS

Hello,

I have a couple of issues trying to create my .pkpass files using dotnet-passbook.
I was able to create a pkpass file but it will not install from Chrome on iOS. (see safari.zip). It works from Safari and Mail, but on Chrome I get an error saying "sorry, your pass cannot be installed to Passbook at this time.

Another problem I have is with the same pass, if I try to set RelevantDate or Expiration date. In those cases the pass is not valid anymore and is not being loaded from any browser / app. (see relevantDate.zip)

safari.zip
relevantDate.zip

Footer image creates invalid passbook

Adding a footer image with version 0.9.7 creates an invalid passbook file.

System log shows:

MobileSafari[251]: Invalid data error reading pass pass.com.envisageny.Engage360/PREREG44859fd3-a4d9-4b5f-8cf0-123ce000005d. No entry in manifest for file footer.png
MobileSafari[251]: PassBook Pass download failed: The pass cannot be read because it isn't valid.

I am perfectly happy to debug this myself, however I see that the version in nuget.org is ahead of the code in github.com. Could you push your latest code to github?

Not adding to passbook

Using your solution I was able to create pkpass file. When I email my self and open it via email - I am able to see the pass. When I click Add on the top right corner, this pass does not get added to iOS passbook app.

Disregard the text, currently I am using dummy data

pass

Mountain Lion Pass Viewer

Pass The generated C # does not open in the Viewer Pass Mountaion Lion (works on iphone).
Already the Pass of passsource, works perfectly.

What can it be?

Unsupported algorithm

I have tried to implement this library and have used the following code (replacing "identifier", "thumbprint" and so on with my actual data):

        generator = new PassGenerator();
        request = new PassGeneratorRequest();
        request.PassTypeIdentifier = "identifier";
        request.TeamIdentifier = "myTeamIdentifier";
        request.SerialNumber = "serialNr";
        request.Description = "text";
        request.OrganizationName = "text";
        request.LogoText = "text";
        request.CertThumbprint = "thumbprint";
        request.CertLocation = System.Security.Cryptography.X509Certificates.StoreLocation.CurrentUser;

        request.BackgroundColor = "rgb(255,255,255)";
        request.ForegroundColor = "rgb(0,0,0)";

        request.Images.Add(PassbookImage.Icon, System.IO.File.ReadAllBytes(@"C:\Users\Administrator\Documents\Visual Studio 2013\Projects\PassbookGenerator\Icons\Icon.png"));
        request.Images.Add(PassbookImage.IconRetina, System.IO.File.ReadAllBytes(@"C:\Users\Administrator\Documents\Visual Studio 2013\Projects\PassbookGenerator\Icons\[email protected]"));

        request.Style = PassStyle.Generic;

        request.AddPrimaryField(new StandardField("name", "", "Name"));

        request.AddSecondaryField(new StandardField("exercise", "Exercise", "Test"));

        request.AddAuxiliaryField(new StandardField("seat", "From date", "01-01-2014"));

            byte[] generatedPass = generator.Generate(request);

When the last line of code is executed I get an ArgumentException saying "Unsupported algorithm specified". Any ida what I am doing wrong and how to fix it? The exception occurs in BountyCastle.Crypto.dll

Update Passes

Hi Tomas,
I have followed your steps to create the pass and that worked out just fine.
As I was trying to update it I couldn't exactly understand the way and both on android and iphone devices when trying to make an update it says that it is not supported.
What exactly should that web service do to update the pass?
Also I couldn't find the PassRegistrationController in your sample project as you mention in the documentation.
I wanna hope that is the part that I am missing to successfully update my pass.

Passbook gets generated but cant open it

Hi,

I generated my Passbook

byte[] generatedPass = generator.Generate(request);

        return new FileContentResult(generatedPass, "application/vnd.apple.pkpass");

But it downloads a file called download and when I add the extension .pkpass it says the pkpass could not be opened.

What am I doing wrong?

Issue in PassGenerator.ValidateCertificates()

Hello and thanks for the continued support with this project.

I noticed that the PassGenerator.ValidateCertificates() method fails when it tries to create the nameParts dictionary if the passCert.SubjectName.Name contains an organization name with a comma. e.g. O="Acme, Inc.". It throws off the split on the comma. Getting an index out of range error.

Dictionary<string, string> nameParts =
passCert.SubjectName.Name
.Split(new string[] { ", " }, StringSplitOptions.RemoveEmptyEntries)
.ToDictionary(k => k.Split(new char[] { '=' }, StringSplitOptions.RemoveEmptyEntries)[0],
e => e.Split(new char[] { '=' }, StringSplitOptions.RemoveEmptyEntries)[1]);

Thanks.

cannot find PassRegistrationController file in Passbook.Sample.Web

As per readme:

There are several methods that the Pass will invoke when it's installed and updated. To see a reference implementation of this, look at the PassRegistrationController class in the Passbook.Sample.Web project.

But I am not able to find this controller class in source code.

Authentication error when trying to install Pass from email

Hi Tomas,

I am trying to use your code to generate a pass and subsequently mailing it to an iPhone (release version of IOS6). The pass is generated without a glitch and shows up in the mail attachment on the iPhone and opens correctly as a Pass. However when trying to 'add' it to Passbook, the console shows these errors.

Sep 21 21:26:24 iPhone-4S passd[219] : Sep 21 21:26:24 SecTrustEvaluate [leaf AnchorSHA1 AnchorTrusted SubjectOrganizationalUnit]
Sep 21 21:26:24 iPhone-4S passd[219] : Invalid data error reading card pass.com.ticket.event/012345678910. The passTypeIdentifier or teamIdentifier provided may not match your certificate, or the certificate trust chain could not be verified.

I checked my thumbprint and installed the root, the dev relations and pass type certs in the personal certificate store on my developer machine (windows) after creating a pass type ID. Copied the thumbprint from the certificate store to web.config. Adjusted references to the pass type id.

Any ideas where this is going wrong? Tried to fix this for an entire day, no improvements....

push notification does not work

Everything seems to work except the push notification method. Response is never returned. Already updated firewall to allow traffic from the designated port. All certs are installed on my server.

Key not valid for use in specified state during generation

Hi,

I'm having trouble generating a Passbook.

PassGenerator.cs, SignManifestFile, at line 288:

Org.BouncyCastle.Crypto.AsymmetricKeyParameter privateKey = DotNetUtilities.GetKeyPair(card.PrivateKey).Private;

Is throwing an exception with Key not valid for used in specified state

It's able to find the certificate for the passbook, but dies there. Any ideas? Thanks!

dotnet Core 2.0?

I'm trying to implement a server web api using .net core 2.0
At the
byte[] generatedPass = generator.Generate(request);
line I get the following error (I have a feeling it's a dot net core issue) :

System.TypeLoadException
HResult=0x80131522
Message=Could not load type 'System.Security.Cryptography.Pkcs.SignedCms' from assembly 'System.Security, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a'.
Source=Passbook.Generator
StackTrace:
at Passbook.Generator.PassGenerator.SignManifestFile(PassGeneratorRequest request)
at Passbook.Generator.PassGenerator.GenerateManifestFile(PassGeneratorRequest request)
at Passbook.Generator.PassGenerator.Generate(PassGeneratorRequest request)
at PasskitServer.Controllers.PassesController.Get(String PassTypeId, String serialNo) in C:\Users\punky\Documents\Visual Studio 2017\Projects\PasskitServer\PasskitServer\Controllers\PassesController.cs:line 72
at Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker.d__12.MoveNext()

Not able to add pass to wallet

I have generated a pk pass and the same loads fine with my passviewer in MAC but the same doesn't load in my phone when I tried to add it to wallet.I tried debugging in Xcode but got the following error:Mar 1 13:05:26 ctsusers-iPhone MobileMail(PassKitCore)[273] : Verifying structure and signature for pass
Mar 1 13:05:26 ctsusers-iPhone MobileMail(PassKitCore)[273] : Invalid data error reading pass .
Mar 1 13:05:26 ctsusers-iPhone MobileMail(PassKitCore)[273] : Invalid data error reading pass .

but I am not able to figure out what is the problem,below I am pasting the pass.json as well.Can someone please review this and let me know what could be the problem.Appreciate your help.

{
"formatVersion": 1,
"passTypeIdentifier": "pass.com.abcd.efgh",
"authenticationToken": "PHT-jpffvctIRditg0nsmfffEFWgg56cFfdddfflvGfff50eMk",
"serialNumber": "12345784500",
"teamIdentifier": "5TKVEP484U",
"webServiceURL": "https: //services-gf.abcd.com/apiservices/passbook/",
"description": "testing Balance\u00AE amount",
"barcode": {
"message": "3453988943989349896889368963",
"format": "PKBarcodeFormatAztec",
"messageEncoding": "iso-8859-1"
},
"organizationName": "XYZ",
"foregroundColor": "rgb(255-255-255)",
"backgroundColor": "rgb(32,95,137)",
"labelColor": "rgb(80-159-209)",
"associatedStoreIdentifiers": ["335364882"],
"locations": [],
"storeCard": {
"headerFields": [{
"key": "date",
"label": "Rx#",
"value": "201..",
"textAlignment": "PKTextAlignmentRight"
}],
"auxiliaryFields": [{
"key": "ABCD",
"label": "gegegegge",
"value": "geegeeeg"
},
{
"label": "MORE INFO",
"value": "ON BACK",
"textAlignment": "PKTextAlignmentRight"
}],
"backFields": [{
"key": "pick-up location",
"label": "PICK-UP LOCATION",
"value": "wewrwttwrtrttllllgslglskknknk "
},
{
"key": "etwr",
"label": "egegegegegeggege",
"value": "34252552525"
},
{
"key": "date",
"label": "fegegegegge",
"value": "egeggeeg"
}]
}
}

Hosting in shared servers

I have complete my own Pasbook generator but as it's in a hosting environment (Cloud hosting) I couldn't use the ThumbPrint part.

Would be nice to support this as well.

I ended up adding 3 new properties to the PassGeneratorRequest

/// <summary>
/// Certificate File Path
/// </summary>
public string CertPath { get; set; }
/// <summary>
/// Developer Certificate Password
/// </summary>
public string  CertPassword { get; set; }
/// <summary>
/// Apple Certificate File Path
/// </summary>
public string AppleCertPath { get; set; }

and then use in the PassGenerator

private X509Certificate2 GetAppleCertificate(PassGeneratorRequest request)
{
    if (string.IsNullOrWhiteSpace(request.AppleCertPath))
        return GetSpecifiedCertificate("โ€Ž0950b6cd3d2f37ea246a1aaa20dfaadbd6fe1f75", StoreName.CertificateAuthority, StoreLocation.LocalMachine);

    return new X509Certificate2(request.AppleCertPath);
}

public static X509Certificate2 GetCertificate(PassGeneratorRequest request)
{
    if (string.IsNullOrWhiteSpace(request.CertPath))
        return GetSpecifiedCertificate(request.CertThumbprint, StoreName.My, request.CertLocation);

    return new X509Certificate2(request.CertPath, request.CertPassword, X509KeyStorageFlags.Exportable);
}

we now can host the certificates in a folder inside our project and simple assign them to the new properties:

request.AppleCertPath = Server.MapPath("~/Certificates/AppleWWDRCA.cer");

request.CertPath = Server.MapPath("~/Certificates/PassBookBoardingPassCertificate.pfx");
request.CertPassword = "123456";

I hope it helps anyone trying this.

Allow major and minor to be added to iBeacons

Right now, you can only add a UUID to the beacon field using the PassGeneratorRequest AddBeacon() method. However, Apple supports optional major and minor fields for more specific locations.

Error in Passbook.Generator.RelevantBeacon

private void Validate()
{
if (!string.IsNullOrEmpty(this.ProximityUUID))
throw new RequiredFieldValueMissingException("ProximityUUID");
}

the check is wrong. it should check if (string.IsNullOrEmpty(this.ProximityUUID))
(also don't forget about nuget)
thanks.

Cannot find the certificate and private key for decryption

I have both certificates:

AppleWWDRCA.cer from apple

Certificates.p12 also from apple, but I added it to keychain and then selected both the certificate and private key and exported it as .p12,

This is how I implement it:

string path = (System.Web.HttpContext.Current.Server.MapPath("~/Certificates.p12"));
byte[] certData = System.IO.File.ReadAllBytes(path);

        request.Certificate = certData;
        request.CertificatePassword = "MyPassword";

        string appleCertPath = (System.Web.HttpContext.Current.Server.MapPath("~/AppleWWDRCA.cer"));
        request.AppleWWDRCACertificate = System.IO.File.ReadAllBytes(appleCertPath);

But I get this error:

Cannot find the certificate and private key for decryption.
When I try my Certificate with .cer format (with private key, not password)

Key does not exist.
What am I doing wrong and how do I fix this?

I have confirmed that both of these files have private key with them. PLEASE HELP

Public access to Pass.packagePathAndName

Currently Pass.packagePathAndName is private which does not allow to identify the temporary file and clean up the file after pass generation.

Suggestion: Add a public getter property for packagePathAndName.

"Failed to sign manifest" when selected pass cert via thumbprint.

Hi!

I followed the instructions on your blog to generate a pass certificate with a private key. I installed the Apple WWDR cert, as well. I tried installing the pass cert in both LocalMachine/Personal and CurrentUser/Personal, as well as some other stores.

I was able to have the PassGenerator automatically pick up the Apple cert, so that isn't an issue. However, no matter which store location I choose, I cannot get it to pick up my pass cert. When I instead use File.ReadAllBytes and set the CertificatePassword, it works without issue, but I don't want to commit a cert with a private key to my repository. I've double-checked my thumbprint multiple times. I'm using what is listed in windows' certificate view.

Is there some kind of bug?

passRequest.CertThumbprint = "[thumbprint goes here]";
passRequest.CertLocation = System.Security.Cryptography.X509Certificates.StoreLocation.LocalMachine;

Update nuget package

The package at nuget.org lacks of
this.RelevantBeacons = new List();
in constructor of PassGeneratorRequest
Cause of that pass generation are failing always

Problem with certificate

Hi,
first of all thanks for this great code.
I am trying to use it to generate coupons and add them to passbook. I have downloaded the sample application and followed the instructions on your blog to create a PassTypeID certificate.

However at runtime the application occurs in an exception at line 438 of the PassGenerator class, exactly in the method private static X509Certificate2 GetCertificateFromBytes(byte[] bytes, string password). However I am pretty sure that the password is correct because I have created personally.

Could you please share any thought regarding this problem I am occurring in ?

Thanks a lot
vdecristofaro

Store Card

how to Generate Store Card ?
And how to create .pkpass file from generatedPass bytes..

Please Provide the best solution.

update passes

First of all, great library. This is really the only dot net / wallet pass integration out there. Is there any way you can provide detailed instructions for updating the passes? The pass generation/signing works excellent, however updating is also critical for me. I'm having trouble piecing together the right details based on your "updating passes" paragraph and your code.

Thanks

The Optional {passesUpdatedSince?} doesn't seem to work

The route
[Route("devices/{deviceLibraryIdentifier}/registrations/{passTypeIdentifier}/{passesUpdatedSince?}")]
public IHttpActionResult GetDevicePasses(string deviceLibraryIdentifier, string passTypeIdentifier, string passesUpdatedSince = null)

doesn't seem to work. Web client gets a 405 error back.
From what I can tell - the syntax looks correct for an option query for passesUpdatesSince is there, but I can't get it to work.
Dropping the {passesUpdatedSince} from the route does work fine of course - I just can't seem to get a route with that option string in there.

Help?

signature file not generated properly

Hi,

I have downloaded the pass certificate by uploading signing request from IIS and after completing file I got pfx file.

I used Newton.json to generate pass.json file but it is not recognized by passbook. I used sample pass.json provided by apple and it is working fine. When I compared both the file, both are have same data including indentation..I wonder why is still not working.

I used below method,

byte[] manifestbytes = Encoding.ASCII.GetBytes(manifest);
ContentInfo contentinfo = new ContentInfo(manifestbytes);
SignedCms signedcms = new SignedCms(contentinfo, true);
CmsSigner oursigner = new CmsSigner(new X509Certificate2(PassCertpfx,Passpfxpassword));
signedcms.ComputeSignature(oursigner);
signatureFile=signedcms.Encode();
return signatureFile;

After this method signature file is getting generated but it is not working

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.