passbook2 1.0.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.
- checksums.yaml +7 -0
- data/.travis.yml +7 -0
- data/Gemfile +18 -0
- data/Gemfile.lock +136 -0
- data/LICENSE +22 -0
- data/README.md +271 -0
- data/Rakefile +8 -0
- data/VERSION +1 -0
- data/lib/passbook/pk_multi_pass.rb +26 -0
- data/lib/passbook/pkpass.rb +133 -0
- data/lib/passbook/push_notification.rb +19 -0
- data/lib/passbook/signer.rb +75 -0
- data/lib/passbook/version.rb +3 -0
- data/lib/passbook2.rb +21 -0
- data/passbook.gemspec +59 -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/passbook/pk_multi_pass_spec.rb +67 -0
- data/spec/lib/passbook/pkpass_spec.rb +169 -0
- data/spec/lib/passbook/push_notification_spec.rb +23 -0
- data/spec/lib/passbook/signer_spec.rb +100 -0
- data/spec/spec_helper.rb +8 -0
- metadata +156 -0
@@ -0,0 +1,75 @@
|
|
1
|
+
require 'openssl'
|
2
|
+
require 'base64'
|
3
|
+
|
4
|
+
module Passbook
|
5
|
+
class Signer
|
6
|
+
attr_accessor :certificate,
|
7
|
+
:password,
|
8
|
+
:rsa_private_key,
|
9
|
+
:apple_intermediate_cert,
|
10
|
+
:p12_cert
|
11
|
+
attr_reader :key_hash
|
12
|
+
|
13
|
+
def initialize(params = {})
|
14
|
+
|
15
|
+
# Path to your X509 cert. This is downloaded after generating
|
16
|
+
# a certificate from your apple Pass Type ID on apple's developer site
|
17
|
+
@certificate = params[:certificate] || Passbook.certificate
|
18
|
+
|
19
|
+
# Path to the .pem file generated from public key of the RSA keypair
|
20
|
+
# that was generated when you made a Certificate Signing Request
|
21
|
+
# It'll be in your keychain under the "Common Name" you specified
|
22
|
+
# for the signing request.
|
23
|
+
@rsa_private_key = params[:rsa_private_key] || Passbook.rsa_private_key
|
24
|
+
|
25
|
+
# this should be the password that goes along with the rsa public key
|
26
|
+
@password = params[:password] || Passbook.password
|
27
|
+
|
28
|
+
# "Apple Intermediate Certificate Worldwide Developer Relations" certificate
|
29
|
+
# downloaded from here <https://www.apple.com/certificateauthority/>
|
30
|
+
# Path to your Apple Intermediate Certificate Worldwide Developer Relations
|
31
|
+
# cert.
|
32
|
+
# downloaded from here https://www.apple.com/certificateauthority/
|
33
|
+
# download that .cer file (binary)
|
34
|
+
@apple_intermediate_cert = params[:apple_intermediate_cert] || Passbook.apple_intermediate_cert
|
35
|
+
compute_cert
|
36
|
+
end
|
37
|
+
|
38
|
+
def sign(data)
|
39
|
+
apple_cert = OpenSSL::X509::Certificate.new file_data(apple_intermediate_cert)
|
40
|
+
# In PKCS#7 SignedData, attached and detached formats are supported… In
|
41
|
+
# detached format, data that is signed is not embedded inside the
|
42
|
+
# SignedData package instead it is placed at some external location…
|
43
|
+
|
44
|
+
pk7 = OpenSSL::PKCS7.sign(
|
45
|
+
key_hash[:certificate],
|
46
|
+
key_hash[:rsa_private_key],
|
47
|
+
data.to_s,
|
48
|
+
[apple_cert],
|
49
|
+
OpenSSL::PKCS7::BINARY | OpenSSL::PKCS7::DETACHED
|
50
|
+
)
|
51
|
+
pk7_data = OpenSSL::PKCS7.write_smime pk7
|
52
|
+
|
53
|
+
str_debut = "filename=\"smime.p7s\"\n\n"
|
54
|
+
pk7_data = pk7_data[pk7_data.index(str_debut)+str_debut.length..pk7_data.length-1]
|
55
|
+
str_end = "\n\n------"
|
56
|
+
pk7_data = pk7_data[0..pk7_data.index(str_end)-1]
|
57
|
+
|
58
|
+
Base64.decode64(pk7_data)
|
59
|
+
end
|
60
|
+
|
61
|
+
def compute_cert
|
62
|
+
@key_hash = {
|
63
|
+
rsa_private_key: OpenSSL::PKey::RSA.new(file_data(rsa_private_key), password),
|
64
|
+
certificate: OpenSSL::X509::Certificate.new(file_data(certificate))
|
65
|
+
}
|
66
|
+
end
|
67
|
+
|
68
|
+
def file_data(data)
|
69
|
+
raise "file_data passed nil" if data.nil?
|
70
|
+
return data if data.is_a? String
|
71
|
+
|
72
|
+
data.respond_to?(:read) ? data.read : File.read(data)
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
data/lib/passbook2.rb
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
require "passbook/version"
|
2
|
+
require "passbook/pkpass"
|
3
|
+
require "passbook/pk_multi_pass"
|
4
|
+
require "passbook/signer"
|
5
|
+
require 'active_support/core_ext/module/attribute_accessors'
|
6
|
+
require 'passbook/push_notification'
|
7
|
+
require 'grocer'
|
8
|
+
|
9
|
+
module Passbook
|
10
|
+
mattr_accessor :certificate,
|
11
|
+
:password,
|
12
|
+
:apple_intermediate_cert,
|
13
|
+
:rsa_private_key,
|
14
|
+
:notification_cert,
|
15
|
+
:notification_gateway,
|
16
|
+
:notification_passphrase
|
17
|
+
|
18
|
+
def self.configure
|
19
|
+
yield self
|
20
|
+
end
|
21
|
+
end
|
data/passbook.gemspec
ADDED
@@ -0,0 +1,59 @@
|
|
1
|
+
require_relative "lib/passbook/version"
|
2
|
+
|
3
|
+
|
4
|
+
Gem::Specification.new do |s|
|
5
|
+
s.name = "passbook2"
|
6
|
+
s.version = Passbook::VERSION
|
7
|
+
|
8
|
+
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
9
|
+
s.require_paths = ["lib"]
|
10
|
+
s.authors = ["Thomas Lauro", "Lance Gleason", "Kay Rhodes"]
|
11
|
+
s.date = "2024-06-11"
|
12
|
+
s.description = "This gem allows you to create Apple Passbook files."
|
13
|
+
s.email = ["thomas@lauro.fr", "lgleason@polyglotprogramminginc.com", "masukomi@masukomi.org"]
|
14
|
+
s.extra_rdoc_files = [
|
15
|
+
"LICENSE",
|
16
|
+
"README.md"
|
17
|
+
]
|
18
|
+
s.files = [
|
19
|
+
".travis.yml",
|
20
|
+
"Gemfile",
|
21
|
+
"Gemfile.lock",
|
22
|
+
"LICENSE",
|
23
|
+
"README.md",
|
24
|
+
"Rakefile",
|
25
|
+
"VERSION",
|
26
|
+
"lib/passbook2.rb",
|
27
|
+
"lib/passbook/pk_multi_pass.rb",
|
28
|
+
"lib/passbook/pkpass.rb",
|
29
|
+
"lib/passbook/push_notification.rb",
|
30
|
+
"lib/passbook/signer.rb",
|
31
|
+
"lib/passbook/version.rb",
|
32
|
+
"passbook.gemspec",
|
33
|
+
"spec/data/icon.png",
|
34
|
+
"spec/data/icon@2x.png",
|
35
|
+
"spec/data/logo.png",
|
36
|
+
"spec/data/logo@2x.png",
|
37
|
+
"spec/lib/passbook/pk_multi_pass_spec.rb",
|
38
|
+
"spec/lib/passbook/pkpass_spec.rb",
|
39
|
+
"spec/lib/passbook/push_notification_spec.rb",
|
40
|
+
"spec/lib/passbook/signer_spec.rb",
|
41
|
+
"spec/spec_helper.rb"
|
42
|
+
]
|
43
|
+
s.homepage = "https://github.com/masukomi/passbook2"
|
44
|
+
s.licenses = ["MIT"]
|
45
|
+
s.rubygems_version = "3.4.17"
|
46
|
+
s.summary = "An Apple Passbook file generator."
|
47
|
+
|
48
|
+
s.specification_version = 4
|
49
|
+
|
50
|
+
# runtime dependencies
|
51
|
+
s.add_dependency(%q<grocer>, [">= 0"])
|
52
|
+
s.add_dependency(%q<rubyzip>, [">= 1.0.0"])
|
53
|
+
s.add_dependency(%q<activesupport>.freeze, [">= 0"])
|
54
|
+
|
55
|
+
# development dependencies
|
56
|
+
s.add_development_dependency(%q<debug>, [">= 0"])
|
57
|
+
s.add_development_dependency(%q<rspec>, [">= 0"])
|
58
|
+
s.add_development_dependency(%q<yard>, [">= 0"])
|
59
|
+
end
|
data/spec/data/icon.png
ADDED
Binary file
|
Binary file
|
data/spec/data/logo.png
ADDED
Binary file
|
Binary file
|
@@ -0,0 +1,67 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'tmpdir'
|
3
|
+
require 'zip'
|
4
|
+
|
5
|
+
describe Passbook do
|
6
|
+
let(:content) do
|
7
|
+
{
|
8
|
+
formatVersion: 1,
|
9
|
+
passTypeIdentifier: 'pass.passbook.test',
|
10
|
+
serialNumber: '001',
|
11
|
+
teamIdentifier: ENV['APPLE_TEAM_ID'],
|
12
|
+
organizationName: 'WorldCo',
|
13
|
+
description: 'description',
|
14
|
+
eventTicket: {
|
15
|
+
primaryFields: [
|
16
|
+
{
|
17
|
+
key: 'date',
|
18
|
+
label: 'DATE',
|
19
|
+
value: 'date'
|
20
|
+
}
|
21
|
+
]
|
22
|
+
}
|
23
|
+
}
|
24
|
+
end
|
25
|
+
|
26
|
+
let(:signer) { double 'signer' }
|
27
|
+
let(:pass) { Passbook::PKPass.new( content.to_json, signer) }
|
28
|
+
let(:base_path) { 'spec/data' }
|
29
|
+
let(:entries) { ['pass.json', 'manifest.json', 'signature', 'icon.png', 'icon@2x.png', 'logo.png', 'logo@2x.png'] }
|
30
|
+
let(:passes){ [pass, pass] }
|
31
|
+
|
32
|
+
before :each do
|
33
|
+
pass.add_files(
|
34
|
+
[
|
35
|
+
"#{base_path}/icon.png",
|
36
|
+
"#{base_path}/icon@2x.png",
|
37
|
+
"#{base_path}/logo.png",
|
38
|
+
"#{base_path}/logo@2x.png"
|
39
|
+
]
|
40
|
+
)
|
41
|
+
allow(signer).to(receive(:sign).and_return('Signed by the Honey Badger'))
|
42
|
+
end
|
43
|
+
|
44
|
+
describe ".create_multi_pass" do
|
45
|
+
it "should create a file where specified" do
|
46
|
+
Dir.mktmpdir do |dir|
|
47
|
+
temp_file = Passbook::PKMultiPass.create_multipass(
|
48
|
+
passes,
|
49
|
+
File.join(dir, "foo.pkpasses")
|
50
|
+
)
|
51
|
+
expect(File.exist?(temp_file)).to(eq(true))
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
it "should contain 2 files", :aggregate_failures do
|
56
|
+
Dir.mktmpdir do |dir|
|
57
|
+
temp_file = Passbook::PKMultiPass.create_multipass(
|
58
|
+
passes,
|
59
|
+
File.join(dir, "foo.pkpasses")
|
60
|
+
)
|
61
|
+
entries = Zip::File.open(temp_file).entries
|
62
|
+
expect(entries.count).to(eq(2))
|
63
|
+
expect(entries.map(&:name)).to(match_array(["1.pkpass", "2.pkpass"]))
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
@@ -0,0 +1,169 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'tempfile'
|
3
|
+
require 'tmpdir'
|
4
|
+
|
5
|
+
describe Passbook do
|
6
|
+
let(:content) do
|
7
|
+
{
|
8
|
+
formatVersion: 1,
|
9
|
+
passTypeIdentifier: 'pass.passbook.test',
|
10
|
+
serialNumber: '001',
|
11
|
+
teamIdentifier: ENV['APPLE_TEAM_ID'],
|
12
|
+
relevantDate: '2012-10-02',
|
13
|
+
locations: [ # TODO
|
14
|
+
{
|
15
|
+
longitude: 2.35403,
|
16
|
+
latitude: 48.893855
|
17
|
+
}
|
18
|
+
],
|
19
|
+
organizationName: 'WorldCo',
|
20
|
+
description: 'description',
|
21
|
+
foregroundColor: 'rgb(227,210,18)',
|
22
|
+
backgroundColor: 'rgb(60, 65, 76)',
|
23
|
+
logoText: 'Event',
|
24
|
+
eventTicket: {
|
25
|
+
primaryFields: [
|
26
|
+
{
|
27
|
+
key: 'date',
|
28
|
+
label: 'DATE',
|
29
|
+
value: 'date'
|
30
|
+
}
|
31
|
+
],
|
32
|
+
backFields: [
|
33
|
+
{
|
34
|
+
key: 'description',
|
35
|
+
label: 'DESCRIPTION',
|
36
|
+
value: 'description'
|
37
|
+
},
|
38
|
+
{
|
39
|
+
key: 'aboutUs',
|
40
|
+
label: 'MORE',
|
41
|
+
value: 'about us'
|
42
|
+
}
|
43
|
+
]
|
44
|
+
}
|
45
|
+
}
|
46
|
+
end
|
47
|
+
|
48
|
+
let(:signer) { double 'signer' }
|
49
|
+
let(:pass) { Passbook::PKPass.new content.to_json, signer }
|
50
|
+
let(:base_path) { 'spec/data' }
|
51
|
+
let(:entries) { ['pass.json', 'manifest.json', 'signature', 'icon.png', 'icon@2x.png', 'logo.png', 'logo@2x.png'] }
|
52
|
+
|
53
|
+
before :each do
|
54
|
+
allow(signer).to(receive(:sign).and_return('Signed by the Honey Badger'))
|
55
|
+
end
|
56
|
+
describe '#file' do
|
57
|
+
context 'when adding a file as File' do
|
58
|
+
before do
|
59
|
+
pass.add_file(File.new("#{base_path}/icon.png"))
|
60
|
+
pass.add_files(
|
61
|
+
[
|
62
|
+
"#{base_path}/icon@2x.png",
|
63
|
+
"#{base_path}/logo.png",
|
64
|
+
"#{base_path}/logo@2x.png"
|
65
|
+
].map { |x| File.new(x) }
|
66
|
+
)
|
67
|
+
end
|
68
|
+
|
69
|
+
it 'should work with no options', :aggregate_failures do
|
70
|
+
temp_file = pass.file
|
71
|
+
expect(File.basename(temp_file.path)).to(eq('pass.pkpass'))
|
72
|
+
expect(File.dirname(temp_file)).to(eq(Dir.tmpdir))
|
73
|
+
end
|
74
|
+
end
|
75
|
+
context 'when adding files as strings' do
|
76
|
+
before do
|
77
|
+
pass.add_file("#{base_path}/icon.png")
|
78
|
+
pass.add_files(
|
79
|
+
[
|
80
|
+
"#{base_path}/icon@2x.png",
|
81
|
+
"#{base_path}/logo.png",
|
82
|
+
"#{base_path}/logo@2x.png"
|
83
|
+
]
|
84
|
+
)
|
85
|
+
end
|
86
|
+
|
87
|
+
it 'should work with no options', :aggregate_failures do
|
88
|
+
temp_file = pass.file
|
89
|
+
expect(File.basename(temp_file.path)).to(eq('pass.pkpass'))
|
90
|
+
expect(File.dirname(temp_file)).to(eq(Dir.tmpdir))
|
91
|
+
end
|
92
|
+
it 'should honor the file_name specified' do
|
93
|
+
temp_file = pass.file(file_name: 'foo.pkpass')
|
94
|
+
expect(File.basename(temp_file)).to(eq('foo.pkpass'))
|
95
|
+
end
|
96
|
+
|
97
|
+
it 'should honor the directory specified as a string' do
|
98
|
+
Dir.mktmpdir do |dir| # dir is a String
|
99
|
+
temp_file = pass.file(directory: dir)
|
100
|
+
expect(File.dirname(temp_file)).to(eq(dir))
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
it 'should honor the directory specified as a Dir' do
|
105
|
+
Dir.mktmpdir do |dir|
|
106
|
+
temp_file = pass.file(directory: Dir.new(dir))
|
107
|
+
expect(File.dirname(temp_file)).to(eq(dir))
|
108
|
+
end
|
109
|
+
end
|
110
|
+
context 'outputs' do
|
111
|
+
before do
|
112
|
+
@file_entries = []
|
113
|
+
Zip::InputStream.open(zip_path) do |io|
|
114
|
+
while (entry = io.get_next_entry)
|
115
|
+
@file_entries << entry.name
|
116
|
+
end
|
117
|
+
end
|
118
|
+
end
|
119
|
+
|
120
|
+
context 'zip file' do
|
121
|
+
let(:zip_path) { pass.file.path }
|
122
|
+
|
123
|
+
it 'should have the expected files' do
|
124
|
+
expect(entries).to(eq(@file_entries))
|
125
|
+
end
|
126
|
+
end
|
127
|
+
|
128
|
+
context 'StringIO' do
|
129
|
+
let(:temp_file) { Tempfile.new('pass.pkpass') }
|
130
|
+
let(:zip_path) do
|
131
|
+
zip_out = pass.stream
|
132
|
+
expect(zip_out.class).to(eq(StringIO))
|
133
|
+
# creating file, re-reading zip to see if correctly formed
|
134
|
+
temp_file.write zip_out.string
|
135
|
+
temp_file.close
|
136
|
+
temp_file.path
|
137
|
+
end
|
138
|
+
|
139
|
+
it 'should contain the expected files' do
|
140
|
+
expect(entries).to(eq(@file_entries))
|
141
|
+
end
|
142
|
+
|
143
|
+
after do
|
144
|
+
temp_file.delete
|
145
|
+
end
|
146
|
+
end
|
147
|
+
end
|
148
|
+
end
|
149
|
+
end
|
150
|
+
|
151
|
+
# TODO: find a proper way to do this
|
152
|
+
context 'Error catcher' do
|
153
|
+
context 'formatVersion' do
|
154
|
+
let(:base_path) { 'spec/data' }
|
155
|
+
|
156
|
+
before :each do
|
157
|
+
pass.add_files ["#{base_path}/icon.png", "#{base_path}/icon@2x.png", "#{base_path}/logo.png",
|
158
|
+
"#{base_path}/logo@2x.png"]
|
159
|
+
tpass = JSON.parse(pass.pass)
|
160
|
+
tpass['formatVersion'] = 'It should be a numeric'
|
161
|
+
pass.pass = tpass.to_json
|
162
|
+
end
|
163
|
+
|
164
|
+
it 'raise an error' do
|
165
|
+
expect { pass.build }.to raise_error('Format Version should be a numeric')
|
166
|
+
end
|
167
|
+
end
|
168
|
+
end
|
169
|
+
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
|
+
allow(Passbook).to(receive(:notification_cert).and_return('./notification_cert.pem'))
|
13
|
+
allow(Grocer::PassbookNotification).to(receive(:new).with(:device_token => 'my token').and_return(notification))
|
14
|
+
allow(grocer_pusher).to(receive(:push).with(notification).and_return(55))
|
15
|
+
allow(Grocer).to(receive(:pusher).with(notification_settings).and_return(grocer_pusher))
|
16
|
+
allow(Passbook).to(receive(:notification_gateway).and_return('honeybadger.apple.com'))
|
17
|
+
allow(Passbook).to(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,100 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe 'Signer' do
|
4
|
+
context 'signatures' do
|
5
|
+
|
6
|
+
context 'using default config info' do
|
7
|
+
before do
|
8
|
+
expect(Passbook).to(receive(:password).and_return 'password')
|
9
|
+
expect(Passbook).to(receive(:rsa_private_key).and_return 'my_rsa_key')
|
10
|
+
expect(Passbook).to(receive(:certificate).and_return 'my_X509_certificate')
|
11
|
+
expect(Passbook).to(
|
12
|
+
receive(:apple_intermediate_cert)
|
13
|
+
.and_return( 'apple_intermediate_cert_file')
|
14
|
+
)
|
15
|
+
end
|
16
|
+
|
17
|
+
context "getting the default config" do
|
18
|
+
context "ignoring signing" do
|
19
|
+
before do
|
20
|
+
# don't care if signing works yet. just dealing with defaults
|
21
|
+
allow_any_instance_of(Passbook::Signer).to(receive(:compute_cert))
|
22
|
+
end
|
23
|
+
|
24
|
+
let(:signer){
|
25
|
+
Passbook::Signer.new
|
26
|
+
}
|
27
|
+
it "should contain rsa_private_key" do
|
28
|
+
expect(signer.rsa_private_key).to(eq('my_rsa_key'))
|
29
|
+
end
|
30
|
+
it "should contain certificate" do
|
31
|
+
expect(signer.certificate).to(eq('my_X509_certificate'))
|
32
|
+
end
|
33
|
+
it "should contain apple_intermediate_cert" do
|
34
|
+
expect(signer.apple_intermediate_cert).to(eq('apple_intermediate_cert_file'))
|
35
|
+
end
|
36
|
+
it "should contain password" do
|
37
|
+
expect(signer.password).to(eq('password'))
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
context "computing cert" do
|
42
|
+
before do
|
43
|
+
expect(OpenSSL::PKey::RSA).to(
|
44
|
+
receive(:new)
|
45
|
+
.with('my_rsa_key', 'password')
|
46
|
+
.and_return 'my_rsa_key' # bogus example
|
47
|
+
)
|
48
|
+
|
49
|
+
expect(OpenSSL::X509::Certificate).to(
|
50
|
+
receive(:new)
|
51
|
+
.with('my_X509_certificate')
|
52
|
+
.and_return 'my_X509_data' # bogus example
|
53
|
+
)
|
54
|
+
end
|
55
|
+
context "signing" do
|
56
|
+
let(:signer){Passbook::Signer.new}
|
57
|
+
|
58
|
+
# this is just checking that
|
59
|
+
# the inputs and outputs of the cert things
|
60
|
+
# are all wired together correctly
|
61
|
+
it "should do the signing dance" do
|
62
|
+
|
63
|
+
# 2nd X509 cert loading...
|
64
|
+
expect(OpenSSL::X509::Certificate).to(
|
65
|
+
receive(:new)
|
66
|
+
.with('apple_intermediate_cert_file')
|
67
|
+
.and_return 'apples_X509_data' # bogus example
|
68
|
+
)
|
69
|
+
|
70
|
+
expect(OpenSSL::PKCS7).to(
|
71
|
+
receive(:sign)
|
72
|
+
.with(
|
73
|
+
'my_X509_data', # from above
|
74
|
+
'my_rsa_key', # also from above
|
75
|
+
'passbook_sign_data', # the param to Signer#sign(...)
|
76
|
+
['apples_X509_data'],
|
77
|
+
OpenSSL::PKCS7::BINARY | OpenSSL::PKCS7::DETACHED
|
78
|
+
)
|
79
|
+
.and_return('pk7') # bogus example
|
80
|
+
)
|
81
|
+
expect(OpenSSL::PKCS7).to(
|
82
|
+
receive(:write_smime)
|
83
|
+
.with('pk7')
|
84
|
+
.and_return("filename=\"smime.p7s\"\n\nsecret_pk7_stuff\n\n------")
|
85
|
+
)
|
86
|
+
expect(Base64).to(
|
87
|
+
receive(:decode64)
|
88
|
+
.with('secret_pk7_stuff') #from above
|
89
|
+
)
|
90
|
+
|
91
|
+
# and... kick it all off
|
92
|
+
signer.sign('passbook_sign_data')
|
93
|
+
|
94
|
+
end
|
95
|
+
end
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
end
|
100
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,8 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'bundler'
|
3
|
+
require 'json'
|
4
|
+
require 'grocer'
|
5
|
+
require 'debug'
|
6
|
+
|
7
|
+
Dir['lib/passbook/**/*.rb'].each {|f| require File.join(File.dirname(__FILE__), '..', f.gsub(/.rb/, ''))}
|
8
|
+
Dir['lib/rack/**/*.rb'].each {|f| require File.join(File.dirname(__FILE__), '..', f.gsub(/.rb/, ''))}
|
metadata
ADDED
@@ -0,0 +1,156 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: passbook2
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 1.0.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Thomas Lauro
|
8
|
+
- Lance Gleason
|
9
|
+
- Kay Rhodes
|
10
|
+
autorequire:
|
11
|
+
bindir: bin
|
12
|
+
cert_chain: []
|
13
|
+
date: 2024-06-11 00:00:00.000000000 Z
|
14
|
+
dependencies:
|
15
|
+
- !ruby/object:Gem::Dependency
|
16
|
+
name: grocer
|
17
|
+
requirement: !ruby/object:Gem::Requirement
|
18
|
+
requirements:
|
19
|
+
- - ">="
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: '0'
|
22
|
+
type: :runtime
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: !ruby/object:Gem::Requirement
|
25
|
+
requirements:
|
26
|
+
- - ">="
|
27
|
+
- !ruby/object:Gem::Version
|
28
|
+
version: '0'
|
29
|
+
- !ruby/object:Gem::Dependency
|
30
|
+
name: rubyzip
|
31
|
+
requirement: !ruby/object:Gem::Requirement
|
32
|
+
requirements:
|
33
|
+
- - ">="
|
34
|
+
- !ruby/object:Gem::Version
|
35
|
+
version: 1.0.0
|
36
|
+
type: :runtime
|
37
|
+
prerelease: false
|
38
|
+
version_requirements: !ruby/object:Gem::Requirement
|
39
|
+
requirements:
|
40
|
+
- - ">="
|
41
|
+
- !ruby/object:Gem::Version
|
42
|
+
version: 1.0.0
|
43
|
+
- !ruby/object:Gem::Dependency
|
44
|
+
name: activesupport
|
45
|
+
requirement: !ruby/object:Gem::Requirement
|
46
|
+
requirements:
|
47
|
+
- - ">="
|
48
|
+
- !ruby/object:Gem::Version
|
49
|
+
version: '0'
|
50
|
+
type: :runtime
|
51
|
+
prerelease: false
|
52
|
+
version_requirements: !ruby/object:Gem::Requirement
|
53
|
+
requirements:
|
54
|
+
- - ">="
|
55
|
+
- !ruby/object:Gem::Version
|
56
|
+
version: '0'
|
57
|
+
- !ruby/object:Gem::Dependency
|
58
|
+
name: debug
|
59
|
+
requirement: !ruby/object:Gem::Requirement
|
60
|
+
requirements:
|
61
|
+
- - ">="
|
62
|
+
- !ruby/object:Gem::Version
|
63
|
+
version: '0'
|
64
|
+
type: :development
|
65
|
+
prerelease: false
|
66
|
+
version_requirements: !ruby/object:Gem::Requirement
|
67
|
+
requirements:
|
68
|
+
- - ">="
|
69
|
+
- !ruby/object:Gem::Version
|
70
|
+
version: '0'
|
71
|
+
- !ruby/object:Gem::Dependency
|
72
|
+
name: rspec
|
73
|
+
requirement: !ruby/object:Gem::Requirement
|
74
|
+
requirements:
|
75
|
+
- - ">="
|
76
|
+
- !ruby/object:Gem::Version
|
77
|
+
version: '0'
|
78
|
+
type: :development
|
79
|
+
prerelease: false
|
80
|
+
version_requirements: !ruby/object:Gem::Requirement
|
81
|
+
requirements:
|
82
|
+
- - ">="
|
83
|
+
- !ruby/object:Gem::Version
|
84
|
+
version: '0'
|
85
|
+
- !ruby/object:Gem::Dependency
|
86
|
+
name: yard
|
87
|
+
requirement: !ruby/object:Gem::Requirement
|
88
|
+
requirements:
|
89
|
+
- - ">="
|
90
|
+
- !ruby/object:Gem::Version
|
91
|
+
version: '0'
|
92
|
+
type: :development
|
93
|
+
prerelease: false
|
94
|
+
version_requirements: !ruby/object:Gem::Requirement
|
95
|
+
requirements:
|
96
|
+
- - ">="
|
97
|
+
- !ruby/object:Gem::Version
|
98
|
+
version: '0'
|
99
|
+
description: This gem allows you to create Apple Passbook files.
|
100
|
+
email:
|
101
|
+
- thomas@lauro.fr
|
102
|
+
- lgleason@polyglotprogramminginc.com
|
103
|
+
- masukomi@masukomi.org
|
104
|
+
executables: []
|
105
|
+
extensions: []
|
106
|
+
extra_rdoc_files:
|
107
|
+
- LICENSE
|
108
|
+
- README.md
|
109
|
+
files:
|
110
|
+
- ".travis.yml"
|
111
|
+
- Gemfile
|
112
|
+
- Gemfile.lock
|
113
|
+
- LICENSE
|
114
|
+
- README.md
|
115
|
+
- Rakefile
|
116
|
+
- VERSION
|
117
|
+
- lib/passbook/pk_multi_pass.rb
|
118
|
+
- lib/passbook/pkpass.rb
|
119
|
+
- lib/passbook/push_notification.rb
|
120
|
+
- lib/passbook/signer.rb
|
121
|
+
- lib/passbook/version.rb
|
122
|
+
- lib/passbook2.rb
|
123
|
+
- passbook.gemspec
|
124
|
+
- spec/data/icon.png
|
125
|
+
- spec/data/icon@2x.png
|
126
|
+
- spec/data/logo.png
|
127
|
+
- spec/data/logo@2x.png
|
128
|
+
- spec/lib/passbook/pk_multi_pass_spec.rb
|
129
|
+
- spec/lib/passbook/pkpass_spec.rb
|
130
|
+
- spec/lib/passbook/push_notification_spec.rb
|
131
|
+
- spec/lib/passbook/signer_spec.rb
|
132
|
+
- spec/spec_helper.rb
|
133
|
+
homepage: https://github.com/masukomi/passbook2
|
134
|
+
licenses:
|
135
|
+
- MIT
|
136
|
+
metadata: {}
|
137
|
+
post_install_message:
|
138
|
+
rdoc_options: []
|
139
|
+
require_paths:
|
140
|
+
- lib
|
141
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
142
|
+
requirements:
|
143
|
+
- - ">="
|
144
|
+
- !ruby/object:Gem::Version
|
145
|
+
version: '0'
|
146
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
147
|
+
requirements:
|
148
|
+
- - ">="
|
149
|
+
- !ruby/object:Gem::Version
|
150
|
+
version: '0'
|
151
|
+
requirements: []
|
152
|
+
rubygems_version: 3.4.20
|
153
|
+
signing_key:
|
154
|
+
specification_version: 4
|
155
|
+
summary: An Apple Passbook file generator.
|
156
|
+
test_files: []
|