passkit 0.8.2 → 0.9.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: c3980bb0fab949c93cc8821dd050f784f97f6a20b3ad9b16ac2c0a73a930529f
4
- data.tar.gz: d0a4be1ab9846f71e4bc7806bb54a110519785c4d2086e33106eb83d5f0e06af
3
+ metadata.gz: b483356d4bcfb7898d15381b4ac43899fbc8b147965e6579110c562a19bf0a21
4
+ data.tar.gz: d529619e1ebdd0ae04943b0fe07f1bc0c43df6f976218ed8c472ad50da1dcf99
5
5
  SHA512:
6
- metadata.gz: 5b9cd2a244f8e5b7ffb9e14d18a6004080ea55e0b302f25862d2f23bd28ce7277ca062436100f6aeec638f0827bf78674ef63c22d7c82c852e3c32be139461ab
7
- data.tar.gz: 5acf99ef60dc001f047e89771431bdb46fcf4417e70f76a9859df94520805a6b355109de4cc0eee67601ff5047f4825b6b753865120e25413864ce1480242933
6
+ metadata.gz: bee3e475d2beaed1f9305613893c9aee7cf9cbfee86e9ae95f46348f0d0e0a13f82b9428147f5132f5793d07c551b892104f3f9fac7478d50924183e03c344cb
7
+ data.tar.gz: 8e614ada638617a10ac3ff807f842e5ceef98d17048a283571809562872cd256ac2de7a05ae9f154eb6e8baf4874c50d03692f73d0719dc41d5d6aedd2932ca0
data/CHANGELOG.md CHANGED
@@ -1,3 +1,11 @@
1
+ ## [0.9.0]
2
+ - [#50](https://github.com/coorasse/passkit/pull/50): **Breaking:** require rubyzip 3.4 or later, which fixes CVE-2026-85396, and Ruby 3.2 or later.
3
+ - [#47](https://github.com/coorasse/passkit/pull/47): Remove the generator's working directory once the `.pkpass` is built, and delete generated archives after sending them, so `tmp/passkit` no longer grows with every download.
4
+ - [#48](https://github.com/coorasse/passkit/pull/48): Answer `304 Not Modified` before generating and signing the pass when `If-Modified-Since` shows the device already has the current version.
5
+
6
+ ## [0.8.3]
7
+ - Exclude development and test files from the packaged gem.
8
+
1
9
  ## [0.8.2]
2
10
  - Set up the Semaphore CI pipeline with a manual promotion to release the gem.
3
11
  - Self-signed certificates for the test suite, so it runs without an Apple Developer certificate.
data/README.md CHANGED
@@ -173,6 +173,11 @@ Passkit::UrlGenerator.new(Passkit::UserTicket, User.find(1), :tickets)
173
173
  and then use `.android` or `.ios` to get the URL to serve the Wallet Pass.
174
174
  Again, check the example mailer included in the gem to see how to use it.
175
175
 
176
+ If you generate passes yourself with `Passkit::Factory.create_pass` or `Passkit::Generator#generate_and_sign`
177
+ instead of going through the bundled controllers, note that the returned `.pkpass` lives in `tmp/passkit`.
178
+ The bundled controllers delete it once it has been sent; if you serve it yourself, do the same, otherwise the
179
+ folder grows by one archive per download.
180
+
176
181
  ## Debug issues
177
182
 
178
183
  * 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.
@@ -0,0 +1,15 @@
1
+ module Passkit
2
+ # Passes are generated into tmp/passkit. Send the archive's contents and
3
+ # delete the file, so the folder does not grow by one archive per download.
4
+ module PassDelivery
5
+ extend ActiveSupport::Concern
6
+
7
+ private
8
+
9
+ def send_pass_file(path, type:, filename: File.basename(path))
10
+ send_data File.binread(path), type: type, disposition: "attachment", filename: filename
11
+ ensure
12
+ FileUtils.rm_f(path)
13
+ end
14
+ end
15
+ end
@@ -2,6 +2,8 @@ module Passkit
2
2
  module Api
3
3
  module V1
4
4
  class PassesController < ActionController::API
5
+ include Passkit::PassDelivery
6
+
5
7
  before_action :decrypt_payload, only: :create
6
8
 
7
9
  def create
@@ -11,11 +13,15 @@ module Passkit
11
13
  files = @generator.public_send(@payload[:collection_name]).collect do |collection_item|
12
14
  Passkit::Factory.create_pass(@payload[:pass_class], collection_item)
13
15
  end
14
- file = Passkit::Generator.compress_passes_files(files)
15
- send_file(file, type: "application/vnd.apple.pkpasses", disposition: "attachment")
16
+ begin
17
+ bundle = Passkit::Generator.compress_passes_files(files)
18
+ ensure
19
+ files.each { |file| FileUtils.rm_f(file) }
20
+ end
21
+ send_pass_file(bundle, type: "application/vnd.apple.pkpasses")
16
22
  else
17
23
  file = Passkit::Factory.create_pass(@payload[:pass_class], @generator)
18
- send_file(file, type: "application/vnd.apple.pkpass", disposition: "attachment")
24
+ send_pass_file(file, type: "application/vnd.apple.pkpass")
19
25
  end
20
26
  end
21
27
 
@@ -35,19 +41,24 @@ module Passkit
35
41
  return
36
42
  end
37
43
 
38
- pass_output_path = Passkit::Generator.new(pass).generate_and_sign
39
-
40
44
  response.headers["last-modified"] = pass.last_update.httpdate
41
- if request.headers["If-Modified-Since"].nil? ||
42
- (pass.last_update.to_i > Time.zone.parse(request.headers["If-Modified-Since"]).to_i)
43
- send_file(pass_output_path, type: "application/vnd.apple.pkpass", disposition: "attachment")
44
- else
45
- head :not_modified
46
- end
45
+ return head :not_modified unless pass_modified_since?(pass, request.headers["If-Modified-Since"])
46
+
47
+ pass_output_path = Passkit::Generator.new(pass).generate_and_sign
48
+ send_pass_file(pass_output_path, type: "application/vnd.apple.pkpass")
47
49
  end
48
50
 
49
51
  private
50
52
 
53
+ # Wallet sends back the Last-Modified it received with the previous
54
+ # download. When the pass has not changed since, there is nothing to
55
+ # generate or sign.
56
+ def pass_modified_since?(pass, if_modified_since)
57
+ return true if if_modified_since.nil?
58
+
59
+ pass.last_update.to_i > Time.zone.parse(if_modified_since).to_i
60
+ end
61
+
51
62
  def decrypt_payload
52
63
  @payload = Passkit::UrlEncrypt.decrypt(params[:payload])
53
64
  if DateTime.parse(@payload[:valid_until]).past?
@@ -1,6 +1,8 @@
1
1
  module Passkit
2
2
  module Dashboard
3
3
  class PreviewsController < ApplicationController
4
+ include Passkit::PassDelivery
5
+
4
6
  def index
5
7
  end
6
8
 
@@ -8,7 +10,7 @@ module Passkit
8
10
  builder = Passkit.configuration.available_passes[params[:class_name]]
9
11
  path = Factory.create_pass(params[:class_name].constantize, builder.call)
10
12
 
11
- send_file path, type: "application/vnd.apple.pkpass", disposition: "attachment", filename: "pass.pkpass"
13
+ send_pass_file path, type: "application/vnd.apple.pkpass", filename: "pass.pkpass"
12
14
  end
13
15
  end
14
16
  end
@@ -21,17 +21,15 @@ module Passkit
21
21
  generate_json_manifest
22
22
  sign_manifest
23
23
  compress_pass_file
24
+ ensure
25
+ remove_temporary_directory
24
26
  end
25
27
 
26
28
  def self.compress_passes_files(files)
27
29
  zip_path = TMP_FOLDER.join("#{SecureRandom.uuid}.pkpasses")
28
- zipped_file = File.open(zip_path, "w")
29
30
 
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
31
+ Zip::File.open(zip_path, create: true) do |zip|
32
+ files.each { |file| zip.add(File.basename(file), file) }
35
33
  end
36
34
  zip_path
37
35
  end
@@ -49,6 +47,12 @@ module Passkit
49
47
  FileUtils.rm_rf(@temporary_path) if File.directory?(@temporary_path)
50
48
  end
51
49
 
50
+ # Only the .pkpass is returned to the caller; the unpacked files it was
51
+ # built from have no further use once it exists.
52
+ def remove_temporary_directory
53
+ FileUtils.rm_rf(@temporary_path) if @temporary_path
54
+ end
55
+
52
56
  def copy_pass_to_tmp_location
53
57
  FileUtils.cp_r(@pass.pass_path, @temporary_path)
54
58
  end
@@ -148,13 +152,12 @@ module Passkit
148
152
 
149
153
  def compress_pass_file
150
154
  zip_path = TMP_FOLDER.join("#{@pass.file_name}.pkpass")
151
- zipped_file = File.open(zip_path, "w")
155
+ FileUtils.rm_f(zip_path)
152
156
 
153
- Zip::OutputStream.open(zipped_file.path) do |z|
154
- Dir.glob(@temporary_path.join("**")).each do |file|
155
- z.put_next_entry(File.basename(file))
156
- z.print File.read(file)
157
- end
157
+ # Entries added from files have a known size, so rubyzip writes a plain zip without the Zip64 extra fields
158
+ # it adds to streamed entries since 3.0.
159
+ Zip::File.open(zip_path, create: true) do |zip|
160
+ Dir.glob(@temporary_path.join("**")).each { |file| zip.add(File.basename(file), file) }
158
161
  end
159
162
  zip_path
160
163
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Passkit
4
- VERSION = "0.8.2"
4
+ VERSION = "0.9.0"
5
5
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: passkit
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.8.2
4
+ version: 0.9.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Alessandro Rodi
@@ -29,14 +29,14 @@ dependencies:
29
29
  requirements:
30
30
  - - "~>"
31
31
  - !ruby/object:Gem::Version
32
- version: '2.0'
32
+ version: '3.4'
33
33
  type: :runtime
34
34
  prerelease: false
35
35
  version_requirements: !ruby/object:Gem::Requirement
36
36
  requirements:
37
37
  - - "~>"
38
38
  - !ruby/object:Gem::Version
39
- version: '2.0'
39
+ version: '3.4'
40
40
  - !ruby/object:Gem::Dependency
41
41
  name: sqlite3
42
42
  requirement: !ruby/object:Gem::Requirement
@@ -143,17 +143,10 @@ executables: []
143
143
  extensions: []
144
144
  extra_rdoc_files: []
145
145
  files:
146
- - ".env.test"
147
- - ".example.env"
148
- - ".semaphore/release.yml"
149
- - ".semaphore/semaphore.yml"
150
- - ".standard.yml"
151
146
  - CHANGELOG.md
152
147
  - CODE_OF_CONDUCT.md
153
- - Gemfile
154
148
  - LICENSE.txt
155
149
  - README.md
156
- - Rakefile
157
150
  - app/assets/config/passkit_manifest.js
158
151
  - app/assets/images/passkit/add_to_apple_wallet_de.png
159
152
  - app/assets/images/passkit/add_to_apple_wallet_en.png
@@ -163,6 +156,7 @@ files:
163
156
  - app/assets/images/passkit/add_to_walletpass_en.png
164
157
  - app/assets/images/passkit/add_to_walletpass_fr.png
165
158
  - app/assets/images/passkit/add_to_walletpass_it.png
159
+ - app/controllers/concerns/passkit/pass_delivery.rb
166
160
  - app/controllers/passkit/api/v1/logs_controller.rb
167
161
  - app/controllers/passkit/api/v1/passes_controller.rb
168
162
  - app/controllers/passkit/api/v1/registrations_controller.rb
@@ -181,18 +175,7 @@ files:
181
175
  - app/views/passkit/dashboard/previews/index.html.erb
182
176
  - app/views/passkit/example_mailer/example_email.html.erb
183
177
  - app/views/shared/passkit/_navigation.html.erb
184
- - bin/console
185
- - bin/generate_test_certificates
186
- - bin/setup
187
178
  - config/routes.rb
188
- - docs/membership.png
189
- - docs/passkit_environment_variables.md
190
- - docs/step1.png
191
- - docs/step2.png
192
- - docs/step3.png
193
- - docs/step4.png
194
- - docs/step5.png
195
- - docs/wallet.png
196
179
  - lib/generators/passkit/install_generator.rb
197
180
  - lib/generators/templates/create_passkit_tables.rb.tt
198
181
  - lib/generators/templates/passkit.rb
@@ -232,14 +215,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
232
215
  requirements:
233
216
  - - ">="
234
217
  - !ruby/object:Gem::Version
235
- version: 2.6.0
218
+ version: 3.2.0
236
219
  required_rubygems_version: !ruby/object:Gem::Requirement
237
220
  requirements:
238
221
  - - ">="
239
222
  - !ruby/object:Gem::Version
240
223
  version: '0'
241
224
  requirements: []
242
- rubygems_version: 4.0.9
225
+ rubygems_version: 4.0.17
243
226
  specification_version: 4
244
227
  summary: Serve Wallet Passes for iOS and Android directly from your Rails app
245
228
  test_files: []
data/.env.test DELETED
@@ -1,8 +0,0 @@
1
- PASSKIT_WEB_SERVICE_HOST=https://localhost:3000
2
- PASSKIT_CERTIFICATE_KEY=passkit
3
- PASSKIT_PRIVATE_P12_CERTIFICATE=certificates/certificate.p12
4
- PASSKIT_APPLE_INTERMEDIATE_CERTIFICATE=certificates/intermediate.cer
5
- PASSKIT_APPLE_TEAM_IDENTIFIER=XXXXXXXXXX
6
- PASSKIT_PASS_TYPE_IDENTIFIER=pass.com.example.pass
7
- PASSKIT_DASHBOARD_USERNAME=admin
8
- PASSKIT_DASHBOARD_PASSWORD=admin
data/.example.env DELETED
@@ -1,8 +0,0 @@
1
- PASSKIT_WEB_SERVICE_HOST=https://localhost:3000
2
- PASSKIT_CERTIFICATE_KEY=theCertPassword
3
- PASSKIT_PRIVATE_P12_CERTIFICATE=path/to/certificate.p12
4
- PASSKIT_APPLE_INTERMEDIATE_CERTIFICATE=path/to/AppleWWDRCA.cer
5
- PASSKIT_APPLE_TEAM_IDENTIFIER=XXXXXXXXXX
6
- PASSKIT_PASS_TYPE_IDENTIFIER=pass.com.example.pass
7
- PASSKIT_DASHBOARD_USERNAME=admin
8
- PASSKIT_DASHBOARD_PASSWORD=admin
@@ -1,21 +0,0 @@
1
- version: "v1.0"
2
- name: Release gem
3
- agent:
4
- machine:
5
- type: f1-standard-2
6
- os_image: ubuntu2204
7
-
8
- blocks:
9
- - name: publish
10
- execution_time_limit:
11
- minutes: 10
12
- task:
13
- secrets:
14
- - name: rubygems
15
- jobs:
16
- - name: build and push to rubygems.org
17
- commands:
18
- - checkout
19
- - sem-version ruby 3.3
20
- - gem build passkit.gemspec
21
- - gem push passkit-*.gem < /dev/null
@@ -1,42 +0,0 @@
1
- version: "v1.0"
2
- name: passkit
3
- agent:
4
- machine:
5
- type: f1-standard-2
6
- os_image: ubuntu2204
7
- auto_cancel:
8
- running:
9
- when: "true"
10
-
11
- blocks:
12
- - name: tests
13
- execution_time_limit:
14
- minutes: 10
15
- task:
16
- env_vars:
17
- - name: RAILS_ENV
18
- value: test
19
- - name: BUNDLE_PATH
20
- value: vendor/bundle
21
- prologue:
22
- commands:
23
- - checkout --use-cache
24
- - sem-version ruby 3.3
25
- - cache restore gems-$(checksum passkit.gemspec)-$(checksum Gemfile)
26
- - bundle install -j 4
27
- - cache store gems-$(checksum passkit.gemspec)-$(checksum Gemfile) vendor/bundle
28
- - bin/generate_test_certificates
29
- jobs:
30
- - name: linter
31
- commands:
32
- - bundle exec standardrb
33
- - name: tests
34
- commands:
35
- - bundle exec rake test
36
- - name: system tests
37
- commands:
38
- - bundle exec rake test:system
39
-
40
- promotions:
41
- - name: Release gem
42
- pipeline_file: release.yml
data/.standard.yml DELETED
@@ -1,2 +0,0 @@
1
- # For available configuration options, see:
2
- # https://github.com/testdouble/standard
data/Gemfile DELETED
@@ -1,12 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- source "https://rubygems.org"
4
-
5
- # Specify your gem's dependencies in passkit.gemspec
6
- gemspec
7
-
8
- gem "rake", "~> 13.0"
9
-
10
- gem "minitest", "~> 5.0"
11
-
12
- gem "standard", "~> 1.3"
data/Rakefile DELETED
@@ -1,20 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require "bundler/gem_tasks"
4
- require "rake/testtask"
5
-
6
- Rake::TestTask.new(:test) do |t|
7
- t.libs << "test"
8
- t.libs << "lib"
9
- t.test_files = FileList["test/**/test_*.rb"]
10
- end
11
-
12
- Rake::TestTask.new("test:system") do |t|
13
- t.libs << "test"
14
- t.libs << "lib"
15
- t.test_files = FileList["test/system/**/*_test.rb"]
16
- end
17
-
18
- require "standard/rake"
19
-
20
- task default: %i[test standard]
data/bin/console DELETED
@@ -1,15 +0,0 @@
1
- #!/usr/bin/env ruby
2
- # frozen_string_literal: true
3
-
4
- require "bundler/setup"
5
- require "passkit"
6
-
7
- # You can add fixtures and/or initialization code here to make experimenting
8
- # with your gem easier. You can also use a different console, if you like.
9
-
10
- # (If you use this, don't forget to add pry to your Gemfile!)
11
- # require "pry"
12
- # Pry.start
13
-
14
- require "irb"
15
- IRB.start(__FILE__)
@@ -1,55 +0,0 @@
1
- #!/usr/bin/env ruby
2
- # frozen_string_literal: true
3
-
4
- # Generates a self-signed pass certificate and a fake "Apple intermediate"
5
- # certificate, so that the test suite can sign passes without a real Apple
6
- # Developer certificate.
7
-
8
- require "openssl"
9
- require "fileutils"
10
-
11
- output_directory = File.expand_path("../test/dummy/certificates", __dir__)
12
- password = ENV.fetch("PASSKIT_CERTIFICATE_KEY", "passkit")
13
-
14
- FileUtils.mkdir_p(output_directory)
15
-
16
- intermediate_key = OpenSSL::PKey::RSA.new(2048)
17
- intermediate_certificate = OpenSSL::X509::Certificate.new
18
- intermediate_certificate.version = 2
19
- intermediate_certificate.serial = 1
20
- intermediate_certificate.subject = OpenSSL::X509::Name.parse("/CN=Passkit Test Intermediate CA")
21
- intermediate_certificate.issuer = intermediate_certificate.subject
22
- intermediate_certificate.public_key = intermediate_key.public_key
23
- intermediate_certificate.not_before = Time.now - 60
24
- intermediate_certificate.not_after = Time.now + (10 * 365 * 24 * 60 * 60)
25
-
26
- extension_factory = OpenSSL::X509::ExtensionFactory.new
27
- extension_factory.subject_certificate = intermediate_certificate
28
- extension_factory.issuer_certificate = intermediate_certificate
29
- intermediate_certificate.add_extension(extension_factory.create_extension("basicConstraints", "CA:TRUE", true))
30
- intermediate_certificate.add_extension(extension_factory.create_extension("keyUsage", "keyCertSign, cRLSign", true))
31
- intermediate_certificate.sign(intermediate_key, OpenSSL::Digest.new("SHA256"))
32
-
33
- pass_key = OpenSSL::PKey::RSA.new(2048)
34
- pass_certificate = OpenSSL::X509::Certificate.new
35
- pass_certificate.version = 2
36
- pass_certificate.serial = 2
37
- pass_certificate.subject = OpenSSL::X509::Name.parse("/CN=#{ENV.fetch("PASSKIT_PASS_TYPE_IDENTIFIER", "pass.com.example.pass")}")
38
- pass_certificate.issuer = intermediate_certificate.subject
39
- pass_certificate.public_key = pass_key.public_key
40
- pass_certificate.not_before = Time.now - 60
41
- pass_certificate.not_after = Time.now + (10 * 365 * 24 * 60 * 60)
42
-
43
- extension_factory = OpenSSL::X509::ExtensionFactory.new
44
- extension_factory.subject_certificate = pass_certificate
45
- extension_factory.issuer_certificate = intermediate_certificate
46
- pass_certificate.add_extension(extension_factory.create_extension("basicConstraints", "CA:FALSE", true))
47
- pass_certificate.add_extension(extension_factory.create_extension("keyUsage", "digitalSignature", true))
48
- pass_certificate.sign(intermediate_key, OpenSSL::Digest.new("SHA256"))
49
-
50
- p12 = OpenSSL::PKCS12.create(password, "Passkit Test Certificate", pass_key, pass_certificate)
51
-
52
- File.binwrite(File.join(output_directory, "intermediate.cer"), intermediate_certificate.to_der)
53
- File.binwrite(File.join(output_directory, "certificate.p12"), p12.to_der)
54
-
55
- puts "Certificates written to #{output_directory}"
data/bin/setup DELETED
@@ -1,8 +0,0 @@
1
- #!/usr/bin/env bash
2
- set -euo pipefail
3
- IFS=$'\n\t'
4
- set -vx
5
-
6
- bundle install
7
-
8
- bin/generate_test_certificates
data/docs/membership.png DELETED
Binary file
@@ -1,53 +0,0 @@
1
- # Setup Passkit Environment variables
2
-
3
- ### `PASSKIT_WEB_SERVICE_HOST`
4
-
5
- This is the host where your Rails app is running. It is used to generate the URLs for the passes.
6
- When the device wants to update the Pass, it will invoke services on this host.
7
- In production, it will simply be your domain name, but in development you can use [ngrok](https://ngrok.com/) to expose your local server to the internet.
8
-
9
- **Remember that it must always start with `https://`.**
10
-
11
- ### `PASSKIT_APPLE_INTERMEDIATE_CERTIFICATE`
12
-
13
- This is the easy one.
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. PASSKIT_APPLE_INTERMEDIATE_CERTIFICATE is the path to the certificate.
16
-
17
- ### `PASSKIT_APPLE_TEAM_IDENTIFIER`
18
-
19
- You find this in your Apple Developer dashboard, under Membership.
20
-
21
- ![Membership](membership.png)
22
-
23
- ### `PASSKIT_PASS_TYPE_IDENTIFIER`, `PASSKIT_PRIVATE_P12_CERTIFICATE` and `PASSKIT_CERTIFICATE_KEY`
24
-
25
- Head to your Apple Developers console and generate a new certificate.
26
-
27
- ![Step 1](step1.png)
28
-
29
- ![Step 2](step2.png)
30
-
31
- ![Step 3](step3.png)
32
-
33
- The identifier is the `PASSKIT_PASS_TYPE_IDENTIFIER` variable.
34
-
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/
39
-
40
- And create the certificate:
41
-
42
- ![Step 4](step4.png)
43
-
44
- At the end, you'll have a `pass.cer` file.
45
-
46
- Open it in the Keychain Access tool and export it (you must be in the My Certificates tab):
47
-
48
- ![Step 5](step5.png)
49
-
50
- Set a password and get your p12 file. The path to this file is the `PASSKIT_PRIVATE_P12_CERTIFICATE` variable.
51
- Save the password. This is the `PASSKIT_CERTIFICATE_KEY` variable.
52
-
53
- `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/step1.png DELETED
Binary file
data/docs/step2.png DELETED
Binary file
data/docs/step3.png DELETED
Binary file
data/docs/step4.png DELETED
Binary file
data/docs/step5.png DELETED
Binary file
data/docs/wallet.png DELETED
Binary file