passbook2 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- 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: []
|