passkit 0.1.0 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (64) hide show
  1. checksums.yaml +4 -4
  2. data/.example.env +6 -0
  3. data/README.md +124 -5
  4. data/app/assets/images/passkit/add_to_apple_wallet_de.png +0 -0
  5. data/app/assets/images/passkit/add_to_apple_wallet_en.png +0 -0
  6. data/app/assets/images/passkit/add_to_apple_wallet_fr.png +0 -0
  7. data/app/assets/images/passkit/add_to_apple_wallet_it.png +0 -0
  8. data/app/assets/images/passkit/add_to_walletpass_de.png +0 -0
  9. data/app/assets/images/passkit/add_to_walletpass_en.png +0 -0
  10. data/app/assets/images/passkit/add_to_walletpass_fr.png +0 -0
  11. data/app/assets/images/passkit/add_to_walletpass_it.png +0 -0
  12. data/app/controllers/passkit/api/v1/logs_controller.rb +14 -0
  13. data/app/controllers/passkit/api/v1/passes_controller.rb +58 -0
  14. data/app/controllers/passkit/api/v1/registrations_controller.rb +115 -0
  15. data/app/controllers/passkit/logs_controller.rb +9 -0
  16. data/app/controllers/passkit/passes_controller.rb +4 -19
  17. data/app/controllers/passkit/previews_controller.rb +13 -0
  18. data/app/mailers/passkit/example_mailer.rb +8 -0
  19. data/{lib → app/models}/passkit/device.rb +2 -2
  20. data/{lib → app/models}/passkit/log.rb +0 -0
  21. data/app/models/passkit/pass.rb +49 -0
  22. data/app/models/passkit/registration.rb +6 -0
  23. data/app/views/layouts/passkit/application.html.erb +16 -0
  24. data/app/views/passkit/example_mailer/example_email.html.erb +15 -0
  25. data/app/views/passkit/logs/index.html.erb +22 -0
  26. data/app/views/passkit/passes/index.html.erb +32 -0
  27. data/app/views/passkit/previews/index.html.erb +21 -0
  28. data/app/views/shared/passkit/_navigation.html.erb +5 -0
  29. data/config/routes.rb +17 -7
  30. data/docs/membership.png +0 -0
  31. data/docs/passkit_environment_variables.md +48 -0
  32. data/docs/step1.png +0 -0
  33. data/docs/step2.png +0 -0
  34. data/docs/step3.png +0 -0
  35. data/docs/step4.png +0 -0
  36. data/docs/step5.png +0 -0
  37. data/docs/wallet.png +0 -0
  38. data/lib/generators/passkit/install_generator.rb +26 -0
  39. data/lib/generators/templates/create_passkit_tables.rb.tt +32 -0
  40. data/lib/generators/templates/passkit.rb +3 -0
  41. data/lib/passkit/base_pass.rb +124 -0
  42. data/lib/passkit/example_store_card/icon.png +0 -0
  43. data/lib/passkit/example_store_card/icon@2x.png +0 -0
  44. data/lib/passkit/example_store_card/icon@3x.png +0 -0
  45. data/lib/passkit/example_store_card/logo.png +0 -0
  46. data/lib/passkit/example_store_card.rb +110 -0
  47. data/lib/passkit/factory.rb +2 -2
  48. data/lib/passkit/generator.rb +30 -22
  49. data/lib/passkit/payload_generator.rb +18 -0
  50. data/lib/passkit/url_encrypt.rb +3 -3
  51. data/lib/passkit/url_generator.rb +20 -0
  52. data/lib/passkit/version.rb +1 -1
  53. data/lib/passkit.rb +37 -3
  54. data/passkit-0.2.0.gem +0 -0
  55. data/sig/lib/passkit/encryptable_payload.rbs +5 -0
  56. data/sig/lib/passkit/factory.rbs +5 -0
  57. data/sig/lib/passkit/generator.rbs +8 -0
  58. data/sig/lib/passkit/generator_object.rbs +5 -0
  59. data/sig/lib/passkit/pass.rbs +5 -0
  60. data/sig/lib/passkit/url_encrypt.rbs +6 -0
  61. data/sig/lib/passkit/url_generator.rbs +9 -0
  62. metadata +140 -8
  63. data/lib/passkit/pass.rb +0 -8
  64. data/sig/passkit.rbs +0 -4
data/config/routes.rb CHANGED
@@ -1,12 +1,22 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  Passkit::Engine.routes.draw do
4
- resources :devices, only: [] do
5
- post 'registrations/:pass_type_id/:serial_number' => 'registrations#create', as: :register
6
- delete 'registrations/:pass_type_id/:serial_number' => 'registrations#destroy', as: :unregister
7
- get 'registrations/:pass_type_id' => 'registrations#show', as: :registrations
4
+ scope :api, constraints: {pass_type_id: /.*/} do
5
+ scope :v1 do
6
+ resources :devices, only: [] do
7
+ post "registrations/:pass_type_id/:serial_number" => "api/v1/registrations#create", :as => :register
8
+ delete "registrations/:pass_type_id/:serial_number" => "api/v1/registrations#destroy", :as => :unregister
9
+ get "registrations/:pass_type_id" => "api/v1/registrations#show", :as => :registrations
10
+ end
11
+ get "passes/:pass_type_id/:serial_number" => "api/v1/passes#show", :as => :pass
12
+ get "passes/:payload", to: "api/v1/passes#create", as: :passes_api
13
+ post "log" => "api/v1/logs#create", :as => :log
14
+ end
15
+ end
16
+
17
+ unless Rails.env.production?
18
+ resources :previews, only: [:index, :show], param: :class_name
19
+ resources :logs, only: [:index]
20
+ resources :passes, only: [:index]
8
21
  end
9
- get 'passes/:pass_type_id/:serial_number' => 'passes#show', as: :pass
10
- get 'passes/:payload', to: 'passes#create', as: :passes
11
- post 'log' => 'logs#create'
12
22
  end
Binary file
@@ -0,0 +1,48 @@
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
+
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
+ Now, create a certificate signing request: https://help.apple.com/developer-account/#/devbfa00fef7
36
+
37
+ And create the certificate:
38
+
39
+ ![Step 4](step4.png)
40
+
41
+ At the end, you'll have a `pass.cer` file.
42
+
43
+ Open it in the Keychain Access tool and export it:
44
+
45
+ ![Step 5](step5.png)
46
+
47
+ Set a password and get your p12 file. The path to this file is the `PASSKIT_PRIVATE_P12_CERTIFICATE` variable.
48
+ Save the password. This is the `PASSKIT_CERTIFICATE_KEY` variable.
data/docs/step1.png ADDED
Binary file
data/docs/step2.png ADDED
Binary file
data/docs/step3.png ADDED
Binary file
data/docs/step4.png ADDED
Binary file
data/docs/step5.png ADDED
Binary file
data/docs/wallet.png ADDED
Binary file
@@ -0,0 +1,26 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "rails/generators/base"
4
+ require "rails/generators/migration"
5
+
6
+ module Passkit
7
+ module Generators
8
+ class InstallGenerator < Rails::Generators::Base
9
+ include Rails::Generators::Migration
10
+
11
+ source_root File.expand_path("../../templates", __FILE__)
12
+
13
+ # Implement the required interface for Rails::Generators::Migration.
14
+ def self.next_migration_number(dirname)
15
+ next_migration_number = current_migration_number(dirname) + 1
16
+ ActiveRecord::Migration.next_migration_number(next_migration_number)
17
+ end
18
+
19
+ desc "Copy all files to your application."
20
+ def generate_files
21
+ migration_template "create_passkit_tables.rb", "db/migrate/create_passkit_tables.rb"
22
+ copy_file "passkit.rb", "config/initializers/passkit.rb"
23
+ end
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,32 @@
1
+ class CreatePasskitTables < ActiveRecord::Migration[<%= ActiveRecord::Migration.current_version %>]
2
+ def change
3
+ create_table :passkit_passes do |t|
4
+ t.string :generator_type
5
+ t.string :klass
6
+ t.bigint :generator_id
7
+ t.string :serial_number
8
+ t.string :authentication_token
9
+ t.json :data
10
+ t.integer :version
11
+ t.timestamps null: false
12
+ t.index [:generator_type, :generator_id], name: 'index_passkit_passes_on_generator'
13
+ end
14
+
15
+ create_table :passkit_devices do |t|
16
+ t.string :identifier
17
+ t.string :push_token
18
+ t.timestamps null: false
19
+ end
20
+
21
+ create_table :passkit_registrations do |t|
22
+ t.belongs_to :passkit_pass, index: true
23
+ t.belongs_to :passkit_device, index: true
24
+ t.timestamps null: false
25
+ end
26
+
27
+ create_table :passkit_logs do |t|
28
+ t.text :content
29
+ t.timestamps null: false
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,3 @@
1
+ Passkit.configure do |config|
2
+ # config.available_passes['Passkit::YourPass'] = -> { User.create }
3
+ end
@@ -0,0 +1,124 @@
1
+ module Passkit
2
+ class BasePass
3
+ def initialize(generator = nil)
4
+ @generator = generator
5
+ end
6
+
7
+ def format_version
8
+ ENV["PASSKIT_FORMAT_VERSION"] || 1
9
+ end
10
+
11
+ def apple_team_identifier
12
+ ENV["PASSKIT_APPLE_TEAM_IDENTIFIER"] || raise(Error.new("Missing environment variable: PASSKIT_APPLE_TEAM_IDENTIFIER"))
13
+ end
14
+
15
+ def pass_type_identifier
16
+ ENV["PASSKIT_PASS_TYPE_IDENTIFIER"] || raise(Error.new("Missing environment variable: PASSKIT_PASS_TYPE_IDENTIFIER"))
17
+ end
18
+
19
+ def language
20
+ nil
21
+ end
22
+
23
+ def last_update
24
+ @generator&.updated_at
25
+ end
26
+
27
+ def pass_path
28
+ rails_folder = Rails.root.join("private/passkit/#{folder_name}")
29
+ # if folder exists, otherwise is in the gem itself under lib/passkit/base_pass
30
+ if File.directory?(rails_folder)
31
+ rails_folder
32
+ else
33
+ File.join(File.dirname(__FILE__), folder_name)
34
+ end
35
+ end
36
+
37
+ def pass_type
38
+ :storeCard
39
+ # :coupon
40
+ end
41
+
42
+ def web_service_url
43
+ raise Error.new("Missing environment variable: PASSKIT_WEB_SERVICE_HOST") unless ENV["PASSKIT_WEB_SERVICE_HOST"]
44
+ "#{ENV["PASSKIT_WEB_SERVICE_HOST"]}/passkit/api"
45
+ end
46
+
47
+ def foreground_color
48
+ "rgb(0, 0, 0)"
49
+ end
50
+
51
+ def background_color
52
+ "rgb(255, 255, 255)"
53
+ end
54
+
55
+ def organization_name
56
+ "Passkit"
57
+ end
58
+
59
+ def description
60
+ "A basic description for a pass"
61
+ end
62
+
63
+ # A pass can have up to ten relevant locations
64
+ #
65
+ # @see https://developer.apple.com/library/archive/documentation/UserExperience/Conceptual/PassKit_PG/Creating.html
66
+ def locations
67
+ []
68
+ end
69
+
70
+ def voided
71
+ false
72
+ end
73
+
74
+ def file_name
75
+ @file_name ||= SecureRandom.uuid
76
+ end
77
+
78
+ # QRCode by default
79
+ def barcode
80
+ {messageEncoding: "iso-8859-1",
81
+ format: "PKBarcodeFormatQR",
82
+ message: "https://github.com/coorasse/passkit",
83
+ altText: "https://github.com/coorasse/passkit"}
84
+ end
85
+
86
+ # Barcode example
87
+ # def barcode
88
+ # { messageEncoding: 'iso-8859-1',
89
+ # format: 'PKBarcodeFormatCode128',
90
+ # message: '12345',
91
+ # altText: '12345' }
92
+ # end
93
+
94
+ def logo_text
95
+ "Logo text"
96
+ end
97
+
98
+ def header_fields
99
+ []
100
+ end
101
+
102
+ def primary_fields
103
+ []
104
+ end
105
+
106
+ def secondary_fields
107
+ []
108
+ end
109
+
110
+ def auxiliary_fields
111
+ []
112
+ end
113
+
114
+ def back_fields
115
+ []
116
+ end
117
+
118
+ private
119
+
120
+ def folder_name
121
+ self.class.name.demodulize.underscore
122
+ end
123
+ end
124
+ end
@@ -0,0 +1,110 @@
1
+ module Passkit
2
+ class ExampleStoreCard < BasePass
3
+ def pass_type
4
+ :storeCard
5
+ # :coupon
6
+ end
7
+
8
+ def foreground_color
9
+ "rgb(0, 0, 0)"
10
+ end
11
+
12
+ def background_color
13
+ "rgb(255, 255, 255)"
14
+ end
15
+
16
+ def organization_name
17
+ "Passkit"
18
+ end
19
+
20
+ def description
21
+ "A basic description for a pass"
22
+ end
23
+
24
+ # A pass can have up to ten relevant locations
25
+ #
26
+ # @see https://developer.apple.com/library/archive/documentation/UserExperience/Conceptual/PassKit_PG/Creating.html
27
+ def locations
28
+ []
29
+ end
30
+
31
+ def voided
32
+ false
33
+ end
34
+
35
+ def file_name
36
+ @file_name ||= SecureRandom.uuid
37
+ end
38
+
39
+ # QRCode by default
40
+ def barcode
41
+ {messageEncoding: "iso-8859-1",
42
+ format: "PKBarcodeFormatQR",
43
+ message: "https://github.com/coorasse/passkit",
44
+ altText: "https://github.com/coorasse/passkit"}
45
+ end
46
+
47
+ # Barcode example
48
+ # def barcode
49
+ # { messageEncoding: 'iso-8859-1',
50
+ # format: 'PKBarcodeFormatCode128',
51
+ # message: '12345',
52
+ # altText: '12345' }
53
+ # end
54
+
55
+ def logo_text
56
+ "Loyalty Card"
57
+ end
58
+
59
+ def header_fields
60
+ [{
61
+ key: "balance",
62
+ label: "Balance",
63
+ value: 100,
64
+ currencyCode: "$"
65
+ }]
66
+ end
67
+
68
+ def back_fields
69
+ [{
70
+ key: "example1",
71
+ label: "Code",
72
+ value: "0123456789"
73
+ },
74
+ {
75
+ key: "example2",
76
+ label: "Creator",
77
+ value: "https://github.com/coorasse"
78
+ },
79
+ {
80
+ key: "example3",
81
+ label: "Contact",
82
+ value: "rodi@hey.com"
83
+ }]
84
+ end
85
+
86
+ def auxiliary_fields
87
+ [{
88
+ key: "name",
89
+ label: "Name",
90
+ value: "Alessandro Rodi"
91
+ },
92
+ {
93
+ key: "email",
94
+ label: "Email",
95
+ value: "rodi@hey.com"
96
+ },
97
+ {
98
+ key: "phone",
99
+ label: "Phone",
100
+ value: "+41 1234567890"
101
+ }]
102
+ end
103
+
104
+ private
105
+
106
+ def folder_name
107
+ self.class.name.demodulize.underscore
108
+ end
109
+ end
110
+ end
@@ -1,8 +1,8 @@
1
1
  module Passkit
2
2
  class Factory
3
3
  class << self
4
- def create_pass(generator)
5
- pass = Pass.create!(generator: generator)
4
+ def create_pass(pass_class, generator = nil)
5
+ pass = Pass.create!(klass: pass_class, generator: generator)
6
6
  Passkit::Generator.new(pass).generate_and_sign
7
7
  end
8
8
  end
@@ -1,13 +1,16 @@
1
+ require "zip"
2
+
1
3
  module Passkit
2
4
  class Generator
3
- TMP_FOLDER = Rails.root.join('tmp/pass_kit').freeze
5
+ TMP_FOLDER = Rails.root.join("tmp/passkit").freeze
4
6
 
5
- def initialize(pass_name, pass)
7
+ def initialize(pass)
6
8
  @pass = pass
7
9
  @generator = pass.generator
8
10
  end
9
11
 
10
12
  def generate_and_sign
13
+ check_necessary_files
11
14
  create_temporary_directory
12
15
  copy_pass_to_tmp_location
13
16
  clean_ds_store_files
@@ -21,9 +24,13 @@ module Passkit
21
24
 
22
25
  private
23
26
 
27
+ def check_necessary_files
28
+ raise "icon.png is not present in #{@pass.pass_path}" unless File.exist?(File.join(@pass.pass_path, "icon.png"))
29
+ end
30
+
24
31
  def create_temporary_directory
25
32
  FileUtils.mkdir_p(TMP_FOLDER) unless File.directory?(TMP_FOLDER)
26
- @temporary_path = TMP_FOLDER.join(@pass.file_name)
33
+ @temporary_path = TMP_FOLDER.join(@pass.file_name.to_s)
27
34
 
28
35
  FileUtils.rm_rf(@temporary_path) if File.directory?(@temporary_path)
29
36
  end
@@ -33,10 +40,9 @@ module Passkit
33
40
  end
34
41
 
35
42
  def clean_ds_store_files
36
- Dir.glob(@temporary_path.join('**/.DS_Store')).each { |file| File.delete(file) }
43
+ Dir.glob(@temporary_path.join("**/.DS_Store")).each { |file| File.delete(file) }
37
44
  end
38
45
 
39
- # rubocop:disable Metrics/AbcSize
40
46
  def generate_json_pass
41
47
  pass = {
42
48
  formatVersion: @pass.format_version,
@@ -53,35 +59,37 @@ module Passkit
53
59
  }
54
60
 
55
61
  pass = pass.merge({
56
- serialNumber: @wallet_pass.serial_number,
57
- passTypeIdentifier: @wallet_pass.pass_type_identifier,
58
- authenticationToken: @wallet_pass.authentication_token
59
- })
62
+ serialNumber: @pass.serial_number,
63
+ passTypeIdentifier: @pass.pass_type_identifier,
64
+ authenticationToken: @pass.authentication_token
65
+ })
60
66
 
61
67
  pass[@pass.pass_type] = {
62
68
  headerFields: @pass.header_fields,
69
+ primaryFields: @pass.primary_fields,
70
+ secondaryFields: @pass.secondary_fields,
63
71
  auxiliaryFields: @pass.auxiliary_fields,
64
72
  backFields: @pass.back_fields
65
73
  }
66
74
 
67
- File.open(@temporary_path.join('pass.json'), 'w') { |f| f.write(pass.to_json) }
75
+ File.write(@temporary_path.join("pass.json"), pass.to_json)
68
76
  end
69
77
 
70
78
  # rubocop:enable Metrics/AbcSize
71
79
 
72
80
  def generate_json_manifest
73
81
  manifest = {}
74
- Dir.glob(@temporary_path.join('**')).each do |file|
82
+ Dir.glob(@temporary_path.join("**")).each do |file|
75
83
  manifest[File.basename(file)] = Digest::SHA1.hexdigest(File.read(file))
76
84
  end
77
85
 
78
- @manifest_url = @temporary_path.join('manifest.json')
79
- File.open(@manifest_url, 'w') { |f| f.write(manifest.to_json) }
86
+ @manifest_url = @temporary_path.join("manifest.json")
87
+ File.write(@manifest_url, manifest.to_json)
80
88
  end
81
89
 
82
- CERTIFICATE = Rails.root.join(ENV['PASSKIT_PRIVATE_P12_CERTIFICATE'])
83
- INTERMEDIATE_CERTIFICATE = Rails.root.join(ENV['APPLE_INTERMEDIATE_CERTIFICATE'])
84
- CERTIFICATE_PASSWORD = ENV['PASSKIT_CERTIFICATE_KEY']
90
+ CERTIFICATE = Rails.root.join(ENV["PASSKIT_PRIVATE_P12_CERTIFICATE"])
91
+ INTERMEDIATE_CERTIFICATE = Rails.root.join(ENV["PASSKIT_APPLE_INTERMEDIATE_CERTIFICATE"])
92
+ CERTIFICATE_PASSWORD = ENV["PASSKIT_CERTIFICATE_KEY"]
85
93
 
86
94
  # :nocov:
87
95
  def sign_manifest
@@ -90,21 +98,21 @@ module Passkit
90
98
 
91
99
  flag = OpenSSL::PKCS7::DETACHED | OpenSSL::PKCS7::BINARY
92
100
  signed = OpenSSL::PKCS7.sign(p12_certificate.certificate,
93
- p12_certificate.key, File.read(@manifest_url),
94
- [intermediate_certificate], flag)
101
+ p12_certificate.key, File.read(@manifest_url),
102
+ [intermediate_certificate], flag)
95
103
 
96
- @signature_url = @temporary_path.join('signature')
97
- File.open(@signature_url, 'w') { |f| f.syswrite signed.to_der }
104
+ @signature_url = @temporary_path.join("signature")
105
+ File.open(@signature_url, "w") { |f| f.syswrite signed.to_der }
98
106
  end
99
107
 
100
108
  # :nocov:
101
109
 
102
110
  def compress_pass_file
103
111
  zip_path = TMP_FOLDER.join("#{@pass.file_name}.pkpass")
104
- zipped_file = File.open(zip_path, 'w')
112
+ zipped_file = File.open(zip_path, "w")
105
113
 
106
114
  Zip::OutputStream.open(zipped_file.path) do |z|
107
- Dir.glob(@temporary_path.join('**')).each do |file|
115
+ Dir.glob(@temporary_path.join("**")).each do |file|
108
116
  z.put_next_entry(File.basename(file))
109
117
  z.print File.read(file)
110
118
  end
@@ -0,0 +1,18 @@
1
+ module Passkit
2
+ class PayloadGenerator
3
+ VALIDITY = 30.days
4
+
5
+ def self.encrypted(pass_class, generator = nil)
6
+ UrlEncrypt.encrypt(hash(pass_class, generator))
7
+ end
8
+
9
+ def self.hash(pass_class, generator = nil)
10
+ valid_until = VALIDITY.from_now
11
+
12
+ {valid_until: valid_until,
13
+ generator_class: generator&.class&.name,
14
+ generator_id: generator&.id,
15
+ pass_class: pass_class.name}
16
+ end
17
+ end
18
+ end
@@ -7,13 +7,13 @@ module Passkit
7
7
  cipher.key = encryption_key
8
8
  s = cipher.update(string) + cipher.final
9
9
 
10
- s.unpack1('H*').upcase
10
+ s.unpack1("H*").upcase
11
11
  end
12
12
 
13
13
  def decrypt(string)
14
14
  cipher = cypher.decrypt
15
15
  cipher.key = encryption_key
16
- s = [string].pack('H*').unpack('C*').pack('c*')
16
+ s = [string].pack("H*").unpack("C*").pack("c*")
17
17
 
18
18
  JSON.parse(cipher.update(s) + cipher.final, symbolize_names: true)
19
19
  end
@@ -25,7 +25,7 @@ module Passkit
25
25
  end
26
26
 
27
27
  def cypher
28
- OpenSSL::Cipher.new('AES-128-CBC')
28
+ OpenSSL::Cipher.new("AES-128-CBC")
29
29
  end
30
30
  end
31
31
  end
@@ -0,0 +1,20 @@
1
+ module Passkit
2
+ class UrlGenerator
3
+ include Passkit::Engine.routes.url_helpers
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))
8
+ end
9
+
10
+ def ios
11
+ @url
12
+ end
13
+
14
+ WALLET_PASS_PREFIX = "https://walletpass.io?u=".freeze
15
+ # @see https://walletpasses.io/developer/
16
+ def android
17
+ "#{WALLET_PASS_PREFIX}#{@url}"
18
+ end
19
+ end
20
+ end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Passkit
4
- VERSION = "0.1.0"
4
+ VERSION = "0.3.0"
5
5
  end
data/lib/passkit.rb CHANGED
@@ -1,9 +1,43 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require_relative "passkit/version"
4
- require 'passkit/engine'
3
+ require "rails"
4
+ require "passkit/engine"
5
+
6
+ require "zeitwerk"
7
+ loader = Zeitwerk::Loader.for_gem
8
+ loader.ignore("#{__dir__}/generators")
9
+ loader.setup
5
10
 
6
11
  module Passkit
7
12
  class Error < StandardError; end
8
- # Your code goes here...
13
+
14
+ class << self
15
+ attr_accessor :configuration
16
+ end
17
+
18
+ def self.configure
19
+ self.configuration ||= Configuration.new
20
+ yield(configuration)
21
+ end
22
+
23
+ class Configuration
24
+ attr_accessor :available_passes,
25
+ :web_service_host,
26
+ :certificate_key,
27
+ :private_p12_certificate,
28
+ :apple_intermediate_certificate,
29
+ :apple_team_identifier,
30
+ :pass_type_identifier
31
+
32
+ def initialize
33
+ @available_passes = {"Passkit::ExampleStoreCard" => -> {}}
34
+ @web_service_host = ENV["PASSKIT_WEB_SERVICE_HOST"] || (raise "Please set PASSKIT_WEB_SERVICE_HOST")
35
+ raise("PASSKIT_WEB_SERVICE_HOST must start with https://") unless @web_service_host.start_with?("https://")
36
+ @certificate_key = ENV["PASSKIT_CERTIFICATE_KEY"] || (raise "Please set PASSKIT_CERTIFICATE_KEY")
37
+ @private_p12_certificate = ENV["PASSKIT_PRIVATE_P12_CERTIFICATE"] || (raise "Please set PASSKIT_PRIVATE_P12_CERTIFICATE")
38
+ @apple_intermediate_certificate = ENV["PASSKIT_APPLE_INTERMEDIATE_CERTIFICATE"] || (raise "Please set PASSKIT_APPLE_INTERMEDIATE_CERTIFICATE")
39
+ @apple_team_identifier = ENV["PASSKIT_APPLE_TEAM_IDENTIFIER"] || (raise "Please set PASSKIT_APPLE_TEAM_IDENTIFIER")
40
+ @pass_type_identifier = ENV["PASSKIT_PASS_TYPE_IDENTIFIER"] || (raise "Please set PASSKIT_PASS_TYPE_IDENTIFIER")
41
+ end
42
+ end
9
43
  end
data/passkit-0.2.0.gem ADDED
Binary file
@@ -0,0 +1,5 @@
1
+ module Passkit
2
+ class EncryptablePayload
3
+ def to_json: () -> Hash[Symbol, String]
4
+ end
5
+ end
@@ -0,0 +1,5 @@
1
+ module Passkit
2
+ class Factory
3
+ def self.create_pass: (String pass_class, Passkit::GeneratorObject ?generator) -> String
4
+ end
5
+ end