passbookpgh 0.4.5
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 +7 -0
- data/.travis.yml +7 -0
- data/Gemfile +17 -0
- data/Gemfile.lock +130 -0
- data/LICENSE +22 -0
- data/README.md +294 -0
- data/Rakefile +36 -0
- data/VERSION +1 -0
- data/bin/pk +22 -0
- data/lib/commands/build.rb +62 -0
- data/lib/commands/commands.rb +31 -0
- data/lib/commands/generate.rb +44 -0
- data/lib/commands/templates/boarding-pass.json +56 -0
- data/lib/commands/templates/coupon.json +33 -0
- data/lib/commands/templates/event-ticket.json +33 -0
- data/lib/commands/templates/generic.json +33 -0
- data/lib/commands/templates/store-card.json +33 -0
- data/lib/passbook/pkpass.rb +121 -0
- data/lib/passbook/push_notification.rb +19 -0
- data/lib/passbook/signer.rb +40 -0
- data/lib/passbook/version.rb +3 -0
- data/lib/passbook.rb +15 -0
- data/lib/rack/passbook_rack.rb +98 -0
- data/lib/rails/generators/passbook/config/config_generator.rb +16 -0
- data/lib/rails/generators/passbook/config/templates/initializer.rb +13 -0
- data/lib/utils/command_utils.rb +12 -0
- data/passbookpgh.gemspec +110 -0
- data/spec/data/icon.png +0 -0
- data/spec/data/icon@2x.png +0 -0
- data/spec/data/logo.png +0 -0
- data/spec/data/logo@2x.png +0 -0
- data/spec/lib/commands/build_spec.rb +92 -0
- data/spec/lib/commands/commands_spec.rb +102 -0
- data/spec/lib/commands/commands_spec_helper.rb +69 -0
- data/spec/lib/commands/generate_spec.rb +72 -0
- data/spec/lib/passbook/pkpass_spec.rb +108 -0
- data/spec/lib/passbook/push_notification_spec.rb +23 -0
- data/spec/lib/passbook/signer_spec.rb +84 -0
- data/spec/lib/rack/passbook_rack_spec.rb +233 -0
- data/spec/spec_helper.rb +9 -0
- metadata +244 -0
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
require 'lib/commands/commands_spec_helper'
|
|
2
|
+
require 'passbook'
|
|
3
|
+
|
|
4
|
+
describe 'Build' do
|
|
5
|
+
|
|
6
|
+
before :each do
|
|
7
|
+
$stderr = StringIO.new
|
|
8
|
+
mock_terminal
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
context 'command' do
|
|
12
|
+
specify 'missing directory' do
|
|
13
|
+
run_command 'build' do
|
|
14
|
+
@output.string.should eq "\e[31mMissing argument\e[0m\n"
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
context 'good directory' do
|
|
19
|
+
|
|
20
|
+
before :each do
|
|
21
|
+
File.should_receive(:directory?).with('scraps').and_return true
|
|
22
|
+
File.should_receive(:exist?).once.with('scraps/pass.json').and_return true
|
|
23
|
+
File.should_receive(:exist?).once.with('scraps.pkpass').and_return false
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
specify 'no certificate file' do
|
|
27
|
+
run_command 'build', 'scraps' do
|
|
28
|
+
@output.string.should eq "\e[31mMissing or invalid certificate file\e[0m\n"
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
context 'good certificate file' do
|
|
33
|
+
before :each do
|
|
34
|
+
File.should_receive(:exist?).with('jackels').and_return true
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
specify 'no certificate password entered' do
|
|
38
|
+
run_command 'build', 'scraps', '-w', 'jackels' do
|
|
39
|
+
@output.string.should eq "Enter certificate password:\n\n"
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
context 'all required values' do
|
|
44
|
+
|
|
45
|
+
let(:pass_json) {'{"this":"is awesome json"}'}
|
|
46
|
+
let(:pass_assets) {['pass.json', 'something.jpeg']}
|
|
47
|
+
|
|
48
|
+
before :each do
|
|
49
|
+
Passbook.should_receive(:wwdc_cert=).with 'jackels'
|
|
50
|
+
Passbook.should_receive(:p12_key=).with 'badger_key'
|
|
51
|
+
Passbook.should_receive(:p12_certificate=).with 'badger_cert'
|
|
52
|
+
Passbook.should_receive(:p12_password=).with 'bees'
|
|
53
|
+
CommandUtils.should_receive(:get_assets).with('scraps').and_return pass_assets
|
|
54
|
+
@pk_pass = double 'pk pass'
|
|
55
|
+
File.should_receive(:read).with('pass.json').and_return pass_json
|
|
56
|
+
Passbook::PKPass.should_receive(:new).with(pass_json).and_return @pk_pass
|
|
57
|
+
@pk_pass.should_receive(:addFiles).with pass_assets
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
specify 'are set from command line' do
|
|
61
|
+
pass_stream = double 'passbook stream'
|
|
62
|
+
pass_stream.should_receive(:string).and_return 'my badass pass'
|
|
63
|
+
@pk_pass.should_receive(:stream).and_return pass_stream
|
|
64
|
+
File.should_receive(:open).with('scraps.pkpass', 'w')
|
|
65
|
+
|
|
66
|
+
run_command 'build', 'scraps', '-w', 'jackels',
|
|
67
|
+
'-p', 'bees', '-k', 'badger_key', '-c', 'badger_cert' do
|
|
68
|
+
@output.string.should eq ""
|
|
69
|
+
end
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
specify 'should catch a general error' do
|
|
73
|
+
@pk_pass.should_receive(:stream).and_raise(StandardError.new('I have failed'))
|
|
74
|
+
run_command 'build', 'scraps', '-w', 'jackels',
|
|
75
|
+
'-p', 'bees', '-k', 'badger_key', '-c', 'badger_cert' do
|
|
76
|
+
@output.string.should eq "\e[31mError: I have failed\e[0m\n"
|
|
77
|
+
end
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
specify 'should catch a general error' do
|
|
81
|
+
@pk_pass.should_receive(:stream).and_raise(OpenSSL::PKCS12::PKCS12Error.new('I am a failure'))
|
|
82
|
+
run_command 'build', 'scraps', '-w', 'jackels',
|
|
83
|
+
'-p', 'bees', '-k', 'badger_key', '-c', 'badger_cert' do
|
|
84
|
+
@output.string.should eq "\e[31mError: I am a failure\e[0m\n\e[33mYou may be getting this error because the certificate password is either incorrect or missing\e[0m\n"
|
|
85
|
+
end
|
|
86
|
+
end
|
|
87
|
+
end
|
|
88
|
+
end
|
|
89
|
+
end
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
end
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
require 'lib/commands/commands_spec_helper'
|
|
2
|
+
|
|
3
|
+
describe 'Commands' do
|
|
4
|
+
|
|
5
|
+
before :each do
|
|
6
|
+
program :version, '1.2.3'
|
|
7
|
+
program :description, "Honey Badger Don't Care"
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
context 'determine directory' do
|
|
11
|
+
|
|
12
|
+
specify 'no directories' do
|
|
13
|
+
Dir.should_receive(:[]).and_return []
|
|
14
|
+
determine_directory!
|
|
15
|
+
@directory.should eq nil
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
specify 'one directory present' do
|
|
19
|
+
Dir.should_receive(:[]).and_return ['ass']
|
|
20
|
+
File.should_receive(:dirname).with('ass').and_return('/honey/badger/is/bad/ass')
|
|
21
|
+
determine_directory!
|
|
22
|
+
@directory.should eq '/honey/badger/is/bad/ass'
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
specify 'multiple directories' do
|
|
26
|
+
Dir.should_receive(:[]).and_return ['cobras', 'bee_larvae']
|
|
27
|
+
File.should_receive(:dirname).with('cobras').and_return('/yummy/cobras')
|
|
28
|
+
File.should_receive(:dirname).with('bee_larvae').and_return('/disgusting/bee_larvae')
|
|
29
|
+
self.should_receive(:choose).with('Select a directory:',
|
|
30
|
+
'/yummy/cobras', '/disgusting/bee_larvae').and_return '/yummy/cobras'
|
|
31
|
+
determine_directory!
|
|
32
|
+
@directory.should eq '/yummy/cobras'
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
context 'validate directory' do
|
|
38
|
+
|
|
39
|
+
specify 'missing directory' do
|
|
40
|
+
self.should_receive(:say_error).with('Missing argument').and_return true
|
|
41
|
+
lambda {
|
|
42
|
+
@directory = nil
|
|
43
|
+
validate_directory!
|
|
44
|
+
}.should exit_with_code(1)
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
specify 'directory does not exist' do
|
|
48
|
+
self.should_receive(:say_error).with("Directory scraps does not exist").and_return true
|
|
49
|
+
File.should_receive(:directory?).with('scraps').and_return false
|
|
50
|
+
lambda {
|
|
51
|
+
@directory = 'scraps'
|
|
52
|
+
validate_directory!
|
|
53
|
+
}.should exit_with_code(1)
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
specify 'directory does not have a valid pass' do
|
|
57
|
+
self.should_receive(:say_error).with("Directory scraps is not a valid pass").and_return true
|
|
58
|
+
File.should_receive(:directory?).with('scraps').and_return true
|
|
59
|
+
File.should_receive(:exist?).with('scraps/pass.json').and_return false
|
|
60
|
+
lambda {
|
|
61
|
+
@directory = 'scraps'
|
|
62
|
+
validate_directory!
|
|
63
|
+
}.should exit_with_code(1)
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
specify 'directory has valid pass' do
|
|
67
|
+
File.should_receive(:directory?).with('scraps').and_return true
|
|
68
|
+
File.should_receive(:exist?).with('scraps/pass.json').and_return true
|
|
69
|
+
lambda {
|
|
70
|
+
@directory = 'scraps'
|
|
71
|
+
validate_directory!
|
|
72
|
+
}.should_not exit_with_code(1)
|
|
73
|
+
end
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
context 'validate certificate' do
|
|
77
|
+
specify 'nil certificate' do
|
|
78
|
+
self.should_receive(:say_error).with("Missing or invalid certificate file").and_return true
|
|
79
|
+
lambda {
|
|
80
|
+
@certificate = nil
|
|
81
|
+
validate_certificate!
|
|
82
|
+
}.should exit_with_code(1)
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
specify 'certificate file does not exist' do
|
|
86
|
+
self.should_receive(:say_error).with("Missing or invalid certificate file").and_return true
|
|
87
|
+
File.should_receive(:exist?).with('jackels').and_return false
|
|
88
|
+
lambda {
|
|
89
|
+
@certificate = 'jackels'
|
|
90
|
+
validate_certificate!
|
|
91
|
+
}.should exit_with_code(1)
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
specify 'certificate file exists' do
|
|
95
|
+
File.should_receive(:exist?).with('jackels').and_return true
|
|
96
|
+
lambda {
|
|
97
|
+
@certificate = 'jackels'
|
|
98
|
+
validate_certificate!
|
|
99
|
+
}.should_not exit_with_code(1)
|
|
100
|
+
end
|
|
101
|
+
end
|
|
102
|
+
end
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
require 'terminal-table'
|
|
3
|
+
require 'commander/import'
|
|
4
|
+
require 'utils/command_utils'
|
|
5
|
+
|
|
6
|
+
def load_commands
|
|
7
|
+
Dir['lib/commands/**/*.rb'].each {|f|
|
|
8
|
+
load File.join(File.dirname(__FILE__), '../../..', f)
|
|
9
|
+
require File.join(File.dirname(__FILE__), '../../..', f.gsub(/.rb/, ''))
|
|
10
|
+
}
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def mock_terminal
|
|
14
|
+
@input = StringIO.new
|
|
15
|
+
@output = StringIO.new
|
|
16
|
+
$terminal = HighLine.new @input, @output
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def new_command_runner *args, &block
|
|
20
|
+
Commander::Runner.instance_variable_set :"@singleton", Commander::Runner.new(args)
|
|
21
|
+
program :version, '1.2.3'
|
|
22
|
+
program :description, "Honey Badger Don't Care"
|
|
23
|
+
yield if block
|
|
24
|
+
Commander::Runner.instance
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def run *args
|
|
28
|
+
runner = new_command_runner(*args) do
|
|
29
|
+
load_commands
|
|
30
|
+
end
|
|
31
|
+
runner.run!
|
|
32
|
+
@output.string
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
RSpec::Matchers.define :exit_with_code do |exp_code|
|
|
36
|
+
actual = nil
|
|
37
|
+
match do |block|
|
|
38
|
+
begin
|
|
39
|
+
block.call
|
|
40
|
+
rescue SystemExit => e
|
|
41
|
+
actual = e.status
|
|
42
|
+
end
|
|
43
|
+
actual and actual == exp_code
|
|
44
|
+
end
|
|
45
|
+
failure_message_for_should do |block|
|
|
46
|
+
"expected block to call exit(#{exp_code}) but exit" +
|
|
47
|
+
(actual.nil? ? " not called" : "(#{actual}) was called")
|
|
48
|
+
end
|
|
49
|
+
failure_message_for_should_not do |block|
|
|
50
|
+
"expected block not to call exit(#{exp_code})"
|
|
51
|
+
end
|
|
52
|
+
description do
|
|
53
|
+
"expect block to call exit(#{exp_code})"
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
def run_raw_command(*args)
|
|
58
|
+
lambda{
|
|
59
|
+
run(*args)
|
|
60
|
+
}.should raise_error(SystemExit, ' ')
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
def run_command(*args, &block)
|
|
64
|
+
begin
|
|
65
|
+
run_raw_command *args
|
|
66
|
+
rescue
|
|
67
|
+
yield
|
|
68
|
+
end
|
|
69
|
+
end
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
require 'lib/commands/commands_spec_helper'
|
|
2
|
+
require 'passbook'
|
|
3
|
+
|
|
4
|
+
describe 'Generate' do
|
|
5
|
+
|
|
6
|
+
before :each do
|
|
7
|
+
$stderr = StringIO.new
|
|
8
|
+
mock_terminal
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
context 'command' do
|
|
12
|
+
specify 'no options' do
|
|
13
|
+
run_command 'generate' do
|
|
14
|
+
@output.string.should eq 'Enter a passbook name: '
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
specify 'passbook entered directory already exists' do
|
|
20
|
+
@input << "my_awesome_passbook\n"
|
|
21
|
+
@input.rewind
|
|
22
|
+
File.should_receive(:directory?).with('my_awesome_passbook').and_return true
|
|
23
|
+
run_command 'generate' do
|
|
24
|
+
@output.string.should eq "Enter a passbook name: \e[31mDirectory my_awesome_passbook already exists\e[0m\n"
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
specify 'passbook entered file already exists' do
|
|
29
|
+
@input << "my_awesome_passbook\n"
|
|
30
|
+
@input.rewind
|
|
31
|
+
File.should_receive(:directory?).with('my_awesome_passbook').and_return false
|
|
32
|
+
File.should_receive(:exist?).with('my_awesome_passbook').and_return true
|
|
33
|
+
run_command 'generate' do
|
|
34
|
+
@output.string.should eq "Enter a passbook name: \e[31mFile exists at my_awesome_passbook\e[0m\n"
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
context 'valid pass directory' do
|
|
39
|
+
|
|
40
|
+
before :each do
|
|
41
|
+
File.should_receive(:directory?).with('my_awesome_passbook').and_return false
|
|
42
|
+
File.should_receive(:exist?).with('my_awesome_passbook').and_return false
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
specify 'invalid type' do
|
|
46
|
+
@input << "my_awesome_passbook\n"
|
|
47
|
+
@input.rewind
|
|
48
|
+
run_command 'generate', '-T', 'honey_badger' do
|
|
49
|
+
@output.string.should eq "Enter a passbook name: \e[31mInvalid type: \"honey_badger\", expected one of: [boarding-pass, coupon, event-ticket, store-card, generic]\e[0m\n"
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
specify 'valid type' do
|
|
54
|
+
CommandUtils.should_receive(:get_current_directory).and_return('')
|
|
55
|
+
FileUtils.should_receive(:mkdir_p).with('my_awesome_passbook')
|
|
56
|
+
FileUtils.should_receive(:cp).with("/../commands/templates/boarding-pass.json", "my_awesome_passbook/pass.json")
|
|
57
|
+
FileUtils.should_receive(:touch).with("my_awesome_passbook/icon.png")
|
|
58
|
+
FileUtils.should_receive(:touch).with("my_awesome_passbook/icon@2x.png")
|
|
59
|
+
@input << "1\n"
|
|
60
|
+
@input.rewind
|
|
61
|
+
run_command 'generate', 'my_awesome_passbook' do
|
|
62
|
+
@output.string.should eq "Select a pass type\n1. boarding-pass\n2. coupon\n3. event-ticket\n4. store-card\n5. generic\n? \e[32mPass generated in my_awesome_passbook\e[0m\n"
|
|
63
|
+
end
|
|
64
|
+
end
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
end
|
|
72
|
+
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
|
|
3
|
+
describe Passbook do
|
|
4
|
+
|
|
5
|
+
let (:content) {{
|
|
6
|
+
:formatVersion => 1,
|
|
7
|
+
:passTypeIdentifier => "pass.passbook.test",
|
|
8
|
+
:serialNumber => "001",
|
|
9
|
+
:teamIdentifier => ENV['APPLE_TEAM_ID'],
|
|
10
|
+
:relevantDate => "2012-10-02",
|
|
11
|
+
:locations => [ #TODO
|
|
12
|
+
{
|
|
13
|
+
:longitude => 2.35403,
|
|
14
|
+
:latitude => 48.893855
|
|
15
|
+
}
|
|
16
|
+
],
|
|
17
|
+
:organizationName => "WorldCo",
|
|
18
|
+
:description => "description",
|
|
19
|
+
:foregroundColor => "rgb(227,210,18)",
|
|
20
|
+
:backgroundColor => "rgb(60, 65, 76)",
|
|
21
|
+
:logoText => "Event",
|
|
22
|
+
:eventTicket => {
|
|
23
|
+
:primaryFields => [
|
|
24
|
+
{
|
|
25
|
+
:key => "date",
|
|
26
|
+
:label => "DATE",
|
|
27
|
+
:value => "date"
|
|
28
|
+
}
|
|
29
|
+
],
|
|
30
|
+
:backFields => [
|
|
31
|
+
{
|
|
32
|
+
:key => "description",
|
|
33
|
+
:label => "DESCRIPTION",
|
|
34
|
+
:value => "description"
|
|
35
|
+
},
|
|
36
|
+
{
|
|
37
|
+
:key => "aboutUs",
|
|
38
|
+
:label => "MORE",
|
|
39
|
+
:value => "about us"
|
|
40
|
+
}
|
|
41
|
+
]
|
|
42
|
+
}
|
|
43
|
+
}}
|
|
44
|
+
|
|
45
|
+
let (:signer) {double 'signer'}
|
|
46
|
+
let (:pass) {Passbook::PKPass.new content.to_json, signer}
|
|
47
|
+
|
|
48
|
+
context 'outputs' do
|
|
49
|
+
let (:base_path) {'spec/data'}
|
|
50
|
+
let (:entries) {["pass.json", "manifest.json", "signature", "icon.png", "icon@2x.png", "logo.png", "logo@2x.png"]}
|
|
51
|
+
|
|
52
|
+
before :each do
|
|
53
|
+
pass.addFiles ["#{base_path}/icon.png","#{base_path}/icon@2x.png","#{base_path}/logo.png","#{base_path}/logo@2x.png"]
|
|
54
|
+
signer.should_receive(:sign).and_return('Signed by the Honey Badger')
|
|
55
|
+
@file_entries = []
|
|
56
|
+
Zip::InputStream::open(zip_path) {|io|
|
|
57
|
+
while (entry = io.get_next_entry)
|
|
58
|
+
@file_entries << entry.name
|
|
59
|
+
end
|
|
60
|
+
}
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
context 'zip file' do
|
|
64
|
+
let(:zip_path) {pass.file.path}
|
|
65
|
+
|
|
66
|
+
subject {entries}
|
|
67
|
+
it {should eq @file_entries}
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
context 'StringIO' do
|
|
71
|
+
let (:temp_file) {Tempfile.new("pass.pkpass")}
|
|
72
|
+
let (:zip_path) {
|
|
73
|
+
zip_out = pass.stream
|
|
74
|
+
zip_out.class.should eq(Class::StringIO)
|
|
75
|
+
#creating file, re-reading zip to see if correctly formed
|
|
76
|
+
temp_file.write zip_out.string
|
|
77
|
+
temp_file.close
|
|
78
|
+
temp_file.path
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
subject {entries}
|
|
82
|
+
it {should eq @file_entries}
|
|
83
|
+
|
|
84
|
+
after do
|
|
85
|
+
temp_file.delete
|
|
86
|
+
end
|
|
87
|
+
end
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
# TODO: find a proper way to do this
|
|
91
|
+
context 'Error catcher' do
|
|
92
|
+
context 'formatVersion' do
|
|
93
|
+
let (:base_path) {'spec/data'}
|
|
94
|
+
|
|
95
|
+
before :each do
|
|
96
|
+
pass.addFiles ["#{base_path}/icon.png","#{base_path}/icon@2x.png","#{base_path}/logo.png","#{base_path}/logo@2x.png"]
|
|
97
|
+
tpass = JSON.parse(pass.pass)
|
|
98
|
+
tpass['formatVersion'] = 'It should be a numeric'
|
|
99
|
+
pass.pass = tpass.to_json
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
it "raise an error" do
|
|
103
|
+
expect { pass.build }.to raise_error('Format Version should be a numeric')
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
end
|
|
107
|
+
end
|
|
108
|
+
end
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
require 'grocer'
|
|
3
|
+
|
|
4
|
+
describe Passbook::PushNotification do
|
|
5
|
+
|
|
6
|
+
context 'send notification' do
|
|
7
|
+
let(:grocer_pusher) {double 'Grocer'}
|
|
8
|
+
let(:notification) {double 'Grocer::Notification'}
|
|
9
|
+
let(:notification_settings) {{:certificate => './notification_cert.pem', :gateway => 'honeybadger.apple.com', :passphrase => 'ah@rdvintAge'}}
|
|
10
|
+
|
|
11
|
+
before :each do
|
|
12
|
+
Passbook.should_receive(:notification_cert).and_return './notification_cert.pem'
|
|
13
|
+
Grocer::PassbookNotification.should_receive(:new).with(:device_token => 'my token').and_return notification
|
|
14
|
+
grocer_pusher.should_receive(:push).with(notification).and_return 55
|
|
15
|
+
Grocer.should_receive(:pusher).with(notification_settings).and_return grocer_pusher
|
|
16
|
+
Passbook.should_receive(:notification_gateway).and_return 'honeybadger.apple.com'
|
|
17
|
+
Passbook.should_receive(:notification_passphrase).and_return 'ah@rdvintAge'
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
subject {Passbook::PushNotification.send_notification('my token')}
|
|
21
|
+
it {should eq 55}
|
|
22
|
+
end
|
|
23
|
+
end
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
|
|
3
|
+
describe 'Signer' do
|
|
4
|
+
context 'signatures' do
|
|
5
|
+
|
|
6
|
+
context 'p12_cert_and_key' do
|
|
7
|
+
context 'pem p12 certs' do
|
|
8
|
+
context 'using config file certificates' do
|
|
9
|
+
before do
|
|
10
|
+
Passbook.should_receive(:p12_password).and_return 'password'
|
|
11
|
+
Passbook.should_receive(:p12_key).and_return 'my_p12_key'
|
|
12
|
+
Passbook.should_receive(:p12_certificate).and_return 'my_p12_certificate'
|
|
13
|
+
Passbook.should_receive(:wwdc_cert).and_return 'i_love_robots'
|
|
14
|
+
File.should_receive(:read).with('my_p12_key').and_return 'my_p12_key_file'
|
|
15
|
+
File.should_receive(:read).with('my_p12_certificate').and_return 'my_p12_certificate_file'
|
|
16
|
+
OpenSSL::PKey::RSA.should_receive(:new).with('my_p12_key_file', 'password').and_return 'my_rsa_key'
|
|
17
|
+
OpenSSL::X509::Certificate.should_receive(:new).with('my_p12_certificate_file').and_return 'my_ssl_p12_cert'
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
subject {Passbook::Signer.new.key_hash}
|
|
21
|
+
its([:key]) {should eq 'my_rsa_key'}
|
|
22
|
+
its([:cert]) {should eq 'my_ssl_p12_cert'}
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
context 'using passed in certificates' do
|
|
26
|
+
before do
|
|
27
|
+
Passbook.should_receive(:p12_password).never
|
|
28
|
+
Passbook.should_receive(:p12_key).never
|
|
29
|
+
Passbook.should_receive(:p12_certificate).never
|
|
30
|
+
Passbook.should_receive(:wwdc_cert).never
|
|
31
|
+
File.should_receive(:read).with('my_p12_key').and_return 'my_p12_key_file'
|
|
32
|
+
File.should_receive(:read).with('my_p12_certificate').and_return 'my_p12_certificate_file'
|
|
33
|
+
OpenSSL::PKey::RSA.should_receive(:new).with('my_p12_key_file', 'password').and_return 'my_rsa_key'
|
|
34
|
+
OpenSSL::X509::Certificate.should_receive(:new).with('my_p12_certificate_file').and_return 'my_ssl_p12_cert'
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
subject {Passbook::Signer.new(certificate: 'my_p12_certificate', password: 'password',
|
|
38
|
+
key: 'my_p12_key', wwdc_cert: 'i_love_robots').key_hash}
|
|
39
|
+
its([:key]) {should eq 'my_rsa_key'}
|
|
40
|
+
its([:cert]) {should eq 'my_ssl_p12_cert'}
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
context 'p12 files' do
|
|
45
|
+
let (:p12) { double('OpenSSL::PKCS12') }
|
|
46
|
+
let (:final_hash) {{:key => 'my_final_p12_key', :cert => 'my_final_p12_cert'}}
|
|
47
|
+
context 'using config file certificates' do
|
|
48
|
+
before do
|
|
49
|
+
p12.should_receive(:key).and_return final_hash[:key]
|
|
50
|
+
p12.should_receive(:certificate).and_return final_hash[:cert]
|
|
51
|
+
Passbook.should_receive(:p12_password).and_return 'password'
|
|
52
|
+
Passbook.should_receive(:wwdc_cert).and_return 'i_love_robots'
|
|
53
|
+
Passbook.should_receive(:p12_certificate).and_return 'my_p12_cert'
|
|
54
|
+
Passbook.should_receive(:p12_key).and_return nil
|
|
55
|
+
File.should_receive(:read).with('my_p12_cert').and_return 'my_p12_cert_file'
|
|
56
|
+
OpenSSL::PKCS12.should_receive(:new).with('my_p12_cert_file', 'password').and_return p12
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
subject {Passbook::Signer.new.key_hash}
|
|
60
|
+
its([:key]) {should eq final_hash[:key]}
|
|
61
|
+
its([:cert]) {should eq final_hash[:cert]}
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
context 'using passed in certificates' do
|
|
65
|
+
before do
|
|
66
|
+
p12.should_receive(:key).and_return final_hash[:key]
|
|
67
|
+
p12.should_receive(:certificate).and_return final_hash[:cert]
|
|
68
|
+
Passbook.should_receive(:p12_password).never
|
|
69
|
+
Passbook.should_receive(:p12_key).never
|
|
70
|
+
Passbook.should_receive(:p12_certificate).never
|
|
71
|
+
Passbook.should_receive(:wwdc_cert).never
|
|
72
|
+
File.should_receive(:read).with('my_p12_cert').and_return 'my_p12_cert_file'
|
|
73
|
+
OpenSSL::PKCS12.should_receive(:new).with('my_p12_cert_file', 'password').and_return p12
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
subject {Passbook::Signer.new(certificate: 'my_p12_cert', password: 'password',
|
|
77
|
+
wwdc_cert: 'i_love_robots').key_hash}
|
|
78
|
+
its([:key]) {should eq final_hash[:key]}
|
|
79
|
+
its([:cert]) {should eq final_hash[:cert]}
|
|
80
|
+
end
|
|
81
|
+
end
|
|
82
|
+
end
|
|
83
|
+
end
|
|
84
|
+
end
|