passbook 0.2.1 → 0.3.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,15 @@
1
+ ---
2
+ !binary "U0hBMQ==":
3
+ metadata.gz: !binary |-
4
+ Y2U1MTYxOTRhMDk5YmJmYWRhMDcxNWEyZTU0MjAzMmIyZGU5ZGQ4NA==
5
+ data.tar.gz: !binary |-
6
+ Yzk2Mzk1NzA5OTEzYTNkZTI2ZWM3YTZiYWZkMjBiNjE5ZDhiMzJkZA==
7
+ SHA512:
8
+ metadata.gz: !binary |-
9
+ OWVjYzI2ODJlNTcxNzdiZDcxMDBkOGJmMTdjMzJiNTBhMTJkOTBjZWExZTdm
10
+ ODdhMzkzNGYyOGRhM2VkNGJlNDg3YzBhNTY5NDhlMmM2YjI3ZGNkMWJmYWEy
11
+ OGJhN2E2ZjU4ZTU1YTNlOWUyMzcxYTQ1MDRiNmFhNzk0NjgyNmI=
12
+ data.tar.gz: !binary |-
13
+ ODY0NDc4NWNhZWNhMjFiN2M0NjQwNjA3ODM0ZDlmNzRkYTIzZjdiYmRiNWY5
14
+ NjAyNDE1NGZhMzcxMmQ2OWJiZDk4OGIxNmRjMDdhMzZiMGNlNzk2ZjEzNjM2
15
+ YmE3YjM2OWQxYzM3MDA2MzFjNWJmYzE5YTIwNGY0NjFiYzQ0YmU=
data/Gemfile CHANGED
@@ -1,13 +1,15 @@
1
1
  source 'https://rubygems.org'
2
2
 
3
3
  # Specify your gem's dependencies in passbook.gemspec
4
- gem 'rubyzip'
4
+ gem 'rubyzip', '~> 1.0.0'
5
5
  gem 'grocer'
6
+ gem 'commander'
7
+ gem 'terminal-table'
6
8
 
7
9
  group :test, :development do
8
10
  gem 'rack-test'
9
11
  gem 'activesupport'
10
- gem 'jeweler'
12
+ gem 'jeweler', :git => 'git://github.com/foxnewsnetwork/jeweler.git', :branch => 'ruby-2.0.0-ifying'
11
13
  gem 'simplecov'
12
14
  gem 'rspec'
13
15
  gem 'rake'
data/Gemfile.lock CHANGED
@@ -1,41 +1,51 @@
1
- GEM
2
- remote: https://rubygems.org/
1
+ GIT
2
+ remote: git://github.com/foxnewsnetwork/jeweler.git
3
+ revision: f05c62e168cfc29bd82cebe06df8fd11e1ef09ee
4
+ branch: ruby-2.0.0-ifying
3
5
  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
6
  jeweler (1.8.4)
12
- bundler (~> 1.0)
7
+ bundler (~> 1.3.0.pre)
13
8
  git (>= 1.2.5)
14
9
  rake
15
10
  rdoc
16
- json (1.7.5)
17
- json (1.7.5-java)
18
- multi_json (1.3.6)
19
- rack (1.4.1)
11
+
12
+ GEM
13
+ remote: https://rubygems.org/
14
+ specs:
15
+ activesupport (3.2.14)
16
+ i18n (~> 0.6, >= 0.6.4)
17
+ multi_json (~> 1.0)
18
+ commander (4.1.5)
19
+ highline (~> 1.6.11)
20
+ diff-lcs (1.2.4)
21
+ git (1.2.6)
22
+ grocer (0.4.1)
23
+ highline (1.6.19)
24
+ i18n (0.6.5)
25
+ json (1.8.0)
26
+ json (1.8.0-java)
27
+ multi_json (1.8.0)
28
+ rack (1.5.2)
20
29
  rack-test (0.6.2)
21
30
  rack (>= 1.0)
22
- rake (0.9.2.2)
23
- rdoc (3.12)
31
+ rake (10.1.0)
32
+ rdoc (4.0.1)
24
33
  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
+ rspec (2.14.1)
35
+ rspec-core (~> 2.14.0)
36
+ rspec-expectations (~> 2.14.0)
37
+ rspec-mocks (~> 2.14.0)
38
+ rspec-core (2.14.5)
39
+ rspec-expectations (2.14.3)
40
+ diff-lcs (>= 1.1.3, < 2.0)
41
+ rspec-mocks (2.14.3)
42
+ rubyzip (1.0.0)
34
43
  simplecov (0.7.1)
35
44
  multi_json (~> 1.0)
36
45
  simplecov-html (~> 0.7.1)
37
46
  simplecov-html (0.7.1)
38
- yard (0.8.3)
47
+ terminal-table (1.4.5)
48
+ yard (0.8.7.2)
39
49
 
40
50
  PLATFORMS
41
51
  java
@@ -43,11 +53,13 @@ PLATFORMS
43
53
 
44
54
  DEPENDENCIES
45
55
  activesupport
56
+ commander
46
57
  grocer
47
- jeweler
58
+ jeweler!
48
59
  rack-test
49
60
  rake
50
61
  rspec
51
- rubyzip
62
+ rubyzip (~> 1.0.0)
52
63
  simplecov
64
+ terminal-table
53
65
  yard
data/README.md CHANGED
@@ -128,7 +128,7 @@ Your pass will need to have a field called 'webServiceURL' with the base url to
128
128
  ...
129
129
  ```
130
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.
131
+ Passbook 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
132
 
133
133
  ```
134
134
  module Passbook
@@ -144,9 +144,13 @@ module Passbook
144
144
  the_passes_serial_number = options['serialNumber']
145
145
  the_devices_device_library_identifier = options['deviceLibraryIdentifier']
146
146
  the_devices_push_token = options['pushToken']
147
+ the_pass_type_identifier = options["passTypeIdentifier"]
148
+ the_authentication_token = options['authToken']
147
149
 
148
150
  # this is if the pass registered successfully
149
151
  # change the code to 200 if the pass has already been registered
152
+ # 404 if pass not found for serialNubmer and passTypeIdentifier
153
+ # 401 if authorization failed
150
154
  # or another appropriate code if something went wrong.
151
155
  {:status => 201}
152
156
  end
@@ -157,6 +161,7 @@ module Passbook
157
161
 
158
162
  def self.passes_for_device(options)
159
163
  device_library_identifier = options['deviceLibraryIdentifier']
164
+ passes_updated_since = options['passesUpdatedSince']
160
165
 
161
166
  # the 'lastUpdated' uses integers values to tell passbook if the pass is
162
167
  # more recent than the current one. If you just set it is the same value
@@ -171,6 +176,8 @@ module Passbook
171
176
  # a solid unique pair of identifiers to identify the pass are
172
177
  serial_number = options['serialNumber']
173
178
  device_library_identifier = options['deviceLibraryIdentifier']
179
+ the_pass_type_identifier = options["passTypeIdentifier"]
180
+ the_authentication_token = options['authToken']
174
181
  # return a status 200 to indicate that the pass was successfully unregistered.
175
182
  {:status => 200}
176
183
  end
@@ -187,7 +194,7 @@ module Passbook
187
194
 
188
195
  # This is called whenever there is something from the update process that is a warning
189
196
  # or error
190
- def self.log(log)
197
+ def self.passbook_log(log)
191
198
  # this is a VERY crude logging example. use the logger of your choice here.
192
199
  p "#{Time.now} #{log}"
193
200
  end
data/Rakefile CHANGED
@@ -19,6 +19,7 @@ Jeweler::Tasks.new do |gem|
19
19
  gem.description = %Q{This gem allows you to create IOS Passbooks. Unlike some, this works with Rails but does not require it.}
20
20
  gem.email = ['thomas@lauro.fr', 'lgleason@polyglotprogramminginc.com']
21
21
  gem.authors = ['Thomas Lauro', 'Lance Gleason']
22
+ gem.executables = ['pk']
22
23
  # dependencies defined in Gemfile
23
24
  end
24
25
  Jeweler::RubygemsDotOrgTasks.new
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.2.1
1
+ 0.3.1
data/bin/pk ADDED
@@ -0,0 +1,22 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'commander/import'
4
+ require 'terminal-table'
5
+
6
+ $:.push File.expand_path("../../lib", __FILE__)
7
+ require 'passbook'
8
+ require 'utils/command_utils'
9
+
10
+ HighLine.track_eof = false # Fix for built-in Ruby
11
+ Signal.trap("INT") {} # Suppress backtrace when exiting command
12
+
13
+ program :version, '0.1'
14
+ program :description, 'A command-line interface for generating and previewing passbook passes'
15
+
16
+ program :help, 'Author', 'Thomas Lauro <>, Lance Gleason <lgleason@polyglotprogramminginc.com>'
17
+ program :help, 'Website', 'https://github.com/frozon/passbook'
18
+ program :help_formatter, :compact
19
+
20
+ default_command :help
21
+
22
+ require 'commands/commands'
@@ -0,0 +1,62 @@
1
+ command :build do |c|
2
+ c.syntax = 'pk build [PASSNAME]'
3
+ c.summary = 'Creates a .pkpass archive'
4
+ c.description = ''
5
+
6
+ c.example 'description', 'pk archive mypass -o mypass.pkpass'
7
+ c.option '-w', '--wwdc_certificate /path/to/wwdc_cert.pem', 'Pass certificate'
8
+ c.option '-k', '--p12_key /path/to/cert.p12'
9
+ c.option '-c', '--p12_certificate /path/to/cert.p12'
10
+ c.option '-p', '--password password', 'certificate password'
11
+ c.option '-o', '--output /path/to/out.pkpass', '.pkpass output filepath'
12
+
13
+ c.action do |args, options|
14
+ determine_directory! unless @directory = args.first
15
+ validate_directory!
16
+
17
+ @filepath = options.output || "#{@directory}.pkpass"
18
+ validate_output_filepath!
19
+
20
+ @certificate = options.wwdc_certificate
21
+ validate_certificate!
22
+
23
+ @password = (options.password ? options.password : (ask("Enter certificate password:"){|q| q.echo = false}))
24
+
25
+ Passbook.configure do |passbook|
26
+ passbook.wwdc_cert = @certificate
27
+ passbook.p12_key = options.p12_key
28
+ passbook.p12_certificate = options.p12_certificate
29
+ passbook.p12_password = @password
30
+ end
31
+
32
+ assets = CommandUtils.get_assets @directory
33
+ pass_json = File.read(assets.delete(assets.detect{|file| File.basename(file) == 'pass.json'}))
34
+ pass = Passbook::PKPass.new(pass_json)
35
+ pass.addFiles assets
36
+
37
+ begin
38
+ pass_stream = pass.stream
39
+ pass_string = pass_stream.string
40
+
41
+ File.open(@filepath, 'w') do |f|
42
+ f.write pass_string
43
+ end
44
+ rescue OpenSSL::PKCS12::PKCS12Error => error
45
+ say_error "Error: #{error.message}"
46
+ say_warning "You may be getting this error because the certificate password is either incorrect or missing"
47
+ abort
48
+ rescue => error
49
+ say_error "Error: #{error.message}" and abort
50
+ end
51
+ end
52
+ end
53
+
54
+ alias_command :archive, :build
55
+ alias_command :b, :build
56
+
57
+ private
58
+
59
+ def validate_output_filepath!
60
+ say_error "Filepath required" and abort if @filepath.nil? or @filepath.empty?
61
+ say_error "#{@filepath} already exists" and abort if File.exist?(@filepath)
62
+ end
@@ -0,0 +1,31 @@
1
+ $:.push File.expand_path('../', __FILE__)
2
+
3
+ require 'commands/build'
4
+ require 'commands/generate'
5
+ #require 'commands/serve'
6
+ # this was added for testability because I couldn't figure out something better.
7
+
8
+ private
9
+
10
+ def determine_directory!
11
+ files = Dir['*/pass.json']
12
+ @directory ||= case files.length
13
+ when 0 then nil
14
+ when 1 then File.dirname(files.first)
15
+ else
16
+ @directory = choose "Select a directory:", *files.collect{|f| File.dirname(f)}
17
+ end
18
+ end
19
+
20
+ def validate_directory!
21
+ say_error "Missing argument" and abort if @directory.nil?
22
+ say_error "Directory #{@directory} does not exist" and abort unless File.directory?(@directory)
23
+ say_error "Directory #{@directory} is not a valid pass" and abort unless File.exist?(File.join(@directory, "pass.json"))
24
+ end
25
+
26
+ def validate_certificate!
27
+ say_error "Missing or invalid certificate file" and abort if @certificate.nil? or not File.exist?(@certificate)
28
+ end
29
+
30
+
31
+
@@ -0,0 +1,44 @@
1
+ require 'fileutils'
2
+
3
+ command :generate do |c|
4
+ c.syntax = 'pk generate PASSNAME'
5
+ c.summary = 'Generates a template pass directory'
6
+ c.description = ''
7
+
8
+ c.example 'description', 'pk generate mypass'
9
+ c.option '-T', '--type [boardingPass|coupon|eventTicket|storeCard|generic]', 'Type of pass'
10
+
11
+ c.action do |args, options|
12
+ @directory = args.first
13
+ @directory ||= ask "Enter a passbook name: "
14
+ say_error "Missing pass name" and abort if @directory.nil? or @directory.empty?
15
+ say_error "Directory #{@directory} already exists" and abort if File.directory?(@directory)
16
+ say_error "File exists at #{@directory}" and abort if File.exist?(@directory)
17
+
18
+ @type = options.type
19
+ determine_type! unless @type
20
+ validate_type!
21
+
22
+ FileUtils.mkdir_p @directory
23
+ FileUtils.cp File.join(CommandUtils.get_current_directory, '..', 'commands/templates', "#{@type}.json"), File.join(@directory, 'pass.json')
24
+ ['icon.png', 'icon@2x.png'].each do |file|
25
+ FileUtils.touch File.join(@directory, file)
26
+ end
27
+
28
+ say_ok "Pass generated in #{@directory}"
29
+ end
30
+ end
31
+
32
+ alias_command :new, :generate
33
+ alias_command :g, :generate
34
+
35
+ private
36
+
37
+ def determine_type!
38
+ @type ||= choose "Select a pass type", *Passbook::PKPass::TYPES
39
+ end
40
+
41
+ def validate_type!
42
+ say_error %{Invalid type: "#{@type}", expected one of: [#{Passbook::PKPass::TYPES.join(', ')}]} and abort unless Passbook::PKPass::TYPES.include?(@type)
43
+ end
44
+
@@ -0,0 +1,56 @@
1
+ {
2
+ "formatVersion" : 1,
3
+ "passTypeIdentifier" : "pass.com.example.boarding-pass",
4
+ "description" : "Example Boarding Pass",
5
+ "teamIdentifier": "Example",
6
+ "organizationName": "Example",
7
+ "serialNumber" : "123456",
8
+ "foregroundColor": "#866B23",
9
+ "backgroundColor": "#FFD248",
10
+ "boardingPass" : {
11
+ "primaryFields" : [
12
+ {
13
+ "key" : "origin",
14
+ "label" : "Atlanta",
15
+ "value" : "ATL"
16
+ },
17
+ {
18
+ "key" : "destination",
19
+ "label" : "Johannesburg",
20
+ "value" : "JNB"
21
+ }
22
+ ],
23
+ "secondaryFields" : [
24
+ {
25
+ "key" : "boarding-gate",
26
+ "label" : "Gate",
27
+ "value" : "F12"
28
+ }
29
+ ],
30
+ "auxiliaryFields" : [
31
+ {
32
+ "key" : "seat",
33
+ "label" : "Seat",
34
+ "value" : "7A"
35
+ },
36
+ {
37
+ "key" : "passenger-name",
38
+ "label" : "Passenger",
39
+ "value" : "Honey Badger"
40
+ }
41
+ ],
42
+ "transitType" : "PKTransitTypeAir",
43
+ "barcode" : {
44
+ "message" : "DL123",
45
+ "format" : "PKBarcodeFormatQR",
46
+ "messageEncoding" : "iso-8859-1"
47
+ },
48
+ "backFields" : [
49
+ {
50
+ "key" : "terms",
51
+ "label" : "Terms and Conditions",
52
+ "value" : "Valid for date of travel only"
53
+ }
54
+ ]
55
+ }
56
+ }
@@ -0,0 +1,33 @@
1
+ {
2
+ "formatVersion" : 1,
3
+ "passTypeIdentifier" : "pass.com.example.coupon",
4
+ "description" : "Example Coupon",
5
+ "teamIdentifier": "Example",
6
+ "organizationName": "Example",
7
+ "serialNumber" : "123456",
8
+ "foregroundColor": "#FFFFFF",
9
+ "backgroundColor": "#C799FF",
10
+ "generic" : {
11
+ "primaryFields" : [
12
+
13
+ ],
14
+ "secondaryFields" : [
15
+
16
+ ],
17
+ "auxiliaryFields" : [
18
+
19
+ ],
20
+ "barcode" : {
21
+ "message" : "ABCD 123 EFGH 456 IJKL 789 MNOP",
22
+ "format" : "PKBarcodeFormatPDF417",
23
+ "messageEncoding" : "iso-8859-1"
24
+ },
25
+ "backFields" : [
26
+ {
27
+ "key" : "terms",
28
+ "label" : "Terms and Conditions",
29
+ "value" : "T's and C's Apply"
30
+ }
31
+ ]
32
+ }
33
+ }