passkit 0.7.0 → 0.8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: a0b38c2c63123caf5195b6ac2e319088a7b09b85b407c773fa6301d12afe2e93
4
- data.tar.gz: bae23beda0bc05e54cad0509697a94e1afa3422bee4f962d3fe51e25e39dbda0
3
+ metadata.gz: 759d9f1d6698e06c21d68d76e55edfa52f4e6e687148b2e553709471158597db
4
+ data.tar.gz: 90453db3b78892ab6ec2df6466288242a23b782b7524734c92bf08f057fbc032
5
5
  SHA512:
6
- metadata.gz: 21618ddd7bf862cff4ce94fece9d5881d9981a5c162ea4ce86a05047542c4f99bc492683e28f9c101e426a3357810eb4872a63d861716e3a2fbaf86feb3db527
7
- data.tar.gz: af5a69f49077ebca8e4645ce24e564db926b1c7052a84ea98f09649f28dd7d9bf49a96df511aadc0b34a4c4134bc3bc783615742341369e7645c7b7eacd86b2a
6
+ metadata.gz: f3fa0b1df59c67f5ea94426c9c18bfcfd89aa90ed02a1499fc0e429ad666160a231b6a6b413c8a4399bcc5a8e0285d72d34d4a41e8aca433ca1ff8eb02e5963b
7
+ data.tar.gz: 17f3a2d0abd18a192f52757a1c256ea9d8645dbdba16bdc7aa921e9575194a1ce3c188f2ee698888697a374e9c672bf73c0305c242689897810cd7332aaf51ad
data/.example.env CHANGED
@@ -1,5 +1,5 @@
1
1
  PASSKIT_WEB_SERVICE_HOST=https://localhost:3000
2
- PASSKIT_CERTIFICATE_KEY=path/to/certificate.key
2
+ PASSKIT_CERTIFICATE_KEY=theCertPassword
3
3
  PASSKIT_PRIVATE_P12_CERTIFICATE=path/to/certificate.p12
4
4
  PASSKIT_APPLE_INTERMEDIATE_CERTIFICATE=path/to/AppleWWDRCA.cer
5
5
  PASSKIT_APPLE_TEAM_IDENTIFIER=XXXXXXXXXX
data/CHANGELOG.md CHANGED
@@ -1,3 +1,7 @@
1
+ ## [0.8.0]
2
+ - [#36](https://github.com/coorasse/passkit/pull/36): More flexible configuration parameters.
3
+ - [#44](https://github.com/coorasse/passkit/pull/44): Add `stripColor` option.
4
+
1
5
  ## [0.7.0]
2
6
  - [#25](https://github.com/coorasse/passkit/pull/25): Change the label default color to black.
3
7
 
data/README.md CHANGED
@@ -58,6 +58,7 @@ If you followed the installation steps, you already saw that Passkit provides
58
58
  you the tables and ActiveRecord models, and also an engine with the necessary APIs already implemented.
59
59
 
60
60
  Now is your turn. Before proceeding, you need to set these ENV variables:
61
+
61
62
  * `PASSKIT_WEB_SERVICE_HOST`
62
63
  * `PASSKIT_CERTIFICATE_KEY`
63
64
  * `PASSKIT_PRIVATE_P12_CERTIFICATE`
@@ -68,6 +69,26 @@ Now is your turn. Before proceeding, you need to set these ENV variables:
68
69
  We have a [specific guide on how to get all these](docs/passkit_environment_variables.md), please follow it.
69
70
  You cannot start using this library without these variables set, and we cannot do the work for you.
70
71
 
72
+ Alternatively, you can configure passkit with an initializer, where you can use environment variables, Rails secrets,
73
+ or any other source for the required credentials:
74
+
75
+ ```ruby
76
+ Passkit.configure do |config|
77
+ # Required, no defaults
78
+ config.apple_team_identifier = "dummy ID"
79
+ config.certificate_key = "dummy key"
80
+ config.private_p12_certificate = "path/to/file"
81
+ config.apple_intermediate_certificate = "path/to/file"
82
+ config.pass_type_identifier = "pass.com.some.id"
83
+
84
+ # Optional, defaults shown
85
+ config.dashboard_username = nil
86
+ config.dashboard_password = nil
87
+ config.skip_verification = false # Unless true, throws exceptions on startup when a required configuration is missing
88
+ config.web_service_host = "https://localhost:3000"
89
+ config.available_passes = { "Passkit::ExampleStoreCard" => -> {} }
90
+ end
91
+
71
92
  ## Usage
72
93
 
73
94
  If you followed the installation steps and you have the ENV variables set, we can start looking at what is provided for you.
@@ -128,22 +149,34 @@ You can define colors, fields and texts. You can also define the logo and the ba
128
149
  You should place the images in a 'private/passkit/<your_downcased_passname>' folder.
129
150
  There is a [dummy app in the gem](test/dummy) that you can use to check how to create your own Wallet Passes.
130
151
 
152
+ Full documentation for image specifications is on Apple's
153
+ [Pass Design and Creation](https://developer.apple.com/library/archive/documentation/UserExperience/Conceptual/PassKit_PG/Creating.html)
154
+ page. Naming the file according to convetion and putting it in 'private/passkit/<your_downcased_passname>' is all that's needed for it
155
+ to be included in the pass.
156
+
131
157
  ### Serve your Wallet Pass
132
158
 
133
- Use the [Passkit::UrlGenerator](lib/passkit/url_generator.rb) to generate the URL to serve your Wallet Pass.
134
- You can initialize it with:
159
+ Use the [Passkit::UrlGenerator](lib/passkit/url_generator.rb) to generate the URL to serve your Wallet Pass.
160
+ For one pass, you can initialize it with:
135
161
 
136
162
  ```ruby
137
163
  Passkit::UrlGenerator.new(Passkit::MyPass, User.find(1))
138
164
  ```
139
165
 
166
+ For one passes, you can initialize it with:
167
+
168
+ ```ruby
169
+ Passkit::UrlGenerator.new(Passkit::UserTicket, User.find(1), :tickets)
170
+ ```
171
+ (this presumes you have `User.find(1).tickets` would return the ticket records)
172
+
140
173
  and then use `.android` or `.ios` to get the URL to serve the Wallet Pass.
141
174
  Again, check the example mailer included in the gem to see how to use it.
142
175
 
143
176
  ## Debug issues
144
177
 
145
- * On Mac, open the `Console.app` to view the errors.
146
- * Check the logs on http://localhost:3000/passkit/logs
178
+ * On Mac, you can open the *.pkpass files with "Pass Viewer". Open the `Console.app` to log possible error messages and filter by "Pass Viewer" process.
179
+ * Check the logs on http://localhost:3000/passkit/dashboard/logs
147
180
  * In case of error "The passTypeIdentifier or teamIdentifier provided may not match your certificate,
148
181
  or the certificate trust chain could not be verified." the certificate (p12) might be expired.
149
182
 
@@ -5,7 +5,18 @@ module Passkit
5
5
  before_action :decrypt_payload, only: :create
6
6
 
7
7
  def create
8
- send_file(fetch_pass(@payload), type: "application/vnd.apple.pkpass", disposition: "attachment")
8
+ set_generator
9
+
10
+ if @generator && @payload[:collection_name].present?
11
+ files = @generator.public_send(@payload[:collection_name]).collect do |collection_item|
12
+ Passkit::Factory.create_pass(@payload[:pass_class], collection_item)
13
+ end
14
+ file = Passkit::Generator.compress_passes_files(files)
15
+ send_file(file, type: 'application/vnd.apple.pkpasses', disposition: 'attachment')
16
+ else
17
+ file = Passkit::Factory.create_pass(@payload[:pass_class], @generator)
18
+ send_file(file, type: 'application/vnd.apple.pkpass', disposition: 'attachment')
19
+ end
9
20
  end
10
21
 
11
22
  # @return If request is authorized, returns HTTP status 200 with a payload of the pass data.
@@ -44,13 +55,13 @@ module Passkit
44
55
  end
45
56
  end
46
57
 
47
- def fetch_pass(payload)
48
- generator = nil
49
- if payload[:generator_class].present? && payload[:generator_id].present?
50
- generator_class = payload[:generator_class].constantize
51
- generator = generator_class.find(payload[:generator_id])
52
- end
53
- Passkit::Factory.create_pass(payload[:pass_class], generator)
58
+ def set_generator
59
+ @generator = nil
60
+
61
+ return unless @payload[:generator_class].present? && @payload[:generator_id].present?
62
+
63
+ generator_class = @payload[:generator_class].constantize
64
+ @generator = generator_class.find(@payload[:generator_id])
54
65
  end
55
66
  end
56
67
  end
@@ -17,14 +17,11 @@ module Passkit
17
17
  :barcodes,
18
18
  :beacons,
19
19
  :boarding_pass,
20
- :coupon,
21
20
  :description,
22
- :event_ticket,
23
21
  :expiration_date,
24
22
  :file_name,
25
23
  :foreground_color,
26
24
  :format_version,
27
- :generic,
28
25
  :grouping_identifier,
29
26
  :header_fields,
30
27
  :label_color,
@@ -42,7 +39,7 @@ module Passkit
42
39
  :secondary_fields,
43
40
  :semantics,
44
41
  :sharing_prohibited,
45
- :store_card,
42
+ :strip_color
46
43
  :suppress_strip_shine,
47
44
  :user_info,
48
45
  :voided,
@@ -2,31 +2,30 @@
2
2
  <h1>Passkit Passes</h1>
3
3
  <%= render 'shared/passkit/navigation' %>
4
4
  </header>
5
-
6
5
  <main>
7
6
  <h2>Last 100 passes and registered devices</h2>
8
7
  <table>
9
8
  <thead>
10
- <th>Created at</th>
11
- <th>Generator</th>
12
- <th>Pass Class</th>
13
- <th>Devices</th>
9
+ <th>Created at</th>
10
+ <th>Generator</th>
11
+ <th>Pass Class</th>
12
+ <th>Devices</th>
14
13
  </thead>
15
14
  <tbody>
16
- <% @passes.each do |pass| %>
17
- <tr>
18
- <td><%= I18n.l(pass.created_at) %></td>
19
- <td><%= pass.generator.to_s %></td>
20
- <td><%= pass.klass %></td>
21
- <td>
22
- <% pass.devices.each do |device| %>
23
- <div>
15
+ <% @passes.each do |pass| %>
16
+ <tr>
17
+ <td><%= I18n.l(pass.created_at) %></td>
18
+ <td><%= pass.generator.class.name %> - <%= pass.generator.id %></td>
19
+ <td><%= pass.klass %></td>
20
+ <td>
21
+ <% pass.devices.each do |device| %>
22
+ <div>
24
23
  <%= device.push_token %>
25
- </div>
26
- <% end %>
27
- </td>
28
- </tr>
29
- <% end %>
24
+ </div>
25
+ <% end %>
26
+ </td>
27
+ </tr>
28
+ <% end %>
30
29
  </tbody>
31
30
  </table>
32
31
  </main>
@@ -2,14 +2,14 @@
2
2
  Here is an example of an email message that contains a link to Download a Wallet Pass.
3
3
  </p>
4
4
  <p>
5
- <a href="<%=@passkit_url_generator.ios %>">
6
- <%=image_tag 'passkit/add_to_apple_wallet_en.png', style: 'width: 150px;' %>
7
- Download a iOS Wallet Pass
5
+ <a href="<%= @passkit_url_generator.ios %>">
6
+ <%= image_tag 'passkit/add_to_apple_wallet_en.png', style: 'width: 150px;' %>
7
+ Download an iOS Wallet Pass
8
8
  </a>
9
9
  </p>
10
10
  <p>
11
11
  <a href="<%=@passkit_url_generator.android %>">
12
- <%=image_tag 'https://walletpasses.io/badges/badge_web_black_en@3x.png', style: 'width: 150px;' %>
12
+ <%= image_tag 'passkit/add_to_walletpass_en.png', style: 'width: 150px;' %>
13
13
  Download an Android Wallet Pass
14
14
  </a>
15
15
  </p>
@@ -12,7 +12,7 @@ In production, it will simply be your domain name, but in development you can us
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
+ You might want to choose the one with the longest expiration date. PASSKIT_APPLE_INTERMEDIATE_CERTIFICATE is the path to the certificate.
16
16
 
17
17
  ### `PASSKIT_APPLE_TEAM_IDENTIFIER`
18
18
 
@@ -32,7 +32,10 @@ Head to your Apple Developers console and generate a new certificate.
32
32
 
33
33
  The identifier is the `PASSKIT_PASS_TYPE_IDENTIFIER` variable.
34
34
 
35
- Now, create a certificate signing request: https://help.apple.com/developer-account/#/devbfa00fef7
35
+ **Note**: When renewing your certificate, make sure that this identifier stays the same as before. Changing this identifier will
36
+ require existing passes to be regenerated, as they will otherwise no longer be updateable via the web service URL.
37
+
38
+ Now, create a certificate signing request: https://developer.apple.com/help/account/create-certificates/create-a-certificate-signing-request/
36
39
 
37
40
  And create the certificate:
38
41
 
@@ -5,15 +5,15 @@ module Passkit
5
5
  end
6
6
 
7
7
  def format_version
8
- ENV["PASSKIT_FORMAT_VERSION"] || 1
8
+ Passkit.configuration.format_version
9
9
  end
10
10
 
11
11
  def apple_team_identifier
12
- ENV["PASSKIT_APPLE_TEAM_IDENTIFIER"] || raise(Error.new("Missing environment variable: PASSKIT_APPLE_TEAM_IDENTIFIER"))
12
+ Passkit.configuration.apple_team_identifier
13
13
  end
14
14
 
15
15
  def pass_type_identifier
16
- ENV["PASSKIT_PASS_TYPE_IDENTIFIER"] || raise(Error.new("Missing environment variable: PASSKIT_PASS_TYPE_IDENTIFIER"))
16
+ Passkit.configuration.pass_type_identifier
17
17
  end
18
18
 
19
19
  def language
@@ -43,34 +43,48 @@ module Passkit
43
43
  end
44
44
 
45
45
  def web_service_url
46
- raise Error.new("Missing environment variable: PASSKIT_WEB_SERVICE_HOST") unless ENV["PASSKIT_WEB_SERVICE_HOST"]
47
- "#{ENV["PASSKIT_WEB_SERVICE_HOST"]}/passkit/api"
46
+ "#{Passkit.configuration.web_service_host}/passkit/api"
48
47
  end
49
48
 
49
+ # The foreground color, used for the values of fields shown on the front of the pass.
50
50
  def foreground_color
51
51
  # black
52
52
  "rgb(0, 0, 0)"
53
53
  end
54
54
 
55
+ # The strip color, used to print the text over the background image.
56
+ def strip_color
57
+ "rgb(0, 0, 0)"
58
+ end
59
+
60
+ # The background color, used for the background of the front and back of the pass.
61
+ # If you provide a background image, any background color is ignored.
55
62
  def background_color
56
63
  # white
57
64
  "rgb(255, 255, 255)"
58
65
  end
59
66
 
67
+ # The label color, used for the labels of fields shown on the front of the pass.
60
68
  def label_color
61
69
  # black
62
70
  "rgb(0, 0, 0)"
63
71
  end
64
72
 
73
+ # The organization name is displayed on the lock screen when your pass is relevant and by apps such as Mail which
74
+ # act as a conduit for passes. The value for the organizationName key in the pass specifies the organization name.
75
+ # Choose a name that users recognize and associate with your organization or company.
65
76
  def organization_name
66
77
  "Passkit"
67
78
  end
68
79
 
80
+ # The description lets VoiceOver make your pass accessible to blind and low-vision users. The value for the
81
+ # description key in the pass specifies the description.
82
+ # @see https://developer.apple.com/library/archive/documentation/UserExperience/Conceptual/PassKit_PG/Creating.html
69
83
  def description
70
84
  "A basic description for a pass"
71
85
  end
72
86
 
73
- # A pass can have up to ten relevant locations
87
+ # An array of up to 10 latitudes and longitudes. iOS uses these locations to determine when to display the pass on the lock screen
74
88
  #
75
89
  # @see https://developer.apple.com/library/archive/documentation/UserExperience/Conceptual/PassKit_PG/Creating.html
76
90
  def locations
@@ -85,7 +99,8 @@ module Passkit
85
99
  def add_other_files(path)
86
100
  end
87
101
 
88
- # Distance in meters from locations; if blank uses pass default
102
+ # Distance in meters from locations; if blank uses pass default.
103
+ # The system uses the smaller of either this distance or the default distance.
89
104
  def max_distance
90
105
  end
91
106
 
@@ -118,30 +133,19 @@ module Passkit
118
133
 
119
134
  # Information specific to a boarding pass
120
135
  # Returns a hash representing Pass.BoardingPass
136
+ # https://developer.apple.com/documentation/walletpasses/pass/boardingpass
137
+ # i.e {transitType: 'PKTransitTypeGeneric'}
121
138
  def boarding_pass
122
- end
123
-
124
- # Information specific to a coupon
125
- # Returns a hash representing Pass.Coupon
126
- def coupon
127
- end
128
-
129
- # Information specific to an event ticket
130
- # Returns a hash representing Pass.EventTicket
131
- def event_ticket
139
+ {}
132
140
  end
133
141
 
134
142
  # Date and time the pass expires, must include
135
143
  # days, hours and minutes (seconds are optional)
136
- # Returns a String representing the date and time in W3C format
144
+ # Returns a String representing the date and time in W3C format ('%Y-%m-%dT%H:%M:%S%:z')
145
+ # For example, 1980-05-07T10:30-05:00.
137
146
  def expiration_date
138
147
  end
139
148
 
140
- # Information specific to a generic pass
141
- # Returns a hash representing Pass.Generic
142
- def generic
143
- end
144
-
145
149
  # A key to identify group multiple passes together
146
150
  # (e.g. a number of boarding passes for the same trip)
147
151
  # Returns a String
@@ -157,7 +161,7 @@ module Passkit
157
161
  # Date and time when the pass becomes relevant and should be
158
162
  # displayed, must include days, hours and minutes
159
163
  # (seconds are optional)
160
- # Returns a String representing the date and time in W3C format
164
+ # Returns a String representing the date and time in W3C format ('%Y-%m-%dT%H:%M:%S%:z')
161
165
  def relevant_date
162
166
  end
163
167
 
@@ -167,11 +171,6 @@ module Passkit
167
171
  def semantics
168
172
  end
169
173
 
170
- # Information specific to a store card
171
- # Returns a hash representing Pass.StoreCard
172
- def store_card
173
- end
174
-
175
174
  # Display the strip image without a shine effect
176
175
  # Returns a boolean
177
176
  def suppress_strip_shine
@@ -58,17 +58,13 @@ module Passkit
58
58
  "Loyalty Card"
59
59
  end
60
60
 
61
- def app_launch_url
62
- "https://github.com/coorasse/passkit"
63
- end
64
-
65
61
  def relevant_date
66
- Time.current.strftime("%Y-%m-%dT%H:%M:%S%z")
62
+ Time.current.strftime('%Y-%m-%dT%H:%M:%S%:z')
67
63
  end
68
64
 
69
65
  def expiration_date
70
66
  # Expire the pass tomorrow
71
- (Time.current + 60*60*24).strftime("%Y-%m-%dT%H:%M:%S%z")
67
+ (Time.current + 1.day).strftime('%Y-%m-%dT%H:%M:%S%:z')
72
68
  end
73
69
 
74
70
  def semantics
@@ -1,6 +1,7 @@
1
1
  module Passkit
2
2
  class Factory
3
3
  class << self
4
+ # generator is an optional ActiveRecord object, the application data for the pass
4
5
  def create_pass(pass_class, generator = nil)
5
6
  pass = Passkit::Pass.create!(klass: pass_class, generator: generator)
6
7
  Passkit::Generator.new(pass).generate_and_sign
@@ -23,6 +23,19 @@ module Passkit
23
23
  compress_pass_file
24
24
  end
25
25
 
26
+ def self.compress_passes_files(files)
27
+ zip_path = TMP_FOLDER.join("#{SecureRandom.uuid}.pkpasses")
28
+ zipped_file = File.open(zip_path, "w")
29
+
30
+ Zip::OutputStream.open(zipped_file.path) do |z|
31
+ files.each do |file|
32
+ z.put_next_entry(File.basename(file))
33
+ z.print File.read(file)
34
+ end
35
+ end
36
+ zip_path
37
+ end
38
+
26
39
  private
27
40
 
28
41
  def check_necessary_files
@@ -59,6 +72,7 @@ module Passkit
59
72
  passTypeIdentifier: @pass.pass_type_identifier,
60
73
  serialNumber: @pass.serial_number,
61
74
  sharingProhibited: @pass.sharing_prohibited,
75
+ stripColor: @pass.strip_color,
62
76
  suppressStripShine: @pass.suppress_strip_shine,
63
77
  voided: @pass.voided,
64
78
  webServiceURL: @pass.web_service_url
@@ -75,20 +89,14 @@ module Passkit
75
89
  else
76
90
  pass[:barcodes] = @pass.barcodes
77
91
  end
78
-
79
92
  pass[:appLaunchURL] = @pass.app_launch_url if @pass.app_launch_url
80
93
  pass[:associatedStoreIdentifiers] = @pass.associated_store_identifiers unless @pass.associated_store_identifiers.empty?
81
94
  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
95
  pass[:expirationDate] = @pass.expiration_date if @pass.expiration_date
86
- pass[:generic] = @pass.generic if @pass.generic
87
96
  pass[:groupingIdentifier] = @pass.grouping_identifier if @pass.grouping_identifier
88
97
  pass[:nfc] = @pass.nfc if @pass.nfc
89
98
  pass[:relevantDate] = @pass.relevant_date if @pass.relevant_date
90
99
  pass[:semantics] = @pass.semantics if @pass.semantics
91
- pass[:store_card] = @pass.store_card if @pass.store_card
92
100
  pass[:userInfo] = @pass.user_info if @pass.user_info
93
101
 
94
102
  pass[@pass.pass_type] = {
@@ -99,11 +107,11 @@ module Passkit
99
107
  backFields: @pass.back_fields
100
108
  }
101
109
 
110
+ pass[:boardingPass].merge(@pass.boarding_pass) if @pass.pass_type == :boardingPass && @pass.boarding_pass
111
+
102
112
  File.write(@temporary_path.join("pass.json"), pass.to_json)
103
113
  end
104
114
 
105
- # rubocop:enable Metrics/AbcSize
106
-
107
115
  def generate_json_manifest
108
116
  manifest = {}
109
117
  Dir.glob(@temporary_path.join("**")).each do |file|
@@ -114,14 +122,18 @@ module Passkit
114
122
  File.write(@manifest_url, manifest.to_json)
115
123
  end
116
124
 
117
- CERTIFICATE = Rails.root.join(ENV["PASSKIT_PRIVATE_P12_CERTIFICATE"])
118
- INTERMEDIATE_CERTIFICATE = Rails.root.join(ENV["PASSKIT_APPLE_INTERMEDIATE_CERTIFICATE"])
119
- CERTIFICATE_PASSWORD = ENV["PASSKIT_CERTIFICATE_KEY"]
125
+ def certificate_path
126
+ Rails.root.join(Passkit.configuration.private_p12_certificate)
127
+ end
128
+
129
+ def intermediate_certificate_path
130
+ Rails.root.join(Passkit.configuration.apple_intermediate_certificate)
131
+ end
120
132
 
121
133
  # :nocov:
122
134
  def sign_manifest
123
- p12_certificate = OpenSSL::PKCS12.new(File.read(CERTIFICATE), CERTIFICATE_PASSWORD)
124
- intermediate_certificate = OpenSSL::X509::Certificate.new(File.read(INTERMEDIATE_CERTIFICATE))
135
+ p12_certificate = OpenSSL::PKCS12.new(File.read(certificate_path), Passkit.configuration.certificate_key)
136
+ intermediate_certificate = OpenSSL::X509::Certificate.new(File.read(intermediate_certificate_path))
125
137
 
126
138
  flag = OpenSSL::PKCS7::DETACHED | OpenSSL::PKCS7::BINARY
127
139
  signed = OpenSSL::PKCS7.sign(p12_certificate.certificate,
@@ -2,17 +2,18 @@ module Passkit
2
2
  class PayloadGenerator
3
3
  VALIDITY = 30.days
4
4
 
5
- def self.encrypted(pass_class, generator = nil)
6
- UrlEncrypt.encrypt(hash(pass_class, generator))
5
+ def self.encrypted(pass_class, generator = nil, collection_name = nil)
6
+ UrlEncrypt.encrypt(hash(pass_class, generator, collection_name))
7
7
  end
8
8
 
9
- def self.hash(pass_class, generator = nil)
9
+ def self.hash(pass_class, generator = nil, collection_name = nil)
10
10
  valid_until = VALIDITY.from_now
11
11
 
12
12
  {valid_until: valid_until,
13
13
  generator_class: generator&.class&.name,
14
14
  generator_id: generator&.id,
15
- pass_class: pass_class.name}
15
+ pass_class: pass_class.name,
16
+ collection_name: collection_name}
16
17
  end
17
18
  end
18
19
  end
@@ -2,9 +2,9 @@ module Passkit
2
2
  class UrlGenerator
3
3
  include Passkit::Engine.routes.url_helpers
4
4
 
5
- def initialize(pass_class, generator = nil)
6
- @url = passes_api_url(host: ENV["PASSKIT_WEB_SERVICE_HOST"],
7
- payload: PayloadGenerator.encrypted(pass_class, generator))
5
+ def initialize(pass_class, generator = nil, collection_name = nil)
6
+ @url = passes_api_url(host: Passkit.configuration.web_service_host,
7
+ payload: PayloadGenerator.encrypted(pass_class, generator, collection_name))
8
8
  end
9
9
 
10
10
  def ios
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Passkit
4
- VERSION = "0.7.0"
4
+ VERSION = "0.8.0"
5
5
  end
data/lib/passkit.rb CHANGED
@@ -18,6 +18,11 @@ module Passkit
18
18
  def self.configure
19
19
  self.configuration ||= Configuration.new
20
20
  yield(configuration) if block_given?
21
+ configuration.verify!
22
+ end
23
+
24
+ def self.configured?
25
+ self.configuration&.configured?
21
26
  end
22
27
 
23
28
  class Configuration
@@ -27,11 +32,24 @@ module Passkit
27
32
  :private_p12_certificate,
28
33
  :apple_intermediate_certificate,
29
34
  :apple_team_identifier,
30
- :pass_type_identifier
35
+ :pass_type_identifier,
36
+ :dashboard_username,
37
+ :dashboard_password,
38
+ :format_version,
39
+ :skip_verification
40
+
41
+ REQUIRED_ATTRIBUTES = %i[
42
+ web_service_host
43
+ certificate_key
44
+ private_p12_certificate
45
+ apple_intermediate_certificate
46
+ apple_team_identifier
47
+ pass_type_identifier
48
+ ]
31
49
 
32
50
  DEFAULT_AUTHENTICATION = proc do
33
51
  authenticate_or_request_with_http_basic("Passkit Dashboard. Login required") do |username, password|
34
- username == ENV["PASSKIT_DASHBOARD_USERNAME"] && password == ENV["PASSKIT_DASHBOARD_PASSWORD"]
52
+ username == Passkit.configuration.dashboard_username && password == Passkit.configuration.dashboard_password
35
53
  end
36
54
  end
37
55
  def authenticate_dashboard_with(&block)
@@ -40,14 +58,34 @@ module Passkit
40
58
  end
41
59
 
42
60
  def initialize
43
- @available_passes = {"Passkit::ExampleStoreCard" => -> {}}
44
- @web_service_host = ENV["PASSKIT_WEB_SERVICE_HOST"] || (raise "Please set PASSKIT_WEB_SERVICE_HOST")
45
- raise("PASSKIT_WEB_SERVICE_HOST must start with https://") unless @web_service_host.start_with?("https://")
46
- @certificate_key = ENV["PASSKIT_CERTIFICATE_KEY"] || (raise "Please set PASSKIT_CERTIFICATE_KEY")
47
- @private_p12_certificate = ENV["PASSKIT_PRIVATE_P12_CERTIFICATE"] || (raise "Please set PASSKIT_PRIVATE_P12_CERTIFICATE")
48
- @apple_intermediate_certificate = ENV["PASSKIT_APPLE_INTERMEDIATE_CERTIFICATE"] || (raise "Please set PASSKIT_APPLE_INTERMEDIATE_CERTIFICATE")
49
- @apple_team_identifier = ENV["PASSKIT_APPLE_TEAM_IDENTIFIER"] || (raise "Please set PASSKIT_APPLE_TEAM_IDENTIFIER")
50
- @pass_type_identifier = ENV["PASSKIT_PASS_TYPE_IDENTIFIER"] || (raise "Please set PASSKIT_PASS_TYPE_IDENTIFIER")
61
+ # Required
62
+ @certificate_key = ENV["PASSKIT_CERTIFICATE_KEY"]
63
+ @private_p12_certificate = ENV["PASSKIT_PRIVATE_P12_CERTIFICATE"]
64
+ @apple_intermediate_certificate = ENV["PASSKIT_APPLE_INTERMEDIATE_CERTIFICATE"]
65
+ @apple_team_identifier = ENV["PASSKIT_APPLE_TEAM_IDENTIFIER"]
66
+ @pass_type_identifier = ENV["PASSKIT_PASS_TYPE_IDENTIFIER"]
67
+
68
+ # Optional
69
+ @skip_verification = false
70
+ @web_service_host = ENV["PASSKIT_WEB_SERVICE_HOST"] || "https://localhost:3000"
71
+ @available_passes = { "Passkit::ExampleStoreCard" => -> {} }
72
+ @format_version = ENV["PASSKIT_FORMAT_VERSION"] || 1
73
+ @dashboard_username = ENV["PASSKIT_DASHBOARD_USERNAME"]
74
+ @dashboard_password = ENV["PASSKIT_DASHBOARD_PASSWORD"]
75
+ end
76
+
77
+ def configured?
78
+ REQUIRED_ATTRIBUTES.all? { |attr| send(attr).present? }
79
+ end
80
+
81
+ def verify!
82
+ return if skip_verification
83
+
84
+ REQUIRED_ATTRIBUTES.each do |attr|
85
+ raise Error, "Please set #{attr.upcase}" unless send(attr).present?
86
+ end
87
+
88
+ raise Error, "PASSKIT_WEB_SERVICE_HOST must start with https://" unless web_service_host.start_with?("https://")
51
89
  end
52
90
  end
53
91
  end
metadata CHANGED
@@ -1,14 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: passkit
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.7.0
4
+ version: 0.8.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Alessandro Rodi
8
- autorequire:
9
8
  bindir: exe
10
9
  cert_chain: []
11
- date: 2024-04-09 00:00:00.000000000 Z
10
+ date: 1980-01-02 00:00:00.000000000 Z
12
11
  dependencies:
13
12
  - !ruby/object:Gem::Dependency
14
13
  name: rails
@@ -222,7 +221,6 @@ metadata:
222
221
  source_code_uri: https://github.com/coorasse/passkit
223
222
  changelog_uri: https://github.com/coorasse/passkit/blob/master/CHANGELOG.md
224
223
  funding_uri: https://github.com/sponsors/coorasse
225
- post_install_message:
226
224
  rdoc_options: []
227
225
  require_paths:
228
226
  - lib
@@ -237,8 +235,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
237
235
  - !ruby/object:Gem::Version
238
236
  version: '0'
239
237
  requirements: []
240
- rubygems_version: 3.2.22
241
- signing_key:
238
+ rubygems_version: 3.6.9
242
239
  specification_version: 4
243
240
  summary: Serve Wallet Passes for iOS and Android directly from your Rails app
244
241
  test_files: []