Skip to content

Instantly share code, notes, and snippets.

@odrobnik
Last active January 3, 2016 08:19
Show Gist options
  • Save odrobnik/8435035 to your computer and use it in GitHub Desktop.
Save odrobnik/8435035 to your computer and use it in GitHub Desktop.
Working on this to bundle up the files of a pkpass
#!/usr/bin/env ruby
require 'json'
require "openssl"
# use current time as serial number
serialNumber = Time.now.to_i.to_s
eventDate = Time.new(2014, 07, 24, 20, 15, 0, "+02:00")
seat = "1A"
# date should be string
eventDateString = eventDate.utc.strftime("%Y-%m-%dT%H:%M:%SZ")
# assemble a "signed" barcode message
barcodeMessage = "TICKET:#{eventDateString},#{seat},#{serialNumber}"
salt = "EXTRA SECRET SAUCE"
barcodeMessageSignature = Digest::MD5.hexdigest barcodeMessage + salt
barcodeMessage = barcodeMessage + "|#{barcodeMessageSignature}"
# check/load WWDR root certificate
begin
root_cert_file = File.read('WWDR.pem')
root_cert = OpenSSL::X509::Certificate.new root_cert_file
rescue => err
puts "Cannot load root certificate: #{err}"
exit 1
end
# check/load signing certificate
begin
certificate = OpenSSL::X509::Certificate.new File.read('passcertificate.pem')
rescue => err
puts "Cannot load signing certificate: #{err}"
exit 1
end
# check/load private signing key
begin
key_file = File.read('passkey.pem')
key = OpenSSL::PKey::RSA.new key_file, '12345'
rescue => err
puts "Cannot load private signing key: #{err}"
exit 1
end
# assemble the pass in a hash
pass = {
"formatVersion" => 1
}
# add pass meta data
pass["passTypeIdentifier"] = "pass.com.drobnik.movienight"
pass["serialNumber"] = serialNumber
pass["teamIdentifier"] = "Z7L2YCUH45"
pass["organizationName"] = "Cocoanetics"
pass["logoText"] = "Cocoanetics"
pass["description"] = "VIP Movie Night Sofa Seat"
pass["relevantDate"] = eventDateString #{}"2014-01-16T11:00:00Z"
location = {
"longitude" => 48.0528,
"latitude" => 14.5877
}
pass["locations"] = [location]
pass["maxDistance"] = 10000
#Time.new.utc.strftime("%Y-%m-%dT%H:%M:%S%Z")
# create the barcode
barcode = {
"format" => "PKBarcodeFormatPDF417",
"messageEncoding" => "iso-8859-1"
}
barcode["message"] = barcodeMessage
pass["barcode"] = barcode
# header fields
headerFields = [{
"key" => "seat",
"label" => "Seat",
"value" => seat
}]
# primary fields
primaryFields = [{
"key" => "name",
"value" => "VIP Movie Night"
}]
# secondary fields
secondaryFields = [{
"key" => "location",
"label" => "Location",
"value" => "Oliver's Home Movie Theater"
}]
# auxiliary fields
auxiliaryFields = [{
"key" => "date",
"label" => "Event Date",
"dateStyle" => "PKDateStyleMedium",
"timeStyle" => "PKDateStyleShort",
"value" => eventDateString
}]
# fields on back of pass
backFields = [
{
"key" => "phone",
"label" => "For more info",
"value" => "800-1234567890"
},
{
"key" => "terms",
"label" => "TERMS AND CONDITIONS",
"value" => "Free popcorn and drink at entrance. Please arrive sufficiently early to pick your seat and allow show to start on time."
}
]
# put ticket fields together
eventTicketFields = {
"headerFields" => headerFields,
"primaryFields" => primaryFields,
"secondaryFields" => secondaryFields,
"auxiliaryFields" => auxiliaryFields,
"backFields" => backFields
}
pass["eventTicket"] = eventTicketFields
# create pass JSON string
passJSON = JSON.pretty_generate(pass)
# get SHA1 of pass JSON
passSHA1 = Digest::SHA1.hexdigest passJSON
# files that are possible in pkpass
possibleResources = ['icon.png', '[email protected]',
'thumbnail.png', '[email protected]',
'strip.png', '[email protected]',
'logo.png', '[email protected]',
'background.png', '[email protected]']
# filter possible resources with actual files in folder
resources = possibleResources & Dir['*']
# first file is the JSON
manifest = {"pass.json" => passSHA1}
# keep track of files to put in ZIP
zipCommand = ["zip", "-q", serialNumber + ".pkpass", "pass.json", "signature", "manifest.json"]
# iterate over resources
resources.each do |resource_file|
# load file contents into variable
file = File.open(resource_file, "rb")
contents = file.read
# get resource SHA1
contents_SHA1 = Digest::SHA1.hexdigest contents
# add resource file and SHA1 to manifest hash
manifest[resource_file] = contents_SHA1
zipCommand << resource_file
end
# create manifest JSON string
manifestJSON = JSON.pretty_generate(manifest)
# write manifest to disk
manifest_file = open("manifest.json", "w")
manifest_file.write(manifestJSON)
manifest_file.close
# write pass file to disk
pass_file = open("pass.json", "w")
pass_file.write(passJSON)
pass_file.close
# create signature
signature = OpenSSL::PKCS7.sign(certificate, key, manifestJSON, [root_cert], OpenSSL::PKCS7::BINARY | OpenSSL::PKCS7::DETACHED).to_der
# write signature to disk
signature_file = open("signature", "wb")
signature_file.write signature
signature_file.close
# execute zip command
system(*zipCommand)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment