passkit 0.1.0 → 0.3.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.
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