passkit 0.5.4 → 0.6.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +4 -0
- data/app/models/passkit/pass.rb +32 -16
- data/docs/passkit_environment_variables.md +8 -6
- data/docs/step5.png +0 -0
- data/lib/passkit/base_pass.rb +103 -5
- data/lib/passkit/example_store_card.rb +30 -6
- data/lib/passkit/generator.rb +36 -11
- data/lib/passkit/version.rb +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 7f0014535dcee793bfad66fd1424eb76f7b93bd5125585c65a2fbbd0ed48e145
|
4
|
+
data.tar.gz: e96bd5782db486f9cdec37721094ed11307e7fda581aa21223c7300c1757cc2a
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: e1d58e15fff676e4dc197676d5d71d8814a21669086f90e9f19c8e136f64d47205c69b71ffd612efd3411f51d3f6014736571f4e64caab992fa308d737872cff
|
7
|
+
data.tar.gz: 5327cad119f6060ace0e4fe2d485d3df18c412d1e6d4cc652eeded28e77108f91b8a7a6b322caebd87581846ee2fc4c268cd6f5b93fe980d2e1e5d12b1339ba8
|
data/CHANGELOG.md
CHANGED
data/app/models/passkit/pass.rb
CHANGED
@@ -7,30 +7,46 @@ module Passkit
|
|
7
7
|
has_many :registrations, foreign_key: :passkit_pass_id
|
8
8
|
has_many :devices, through: :registrations
|
9
9
|
|
10
|
-
delegate :
|
11
|
-
:
|
12
|
-
:
|
13
|
-
:
|
14
|
-
:
|
15
|
-
:foreground_color,
|
10
|
+
delegate :apple_team_identifier,
|
11
|
+
:app_launch_url,
|
12
|
+
:associated_store_identifiers,
|
13
|
+
:auxiliary_fields,
|
14
|
+
:back_fields,
|
16
15
|
:background_color,
|
17
|
-
:label_color,
|
18
|
-
:web_service_url,
|
19
16
|
:barcode,
|
20
|
-
:
|
21
|
-
:
|
17
|
+
:barcodes,
|
18
|
+
:beacons,
|
19
|
+
:boarding_pass,
|
20
|
+
:coupon,
|
22
21
|
:description,
|
23
|
-
:
|
22
|
+
:event_ticket,
|
23
|
+
:expiration_date,
|
24
|
+
:file_name,
|
25
|
+
:foreground_color,
|
26
|
+
:format_version,
|
27
|
+
:generic,
|
28
|
+
:grouping_identifier,
|
29
|
+
:header_fields,
|
30
|
+
:label_color,
|
31
|
+
:language,
|
24
32
|
:locations,
|
25
|
-
:
|
33
|
+
:logo_text,
|
34
|
+
:max_distance,
|
35
|
+
:nfc,
|
36
|
+
:organization_name,
|
37
|
+
:pass_path,
|
26
38
|
:pass_type,
|
27
|
-
:
|
39
|
+
:pass_type_identifier,
|
28
40
|
:primary_fields,
|
41
|
+
:relevant_date,
|
29
42
|
:secondary_fields,
|
30
|
-
:
|
31
|
-
:back_fields,
|
43
|
+
:semantics,
|
32
44
|
:sharing_prohibited,
|
33
|
-
:
|
45
|
+
:store_card,
|
46
|
+
:suppress_strip_shine,
|
47
|
+
:user_info,
|
48
|
+
:voided,
|
49
|
+
:web_service_url,
|
34
50
|
to: :instance
|
35
51
|
|
36
52
|
before_validation on: :create do
|
@@ -1,6 +1,6 @@
|
|
1
1
|
# Setup Passkit Environment variables
|
2
2
|
|
3
|
-
|
3
|
+
### `PASSKIT_WEB_SERVICE_HOST`
|
4
4
|
|
5
5
|
This is the host where your Rails app is running. It is used to generate the URLs for the passes.
|
6
6
|
When the device wants to update the Pass, it will invoke services on this host.
|
@@ -8,19 +8,19 @@ In production, it will simply be your domain name, but in development you can us
|
|
8
8
|
|
9
9
|
**Remember that it must always start with `https://`.**
|
10
10
|
|
11
|
-
|
11
|
+
### `PASSKIT_APPLE_INTERMEDIATE_CERTIFICATE`
|
12
12
|
|
13
13
|
This is the easy one.
|
14
14
|
Head to https://www.apple.com/certificateauthority/ and download the latest Apple Intermediate Certificate Worldwide Developer Relations.
|
15
|
+
You might want to choose the one with the longest expiration date.
|
15
16
|
|
16
|
-
|
17
|
-
## `PASSKIT_APPLE_TEAM_IDENTIFIER`
|
17
|
+
### `PASSKIT_APPLE_TEAM_IDENTIFIER`
|
18
18
|
|
19
19
|
You find this in your Apple Developer dashboard, under Membership.
|
20
20
|
|
21
21
|
![Membership](membership.png)
|
22
22
|
|
23
|
-
|
23
|
+
### `PASSKIT_PASS_TYPE_IDENTIFIER`, `PASSKIT_PRIVATE_P12_CERTIFICATE` and `PASSKIT_CERTIFICATE_KEY`
|
24
24
|
|
25
25
|
Head to your Apple Developers console and generate a new certificate.
|
26
26
|
|
@@ -40,9 +40,11 @@ And create the certificate:
|
|
40
40
|
|
41
41
|
At the end, you'll have a `pass.cer` file.
|
42
42
|
|
43
|
-
Open it in the Keychain Access tool and export it:
|
43
|
+
Open it in the Keychain Access tool and export it (you must be in the My Certificates tab):
|
44
44
|
|
45
45
|
![Step 5](step5.png)
|
46
46
|
|
47
47
|
Set a password and get your p12 file. The path to this file is the `PASSKIT_PRIVATE_P12_CERTIFICATE` variable.
|
48
48
|
Save the password. This is the `PASSKIT_CERTIFICATE_KEY` variable.
|
49
|
+
|
50
|
+
`PKCS12_parse: unsupported`: you might encounter this issue: https://help.heroku.com/88GYDTB2/how-do-i-configure-openssl-to-allow-the-use-of-legacy-cryptographic-algorithms
|
data/docs/step5.png
CHANGED
Binary file
|
data/lib/passkit/base_pass.rb
CHANGED
@@ -37,6 +37,9 @@ module Passkit
|
|
37
37
|
def pass_type
|
38
38
|
:storeCard
|
39
39
|
# :coupon
|
40
|
+
# :eventTicket
|
41
|
+
# :generic
|
42
|
+
# :boardingPass
|
40
43
|
end
|
41
44
|
|
42
45
|
def web_service_url
|
@@ -83,16 +86,111 @@ module Passkit
|
|
83
86
|
def max_distance
|
84
87
|
end
|
85
88
|
|
89
|
+
# URL to launch the associated app (nil by default)
|
90
|
+
# Returns a String
|
91
|
+
def app_launch_url
|
92
|
+
end
|
93
|
+
|
94
|
+
# A list of Apple App Store identifiers for apps associated
|
95
|
+
# with the pass. The first one that is compatible with the
|
96
|
+
# device is picked.
|
97
|
+
# Returns an array of numbers
|
98
|
+
def associated_store_identifiers
|
99
|
+
[]
|
100
|
+
end
|
101
|
+
|
102
|
+
# An array of barcodes, the first one that can
|
103
|
+
# be displayed on the device is picked.
|
104
|
+
# Returns an array of hashes representing Pass.Barcodes
|
105
|
+
def barcodes
|
106
|
+
[]
|
107
|
+
end
|
108
|
+
|
109
|
+
# List of iBeacon identifiers to identify when the
|
110
|
+
# pass should be displayed.
|
111
|
+
# Returns an array of hashes representing Pass.Beacons
|
112
|
+
def beacons
|
113
|
+
[]
|
114
|
+
end
|
115
|
+
|
116
|
+
# Information specific to a boarding pass
|
117
|
+
# Returns a hash representing Pass.BoardingPass
|
118
|
+
def boarding_pass
|
119
|
+
end
|
120
|
+
|
121
|
+
# Information specific to a coupon
|
122
|
+
# Returns a hash representing Pass.Coupon
|
123
|
+
def coupon
|
124
|
+
end
|
125
|
+
|
126
|
+
# Information specific to an event ticket
|
127
|
+
# Returns a hash representing Pass.EventTicket
|
128
|
+
def event_ticket
|
129
|
+
end
|
130
|
+
|
131
|
+
# Date and time the pass expires, must include
|
132
|
+
# days, hours and minutes (seconds are optional)
|
133
|
+
# Returns a String representing the date and time in W3C format
|
134
|
+
def expiration_date
|
135
|
+
end
|
136
|
+
|
137
|
+
# Information specific to a generic pass
|
138
|
+
# Returns a hash representing Pass.Generic
|
139
|
+
def generic
|
140
|
+
end
|
141
|
+
|
142
|
+
# A key to identify group multiple passes together
|
143
|
+
# (e.g. a number of boarding passes for the same trip)
|
144
|
+
# Returns a String
|
145
|
+
def grouping_identifier
|
146
|
+
end
|
147
|
+
|
148
|
+
# Information specific to Value Added Service Protocol
|
149
|
+
# transactions
|
150
|
+
# Returns a hash representing Pass.NFC
|
151
|
+
def nfc
|
152
|
+
end
|
153
|
+
|
154
|
+
# Date and time when the pass becomes relevant and should be
|
155
|
+
# displayed, must include days, hours and minutes
|
156
|
+
# (seconds are optional)
|
157
|
+
# Returns a String representing the date and time in W3C format
|
158
|
+
def relevant_date
|
159
|
+
end
|
160
|
+
|
161
|
+
# Machine readable metadata that the device can use
|
162
|
+
# to suggest actions
|
163
|
+
# Returns a hash representing SemanticTags
|
164
|
+
def semantics
|
165
|
+
end
|
166
|
+
|
167
|
+
# Information specific to a store card
|
168
|
+
# Returns a hash representing Pass.StoreCard
|
169
|
+
def store_card
|
170
|
+
end
|
171
|
+
|
172
|
+
# Display the strip image without a shine effect
|
173
|
+
# Returns a boolean
|
174
|
+
def suppress_strip_shine
|
175
|
+
true
|
176
|
+
end
|
177
|
+
|
178
|
+
# JSON dictionary to display custom information for
|
179
|
+
# companion apps. Data isn't displayed to the user. e.g.
|
180
|
+
# a machine readable version of the user's favourite coffee
|
181
|
+
def user_info
|
182
|
+
end
|
183
|
+
|
86
184
|
def file_name
|
87
185
|
@file_name ||= SecureRandom.uuid
|
88
186
|
end
|
89
187
|
|
90
188
|
# QRCode by default
|
91
189
|
def barcode
|
92
|
-
{messageEncoding: "iso-8859-1",
|
93
|
-
|
94
|
-
|
95
|
-
|
190
|
+
{ messageEncoding: "iso-8859-1",
|
191
|
+
format: "PKBarcodeFormatQR",
|
192
|
+
message: "https://github.com/coorasse/passkit",
|
193
|
+
altText: "https://github.com/coorasse/passkit" }
|
96
194
|
end
|
97
195
|
|
98
196
|
# Barcode example
|
@@ -131,7 +229,7 @@ module Passkit
|
|
131
229
|
false
|
132
230
|
end
|
133
231
|
|
134
|
-
|
232
|
+
private
|
135
233
|
|
136
234
|
def folder_name
|
137
235
|
self.class.name.demodulize.underscore
|
@@ -37,11 +37,13 @@ module Passkit
|
|
37
37
|
end
|
38
38
|
|
39
39
|
# QRCode by default
|
40
|
-
def
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
40
|
+
def barcodes
|
41
|
+
[
|
42
|
+
{ messageEncoding: "iso-8859-1",
|
43
|
+
format: "PKBarcodeFormatQR",
|
44
|
+
message: "https://github.com/coorasse/passkit",
|
45
|
+
altText: "https://github.com/coorasse/passkit" }
|
46
|
+
]
|
45
47
|
end
|
46
48
|
|
47
49
|
# Barcode example
|
@@ -56,6 +58,28 @@ module Passkit
|
|
56
58
|
"Loyalty Card"
|
57
59
|
end
|
58
60
|
|
61
|
+
def app_launch_url
|
62
|
+
"https://github.com/coorasse/passkit"
|
63
|
+
end
|
64
|
+
|
65
|
+
def relevant_date
|
66
|
+
Time.current.strftime("%Y-%m-%dT%H:%M:%S%z")
|
67
|
+
end
|
68
|
+
|
69
|
+
def expiration_date
|
70
|
+
# Expire the pass tomorrow
|
71
|
+
(Time.current + 60*60*24).strftime("%Y-%m-%dT%H:%M:%S%z")
|
72
|
+
end
|
73
|
+
|
74
|
+
def semantics
|
75
|
+
{
|
76
|
+
balance: {
|
77
|
+
amount: "100",
|
78
|
+
currencyCode: "USD"
|
79
|
+
}
|
80
|
+
}
|
81
|
+
end
|
82
|
+
|
59
83
|
def header_fields
|
60
84
|
[{
|
61
85
|
key: "balance",
|
@@ -101,7 +125,7 @@ module Passkit
|
|
101
125
|
}]
|
102
126
|
end
|
103
127
|
|
104
|
-
|
128
|
+
private
|
105
129
|
|
106
130
|
def folder_name
|
107
131
|
self.class.name.demodulize.underscore
|
data/lib/passkit/generator.rb
CHANGED
@@ -23,7 +23,7 @@ module Passkit
|
|
23
23
|
compress_pass_file
|
24
24
|
end
|
25
25
|
|
26
|
-
|
26
|
+
private
|
27
27
|
|
28
28
|
def check_necessary_files
|
29
29
|
raise "icon.png is not present in #{@pass.pass_path}" unless File.exist?(File.join(@pass.pass_path, "icon.png"))
|
@@ -48,24 +48,49 @@ module Passkit
|
|
48
48
|
pass = {
|
49
49
|
formatVersion: @pass.format_version,
|
50
50
|
teamIdentifier: @pass.apple_team_identifier,
|
51
|
-
|
51
|
+
authenticationToken: @pass.authentication_token,
|
52
52
|
backgroundColor: @pass.background_color,
|
53
|
-
webServiceURL: @pass.web_service_url,
|
54
|
-
barcode: @pass.barcode,
|
55
|
-
voided: @pass.voided,
|
56
|
-
organizationName: @pass.organization_name,
|
57
53
|
description: @pass.description,
|
58
|
-
|
59
|
-
locations: @pass.locations,
|
54
|
+
foregroundColor: @pass.foreground_color,
|
60
55
|
labelColor: @pass.label_color,
|
61
|
-
|
62
|
-
|
56
|
+
locations: @pass.locations,
|
57
|
+
logoText: @pass.logo_text,
|
58
|
+
organizationName: @pass.organization_name,
|
63
59
|
passTypeIdentifier: @pass.pass_type_identifier,
|
64
|
-
|
60
|
+
serialNumber: @pass.serial_number,
|
61
|
+
sharingProhibited: @pass.sharing_prohibited,
|
62
|
+
suppressStripShine: @pass.suppress_strip_shine,
|
63
|
+
voided: @pass.voided,
|
64
|
+
webServiceURL: @pass.web_service_url
|
65
65
|
}
|
66
66
|
|
67
67
|
pass[:maxDistance] = @pass.max_distance if @pass.max_distance
|
68
68
|
|
69
|
+
# If the newer barcodes attribute has been used, then
|
70
|
+
# include the list of barcodes, otherwise fall back to
|
71
|
+
# the original barcode attribute
|
72
|
+
barcodes = @pass.barcodes || []
|
73
|
+
if barcodes.empty?
|
74
|
+
pass[:barcode] = @pass.barcode
|
75
|
+
else
|
76
|
+
pass[:barcodes] = @pass.barcodes
|
77
|
+
end
|
78
|
+
|
79
|
+
pass[:appLaunchURL] = @pass.app_launch_url if @pass.app_launch_url
|
80
|
+
pass[:associatedStoreIdentifiers] = @pass.associated_store_identifiers unless @pass.associated_store_identifiers.empty?
|
81
|
+
pass[:beacons] = @pass.beacons unless @pass.beacons.empty?
|
82
|
+
pass[:boardingPass] = @pass.boarding_pass if @pass.boarding_pass
|
83
|
+
pass[:coupon] = @pass.coupon if @pass.coupon
|
84
|
+
pass[:eventTicket] = @pass.event_ticket if @pass.event_ticket
|
85
|
+
pass[:expirationDate] = @pass.expiration_date if @pass.expiration_date
|
86
|
+
pass[:generic] = @pass.generic if @pass.generic
|
87
|
+
pass[:groupingIdentifier] = @pass.grouping_identifier if @pass.grouping_identifier
|
88
|
+
pass[:nfc] = @pass.nfc if @pass.nfc
|
89
|
+
pass[:relevantDate] = @pass.relevant_date if @pass.relevant_date
|
90
|
+
pass[:semantics] = @pass.semantics if @pass.semantics
|
91
|
+
pass[:store_card] = @pass.store_card if @pass.store_card
|
92
|
+
pass[:userInfo] = @pass.user_info if @pass.user_info
|
93
|
+
|
69
94
|
pass[@pass.pass_type] = {
|
70
95
|
headerFields: @pass.header_fields,
|
71
96
|
primaryFields: @pass.primary_fields,
|
data/lib/passkit/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: passkit
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.6.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Alessandro Rodi
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2024-01-19 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rails
|