passbook 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
data/.travis.yml ADDED
@@ -0,0 +1,5 @@
1
+ language: ruby
2
+ rvm:
3
+ - 1.9.3
4
+ - 1.9.2
5
+ - ruby-head
data/Gemfile ADDED
@@ -0,0 +1,15 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in passbook.gemspec
4
+ gem 'rubyzip'
5
+ gem 'grocer'
6
+
7
+ group :test, :development do
8
+ gem 'rack-test'
9
+ gem 'activesupport'
10
+ gem 'jeweler'
11
+ gem 'simplecov'
12
+ gem 'rspec'
13
+ gem 'rake'
14
+ gem 'yard'
15
+ end
data/Gemfile.lock ADDED
@@ -0,0 +1,53 @@
1
+ GEM
2
+ remote: https://rubygems.org/
3
+ specs:
4
+ activesupport (3.2.8)
5
+ i18n (~> 0.6)
6
+ multi_json (~> 1.0)
7
+ diff-lcs (1.1.3)
8
+ git (1.2.5)
9
+ grocer (0.3.0)
10
+ i18n (0.6.1)
11
+ jeweler (1.8.4)
12
+ bundler (~> 1.0)
13
+ git (>= 1.2.5)
14
+ rake
15
+ rdoc
16
+ json (1.7.5)
17
+ json (1.7.5-java)
18
+ multi_json (1.3.6)
19
+ rack (1.4.1)
20
+ rack-test (0.6.2)
21
+ rack (>= 1.0)
22
+ rake (0.9.2.2)
23
+ rdoc (3.12)
24
+ json (~> 1.4)
25
+ rspec (2.11.0)
26
+ rspec-core (~> 2.11.0)
27
+ rspec-expectations (~> 2.11.0)
28
+ rspec-mocks (~> 2.11.0)
29
+ rspec-core (2.11.1)
30
+ rspec-expectations (2.11.3)
31
+ diff-lcs (~> 1.1.3)
32
+ rspec-mocks (2.11.3)
33
+ rubyzip (0.9.9)
34
+ simplecov (0.7.1)
35
+ multi_json (~> 1.0)
36
+ simplecov-html (~> 0.7.1)
37
+ simplecov-html (0.7.1)
38
+ yard (0.8.3)
39
+
40
+ PLATFORMS
41
+ java
42
+ ruby
43
+
44
+ DEPENDENCIES
45
+ activesupport
46
+ grocer
47
+ jeweler
48
+ rack-test
49
+ rake
50
+ rspec
51
+ rubyzip
52
+ simplecov
53
+ yard
data/LICENSE ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2012 Thomas Lauro
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,237 @@
1
+ [![Build Status](https://travis-ci.org/lgleasain/passbook.png)](https://travis-ci.org/lgleasain/passbook)
2
+
3
+ # passbook-ios
4
+
5
+ The passbook-ios gem let's you create a pkpass for passbook in iOS 6+
6
+
7
+ ## Installation
8
+
9
+ Include the passbook-ios gem in your project.
10
+
11
+ IE: In your Gemfile
12
+ ```
13
+ gem 'passbook-ios'
14
+ ```
15
+
16
+ ## Configuration
17
+
18
+ Create initializer
19
+ ```
20
+ rails g passbook:config
21
+ or with params
22
+ rails g passbook:config [Absolute path to the wwdc cert file] [Absolute path to your cert.p12 file] [Password for your certificate]
23
+ ```
24
+
25
+ Configure your config/initializers/passbook.rb
26
+ ```
27
+ Passbook.configure do |passbook|
28
+ passbook.wwdc_cert = Rails.root.join('wwdc_cert.pem')
29
+ passbook.p12_cert = Rails.root.join('cert.p12')
30
+ passbook.p12_password = 'cert password'
31
+ end
32
+ ```
33
+
34
+ If you are running this on a different machine from what you used to create your WWDC keys
35
+ ```
36
+ Passbook.configure do |passbook|
37
+ passbook.wwdc_cert = Rails.root.join('wwdc_cert.pem')
38
+ passbook.p12_key = Rails.root.join('key.pem')
39
+ passbook.p12_certificate = Rails.root.join('certificate.pem')
40
+ passbook.p12_password = 'cert password'
41
+ end
42
+ ```
43
+ If you are using Sinatra you can place this in the file you are executing or in a file that you do a require on. You would also not reference Rails.root when specifying your file path.
44
+
45
+ If You are doing push notifications then you will need to add some extra configuration options, namely a push notification certificate and a notification gateway certificate. Look at the Grocer gem documentation to find information on how to create this certificate. Settings you will want ot use for the notification gateway are either 'gateway.push.apple.com' for production, 'gateway.sandbox.push.apple.com' for developmetn and 'localhost' for unit tests.
46
+ ```
47
+ Passbook.configure do |passbook|
48
+ .....other settings.....
49
+ passbook.notification_gateway = 'gateway.push.apple.com'
50
+ passbook.notification_cert = 'lib/assets/my_notification_cert.pem'
51
+ end
52
+ ```
53
+
54
+ If you want to also support the push notification endpoints you will also need to include the Rack::PassbookRack middleware. In rails your config will look something like this.
55
+ ```
56
+ config.middleware.use Rack::PassbookRack
57
+ ```
58
+
59
+ ## Usage
60
+
61
+ Please refer to apple iOS dev center for how to build cert and json. [This article is also helpful.](http://www.raywenderlich.com/20734/beginning-passbook-part-1#more-20734)
62
+ ```
63
+ pass = Passbook::PKPass.new 'your json data'
64
+
65
+ # Add file from disk
66
+ pass.addFile 'file_path'
67
+
68
+ # Add file from memory
69
+ file[:name] = 'file name'
70
+ file[:content] = 'whatever you want'
71
+ pass.addFile file
72
+
73
+ # Add multiple files
74
+ pass.addFiles [file_path_1, file_path_2, file_path_3]
75
+
76
+ # Add multiple files from memory
77
+ pass.addFiles [{name: 'file1', content: 'content1'}, {name: 'file2', content: 'content2'}, {name: 'file3', content: 'content3'}]
78
+
79
+ # Output a Tempfile
80
+
81
+ pkpass = pass.file
82
+ send_file pkpass.path, type: 'application/vnd.apple.pkpass', disposition: 'attachment', filename: "pass.pkpass"
83
+
84
+ # Or a stream
85
+
86
+ pkpass = pass.stream
87
+ send_data pkpass.string, type: 'application/vnd.apple.pkpass', disposition: 'attachment', filename: "pass.pkpass"
88
+
89
+ ```
90
+ If you are using Sinatra you will need to include the 'active_support' gem and will need to require 'active_support/json/encoding'. Here is an example using the streaming mechanism.
91
+
92
+ ```
93
+ require 'sinatra'
94
+ require 'passbook'
95
+ require 'active_support/json/encoding'
96
+
97
+ Passbook.configure do |passbook|
98
+ passbook.p12_password = '12345'
99
+ passbook.p12_key = 'passkey.pem'
100
+ passbook.p12_certificate = 'passcertificate.pem'
101
+ passbook.wwdc_cert = 'WWDR.pem'
102
+ end
103
+
104
+ get '/passbook' do
105
+ pass = # valid passbook json. refer to the wwdc documentation.
106
+ passbook = Passbook::PKPass.new pass
107
+ passbook.addFiles ['logo.png', 'logo@2x.png', 'icon.png', 'icon@2x.png']
108
+ response['Content-Type'] = 'application/vnd.apple.pkpass'
109
+ attachment 'mypass.pkpass'
110
+ passbook.stream.string
111
+ end
112
+ ```
113
+
114
+ We will try to make this cleaner in subsequent releases.
115
+
116
+ ### Passbook
117
+
118
+ If you want to support passbook push notification updates you will need to congigure the appropriate bits above.
119
+
120
+ In order to support push notifications you will need to have a basic understanding of the way that push notifications work and how the data is passed back and forth. See [this](http://developer.apple.com/library/ios/#Documentation/UserExperience/Conceptual/PassKit_PG/Chapters/Creating.html) for basic information about passes and [this](http://developer.apple.com/library/ios/#Documentation/UserExperience/Conceptual/PassKit_PG/Chapters/Updating.html#//apple_ref/doc/uid/TP40012195-CH5-SW1) to understand the information that needs to be exchanged between each device and your application to support the update service.
121
+
122
+ Your pass will need to have a field called 'webServiceURL' with the base url to your site and a field called 'authenticationToken'. The json snippet should look like this. Note that your url needs to be a valid signed https endpoint for production. You can put your phone in dev mode to test updates against a insecure http endpoint (under settings => developer => passkit testing).
123
+
124
+ ```
125
+ ...
126
+ "webserviceURL" : "https://www.honeybadgers.com/",
127
+ "authenticationToken" : "yummycobras"
128
+ ...
129
+ ```
130
+
131
+ Passbook-ios includes rack middleware to make the job of supporting the passbook endpoints easier. You will need to configure the middleware as outlined above and then implement a class called Passbook::PassbookNotification. Below is an annotated implementation.
132
+
133
+ ```
134
+ module Passbook
135
+ class PassbookNotification
136
+
137
+ # This is called whenever a new pass is saved to a users passbook or the
138
+ # notifications are re-enabled. You will want to persist these values to
139
+ # allow for updates on subsequent calls in the call chain. You can have
140
+ # multiple push tokens and serial numbers for a specific
141
+ # deviceLibraryIdentifier.
142
+
143
+ def self.register_pass(options)
144
+ the_passes_serial_number = options['serialNumber']
145
+ the_devices_device_library_identifier = options['deviceLibraryIdentifier']
146
+ the_devices_push_token = options['pushToken']
147
+
148
+ # this is if the pass registered successfully
149
+ # change the code to 200 if the pass has already been registered
150
+ # or another appropriate code if something went wrong.
151
+ {:status => 201}
152
+ end
153
+
154
+ # This is called when the device receives a push notification from apple.
155
+ # You will need to return the serial number of all passes associated with
156
+ # that deviceLibraryIdentifier.
157
+
158
+ def self.passes_for_device(options)
159
+ device_library_identifier = options['deviceLibraryIdentifier']
160
+
161
+ # the 'lastUpdated' uses integers values to tell passbook if the pass is
162
+ # more recent than the current one. If you just set it is the same value
163
+ # every time the pass will update and you will get a warning in the log files.
164
+ # you can use the time in milliseconds, a counter or any other numbering scheme.
165
+ # you then also need to return an array of serial numbers.
166
+ {'lastUpdated' => '1', 'serialNumbers' => ['various', 'serial', 'numbers']}
167
+ end
168
+
169
+ # this is called when a pass is deleted or the user selects the option to disable pass updates.
170
+ def self.unregister_pass(options)
171
+ # a solid unique pair of identifiers to identify the pass are
172
+ serial_number = options['serialNumber']
173
+ device_library_identifier = options['deviceLibraryIdentifier']
174
+ # return a status 200 to indicate that the pass was successfully unregistered.
175
+ {:status => 200}
176
+ end
177
+
178
+ # this returns your updated pass
179
+ def self.latest_pass(options)
180
+ the_pass_serial_number = options['serialNumber']
181
+ # create your PkPass the way you did when your first created the pass.
182
+ # you will want to return
183
+ my_pass = PkPass.new 'your pass json'
184
+ # you will want to return the string from the stream of your PkPass object.
185
+ mypass.stream.string
186
+ end
187
+
188
+ # This is called whenever there is something from the update process that is a warning
189
+ # or error
190
+ def self.log(log)
191
+ # this is a VERY crude logging example. use the logger of your choice here.
192
+ p "#{Time.now} #{log}"
193
+ end
194
+
195
+ end
196
+ end
197
+
198
+ ```
199
+
200
+ To send a push notification for a updated pass simply call Passbook::PassbookPushNotification.send_notifications_for_promotion with the push token for the pass you are updating
201
+
202
+ ```
203
+ Passbook::PassbookPushNotification.send_notifications_for_promotion the_pass_push_token
204
+
205
+ ```
206
+
207
+ Apple will send out a notification to your phone (usually within 15 minutes or less), which will cause the phone that this push notification is associated with to make a call to your server to get pass serial numbers and to then get the updated pass. Each phone/pass combination has it's own push token whch will require a separate call for every phone that has push notifications enabled for a pass (this is an Apple thing). In the future we may look into offering background process support for this as part of this gem. For now, if you have a lot of passes to update you will need to do this yourself.
208
+
209
+ ## Tests
210
+
211
+ To launch tests :
212
+ ```
213
+ bundle exec rspec spec/lib/passbook/pkpass_spec.rb
214
+ ```
215
+
216
+ ## Contributing
217
+
218
+ 1. Fork it
219
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
220
+ 3. Commit your changes (`git commit -am 'Added some feature'`)
221
+ 4. Push to the branch (`git push origin my-new-feature`)
222
+ 5. Create new Pull Request
223
+
224
+ ## Changelog
225
+
226
+ ### 0.0.4
227
+ Allow passbook gem to return a ZipOutputStream (needed when garbage collector delete tempfile before beeing able to use it) [Thx to applidget]
228
+
229
+ ### 0.2.0
230
+ Adding support for push notification updates for passes.
231
+
232
+ License
233
+ -------
234
+
235
+ passbook-ios is released under the MIT license:
236
+
237
+ * http://www.opensource.org/licenses/MIT
data/Rakefile ADDED
@@ -0,0 +1,35 @@
1
+ #!/usr/bin/env rake
2
+ require 'rubygems'
3
+ require 'bundler'
4
+ begin
5
+ Bundler.setup(:default, :development)
6
+ rescue Bundler::BundlerError => e
7
+ $stderr.puts e.message
8
+ $stderr.puts "Run `bundle install` to install missing gems"
9
+ exit e.status_code
10
+ end
11
+ require 'rake'
12
+ require 'jeweler'
13
+ Jeweler::Tasks.new do |gem|
14
+ # gem is a Gem::Specification... see http://docs.rubygems.org/read/chapter/20 for more options
15
+ gem.name = "passbook"
16
+ gem.homepage = "http://github.com/frozon/passbook"
17
+ gem.license = "MIT"
18
+ gem.summary = %Q{A IOS Passbook generator.}
19
+ gem.description = %Q{This gem allows you to create IOS Passbooks. Unlike some, this works with Rails but does not require it.}
20
+ gem.email = ['thomas@lauro.fr', 'lgleason@polyglotprogramminginc.com']
21
+ gem.authors = ['Thomas Lauro', 'Lance Gleason']
22
+ # dependencies defined in Gemfile
23
+ end
24
+ Jeweler::RubygemsDotOrgTasks.new
25
+
26
+ require 'rspec/core'
27
+ require 'rspec/core/rake_task'
28
+ RSpec::Core::RakeTask.new(:spec) do |spec|
29
+ spec.pattern = FileList['spec/**/*_spec.rb']
30
+ end
31
+
32
+ task :default => :spec
33
+
34
+ require 'yard'
35
+ YARD::Rake::YardocTask.new
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 0.2.0
@@ -0,0 +1,142 @@
1
+ require 'digest/sha1'
2
+ require 'openssl'
3
+ require 'zip/zip'
4
+ require 'base64'
5
+
6
+ module Passbook
7
+ class PKPass
8
+ attr_accessor :pass, :manifest_files
9
+
10
+ def initialize pass
11
+ @pass = pass
12
+ @manifest_files = []
13
+ end
14
+
15
+ def addFile file
16
+ @manifest_files << file
17
+ end
18
+
19
+ def addFiles files
20
+ @manifest_files += files
21
+ end
22
+
23
+ # for backwards compatibility
24
+ def json= json
25
+ @pass = json
26
+ end
27
+
28
+ def build
29
+ manifest = createManifest
30
+
31
+ # Check pass for necessary files and fields
32
+ checkPass manifest
33
+
34
+ # Create pass signature
35
+ signature = createSignature manifest
36
+
37
+ return [manifest, signature]
38
+ end
39
+
40
+ # Backward compatibility
41
+ def create
42
+ self.file.path
43
+ end
44
+
45
+ # Return a Tempfile containing our ZipStream
46
+ def file(options = {})
47
+ options[:file_name] ||= 'pass.pkpass'
48
+
49
+ temp_file = Tempfile.new(options[:file_name])
50
+ temp_file.write self.stream.string
51
+ temp_file.close
52
+
53
+ temp_file
54
+ end
55
+
56
+ # Return a ZipOutputStream
57
+ def stream
58
+ manifest, signature = build
59
+
60
+ outputZip manifest, signature
61
+ end
62
+
63
+ def get_p12_cert_and_key
64
+ key_hash = {}
65
+ if Passbook.p12_key
66
+ key_hash[:key] = OpenSSL::PKey::RSA.new File.read(Passbook.p12_key), Passbook.p12_password
67
+ key_hash[:cert] = OpenSSL::X509::Certificate.new File.read(Passbook.p12_certificate)
68
+ else
69
+ p12 = OpenSSL::PKCS12.new File.read(Passbook.p12_cert), Passbook.p12_password
70
+ key_hash[:key], key_hash[:cert] = p12.key, p12.certificate
71
+ end
72
+ key_hash
73
+ end
74
+
75
+ def createSignature manifest
76
+ p12 = get_p12_cert_and_key
77
+ wwdc = OpenSSL::X509::Certificate.new File.read(Passbook.wwdc_cert)
78
+ pk7 = OpenSSL::PKCS7.sign p12[:cert], p12[:key], manifest.to_s, [wwdc], OpenSSL::PKCS7::BINARY | OpenSSL::PKCS7::DETACHED
79
+ data = OpenSSL::PKCS7.write_smime pk7
80
+
81
+ str_debut = "filename=\"smime.p7s\"\n\n"
82
+ data = data[data.index(str_debut)+str_debut.length..data.length-1]
83
+ str_end = "\n\n------"
84
+ data = data[0..data.index(str_end)-1]
85
+
86
+ return Base64.decode64(data)
87
+ end
88
+
89
+ private
90
+
91
+ def checkPass manifest
92
+ # Check for default images
93
+ raise 'Icon missing' unless manifest.include?('icon.png')
94
+ raise 'Icon@2x missing' unless manifest.include?('icon@2x.png')
95
+
96
+ # Check for developer field in JSON
97
+ raise 'Pass Type Identifier missing' unless @pass.include?('passTypeIdentifier')
98
+ raise 'Team Identifier missing' unless @pass.include?('teamIdentifier')
99
+ raise 'Serial Number missing' unless @pass.include?('serialNumber')
100
+ raise 'Organization Name Identifier missing' unless @pass.include?('organizationName')
101
+ raise 'Format Version' unless @pass.include?('formatVersion')
102
+ raise 'Description' unless @pass.include?('description')
103
+ end
104
+
105
+ def createManifest
106
+ sha1s = {}
107
+ sha1s['pass.json'] = Digest::SHA1.hexdigest @pass
108
+
109
+ @manifest_files.each do |file|
110
+ if file.class == Hash
111
+ sha1s[file[:name]] = Digest::SHA1.hexdigest file[:content]
112
+ else
113
+ sha1s[File.basename(file)] = Digest::SHA1.file(file).hexdigest
114
+ end
115
+ end
116
+
117
+ return sha1s.to_json
118
+ end
119
+
120
+ def outputZip manifest, signature
121
+
122
+ Zip::ZipOutputStream.write_buffer do |zip|
123
+ zip.put_next_entry 'pass.json'
124
+ zip.write @pass
125
+ zip.put_next_entry 'manifest.json'
126
+ zip.write manifest
127
+ zip.put_next_entry 'signature'
128
+ zip.write signature
129
+
130
+ @manifest_files.each do |file|
131
+ if file.class == Hash
132
+ zip.put_next_entry file[:name]
133
+ zip.print file[:content]
134
+ else
135
+ zip.put_next_entry File.basename(file)
136
+ zip.print IO.read(file)
137
+ end
138
+ end
139
+ end
140
+ end
141
+ end
142
+ end
@@ -0,0 +1,10 @@
1
+ module Passbook
2
+ class PushNotification
3
+ def self.send_notification(device_token)
4
+ pusher = Grocer.pusher({:certificate => Passbook.notification_cert, :gateway => Passbook.notification_gateway})
5
+ notification = Grocer::PassbookNotification.new(:device_token => device_token)
6
+
7
+ pusher.push notification
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,3 @@
1
+ module Passbook
2
+ VERSION = "0.0.4"
3
+ end
data/lib/passbook.rb ADDED
@@ -0,0 +1,13 @@
1
+ require "passbook/version"
2
+ require "passbook/pkpass"
3
+ require 'active_support/core_ext/module/attribute_accessors'
4
+ require 'passbook/push_notification'
5
+ require 'grocer/passbook_notification'
6
+
7
+ module Passbook
8
+ mattr_accessor :p12_cert, :p12_password, :wwdc_cert, :p12_certificate, :p12_key, :notification_cert, :notification_gateway
9
+
10
+ def self.configure
11
+ yield self
12
+ end
13
+ end
@@ -0,0 +1,94 @@
1
+ module Rack
2
+ class PassbookRack
3
+
4
+ def initialize(app)
5
+ @app = app
6
+ end
7
+
8
+ def call(env)
9
+ method_and_params = find_method env['PATH_INFO']
10
+ if method_and_params
11
+ case method_and_params[:method]
12
+ when 'device_register_delete'
13
+ if env['REQUEST_METHOD'] == 'POST'
14
+ [Passbook::PassbookNotification.
15
+ register_pass(method_and_params[:params].merge! JSON.parse(env['rack.input'].read 1000))[:status],
16
+ {}, ['']]
17
+ elsif env['REQUEST_METHOD'] == 'DELETE'
18
+ [Passbook::PassbookNotification.unregister_pass(method_and_params[:params])[:status], {}, {}]
19
+ end
20
+ when 'passes_for_device'
21
+ response = Passbook::PassbookNotification.passes_for_device(method_and_params[:params])
22
+ [response ? 200 : 204, {}, [response.to_json]]
23
+ when 'latest_pass'
24
+ response = Passbook::PassbookNotification.latest_pass(method_and_params[:params])
25
+ if response
26
+ [200, {'Content-Type' => 'application/vnd.apple.pkpass',
27
+ 'Content-Disposition' => 'attachment',
28
+ 'filename' => "#{method_and_params[:params]['serialNumber']}.pkpass"}, [response]]
29
+ else
30
+ [204, {}, {}]
31
+ end
32
+ when 'log'
33
+ Passbook::PassbookNotification.log JSON.parse(env['rack.input'].read 10000)
34
+ [200, {}, {}]
35
+ else
36
+ end
37
+ else
38
+ @app.call env
39
+ end
40
+ end
41
+
42
+ def append_parameter_separator url
43
+ end
44
+
45
+ def each(&block)
46
+ end
47
+
48
+
49
+ def find_method(path)
50
+ parsed_path = path.split '/'
51
+ url_beginning = parsed_path.index 'v1'
52
+ if url_beginning
53
+ args_length = parsed_path.size - url_beginning
54
+
55
+ if (parsed_path[url_beginning + 1 ] == 'devices') and
56
+ (parsed_path[url_beginning + 3 ] == 'registrations')
57
+ if args_length == 6
58
+ return method_and_params_hash 'device_register_delete', path
59
+ elsif args_length == 5
60
+ return method_and_params_hash 'passes_for_device', path
61
+ end
62
+ elsif parsed_path[url_beginning + 1] == 'passes' and args_length == 4
63
+ return method_and_params_hash 'latest_pass', path
64
+ elsif parsed_path[url_beginning + 1] == 'log' and args_length == 2
65
+ return {:method => 'log'}
66
+ end
67
+ end
68
+
69
+ return nil
70
+ end
71
+
72
+ private
73
+
74
+ def method_and_params_hash(method, path)
75
+ parsed_path = path.split '/'
76
+ url_beginning = parsed_path.index 'v1'
77
+ if method == 'latest_pass'
78
+ {:method => 'latest_pass',
79
+ :params => {'passTypeIdentifier' => parsed_path[url_beginning + 2],
80
+ 'serialNumber' => parsed_path[url_beginning + 3]}}
81
+ else
82
+ return_hash = {:method => method, :params =>
83
+ {'deviceLibraryIdentifier' => parsed_path[url_beginning + 2],
84
+ 'passTypeIdentifier' => parsed_path[url_beginning + 4]}}
85
+ return_hash[:params]['serialNumber'] = parsed_path[url_beginning + 5] if
86
+ method == 'device_register_delete'
87
+ return_hash
88
+ end
89
+ end
90
+
91
+
92
+ end
93
+ end
94
+
@@ -0,0 +1,16 @@
1
+ module Passbook
2
+ module Generators
3
+ class ConfigGenerator < Rails::Generators::Base
4
+ source_root File.expand_path('../templates', __FILE__)
5
+
6
+ argument :wwdc_cert_path, type: :string, default: '', optional: true, banner: "Absolute path to your wwdc cert file"
7
+ argument :p12_cert_path, type: :string, default: '', optional: true, banner: "Absolute path to your cert.p12 file"
8
+ argument :p12_password, type: :string, default: '', optional: true, banner: "Password for your certificate"
9
+
10
+ desc 'Create passbook initializer'
11
+ def create_initializer_file
12
+ template 'initializer.rb', File.join('config', 'initializers', 'passbook.rb')
13
+ end
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,13 @@
1
+ require 'passbook'
2
+
3
+ Passbook.configure do |passbook|
4
+
5
+ # Path to your wwdc cert file
6
+ passbook.wwdc_cert = '<%= wwdc_cert_path %>'
7
+
8
+ # Path to your cert.p12 file
9
+ passbook.p12_cert = '<%= p12_cert_path %>'
10
+
11
+ # Password for your certificate
12
+ passbook.p12_password = '<%= p12_password %>'
13
+ end