push_package 0.0.1 → 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,15 +1,15 @@
1
1
  ---
2
2
  !binary "U0hBMQ==":
3
3
  metadata.gz: !binary |-
4
- MTdmMDFlZmVlNWE5MDFkYzgzNGVhMjM4ZDAxMTc4YTY4N2VlMDVlNA==
4
+ YzMyYmUwZDI3OTNhMjQ5ZmMzYTljZDk0M2Y1YmU0NTUwM2M3MTA2OA==
5
5
  data.tar.gz: !binary |-
6
- OTEwZTQ0NjBkOGZlNTBmYmY5M2QyZmQ3ZTU2NTE0NGFhN2FiYzU2OQ==
6
+ YmQwOGVjMjRiMTUwZTYzMGM0MGEzM2I1MzcxODczMGRkNGQ0ZGU4Zg==
7
7
  SHA512:
8
8
  metadata.gz: !binary |-
9
- ZjcwNTc2YzVlZDc0MTY3NGMwZTFkNDU5OTE3NGYzN2UyMzljMzc0YTE5OTVm
10
- NTk5OGFhZDA1OWZhYjQ1MmJiMmI3NGU0Nzc4MjNlMjM5MTM0MWMwYTRjNGQz
11
- NzQzYzcxNjE5MmFiZDRiYzZjODg1MGU1Y2RmYWU1ZDA4MzQ4NTE=
9
+ MWQzY2NkYzBhZjhjMGI3MzJkMjg4YTZkYzUwYTNiMmE4NzQ5MmJiZDE4NDJi
10
+ MTdkZGQyY2I0ZDUzZjdmMzc0MjJmYzI4MTk4YjBkMjY0NjU4M2RkZmUyNzJi
11
+ NzJhNTJkOGVkN2JkODkzYWMyNDQxMDgyYmEwMGE0ZjUyZmZjMTg=
12
12
  data.tar.gz: !binary |-
13
- MjQ0NTM4NzBkNjg1Y2U4NmY3MWY2MDU2MjcwNTM3ZmE2NWY1ZmNhNzM3YjYw
14
- Njk4NjUwZTQ1ZWRhOTllMGRhZDU2ZDE2MzkyMTM4Mzc0YzMyOGRjOTIyYzY0
15
- ZWJlZGEyMzk2ZDlhNjAzMmQzNGNhNGEwMjFlZGYwNmY3YjA1Mjk=
13
+ ZmZjYjNkYWFmOWQxMmY0ZmJmMDIyNDExZDU0MmExMDliZjEzMjM4MWQzOGZl
14
+ Y2Y1N2I1MDRiNDIzNjIwYmYwMDFmMDdlOWU3MDJhYTdiMmFmMjMxZTUyMDFk
15
+ NWRkMDk2ZGE0NTVjZjYyZGI4NWNmYjAxMjdkZWVmNzk1YTRjMTY=
data/Gemfile.lock CHANGED
@@ -1,18 +1,26 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- push_package (0.0.1)
4
+ push_package (0.0.2)
5
5
 
6
6
  GEM
7
7
  remote: https://rubygems.org/
8
8
  specs:
9
+ coderay (1.0.9)
10
+ method_source (0.8.2)
9
11
  minitest (4.7.0)
12
+ pry (0.9.12.2)
13
+ coderay (~> 1.0.5)
14
+ method_source (~> 0.8)
15
+ slop (~> 3.4)
10
16
  rake (10.0.3)
17
+ slop (3.4.6)
11
18
 
12
19
  PLATFORMS
13
20
  ruby
14
21
 
15
22
  DEPENDENCIES
16
23
  minitest (~> 4.7.0)
24
+ pry
17
25
  push_package!
18
26
  rake (~> 10.0.3)
data/README.md CHANGED
@@ -2,7 +2,19 @@
2
2
  Make implementing safari push notifications easier for ruby developers.
3
3
 
4
4
  ## Notes:
5
- This is not ready for use.
5
+
6
+ ```ruby
7
+ def create
8
+ package = PushPackage.new(website_params, iconset_path, certificate)
9
+ package.save('path/to/save')
10
+ send_file 'path/to/save'
11
+ end
12
+ ```
13
+
14
+ ```shell
15
+ $> push_package --website-json=./website.json --iconset-path=~/project/iconset --output-dir=./ --certificate=./Certificate.p12
16
+ wrote: ./pushPackage.zip
17
+ ```
6
18
 
7
19
  ## Contributing
8
20
 
data/lib/push_package.rb CHANGED
@@ -1,4 +1,78 @@
1
1
  require 'push_package/version'
2
+ require 'json'
3
+ require 'fileutils'
4
+ require 'tmpdir'
5
+ require 'openssl'
2
6
 
3
- module PushPackage
7
+ class PushPackage
8
+ class InvalidIconsetError < StandardError; end
9
+ class InvalidParameterError < StandardError; end
10
+
11
+ REQUIRED_WEBSITE_PARAMS = ["websiteName", "websitePushID", "allowedDomains", "urlFormatString", "authenticationToken", "webServiceURL"]
12
+ REQUIRED_ICONSET_FILES = ["icon_16x16.png", "icon_16x16@2x.png", "icon_32x32.png", "icon_32x32@2x.png", "icon_128x128.png", "icon_128x128@2x.png" ]
13
+
14
+ attr_reader :p12
15
+
16
+ def initialize(website_params, iconset_path, certificate, password = nil)
17
+ raise InvalidParameterError unless valid_website_params?(website_params)
18
+ raise InvalidIconsetError unless valid_iconset?(iconset_path)
19
+ raise ArgumentError unless certificate
20
+
21
+ @website_params = website_params
22
+ @iconset_path = iconset_path
23
+
24
+ if certificate.respond_to?(:read)
25
+ cert_data = certificate.read
26
+ certificate.rewind if certificate.respond_to?(:rewind)
27
+ else
28
+ cert_data = File.read(certificate)
29
+ end
30
+ @p12 = OpenSSL::PKCS12.new(cert_data, password)
31
+ end
32
+
33
+ def save(output_path)
34
+ Dir.mktmpdir('pushPackage') do |dir|
35
+ json = File.open(dir + '/website.json', 'w+')
36
+ json.write(JSON.dump(@website_params))
37
+ json.close
38
+
39
+ Dir.mkdir(File.join(dir,'icon.iconset'))
40
+ Dir.glob(@iconset_path + '/*.png').each do |icon|
41
+ FileUtils.cp(icon, dir + '/icon.iconset/')
42
+ end
43
+
44
+ manifest_keys = REQUIRED_ICONSET_FILES.map{|f| 'icon.iconset/' + f }
45
+ manifest_keys << 'website.json'
46
+ manifest_values = manifest_keys.map {|file| Digest::SHA1.file(File.join(dir, file)).hexdigest }
47
+ manifest_data = Hash[manifest_keys.zip(manifest_values)].to_json
48
+ File.open(dir + '/manifest.json', 'w+') do |manifest|
49
+ manifest.write(manifest_data)
50
+ end
51
+
52
+ #use the certificate to create a pkcs7 detached signature
53
+ signature = OpenSSL::PKCS7::sign(@p12.certificate, @p12.key, manifest_data, [], OpenSSL::PKCS7::BINARY | OpenSSL::PKCS7::DETACHED)
54
+
55
+ File.open(dir + '/signature', 'wb+') do |file|
56
+ file << signature.to_der
57
+ end
58
+
59
+ `pushd #{dir}; zip -r #{output_path} ./; popd`
60
+ end
61
+
62
+ File.open(output_path, 'r')
63
+ end
64
+
65
+ private
66
+
67
+ def valid_website_params?(params)
68
+ REQUIRED_WEBSITE_PARAMS.all? do |param|
69
+ params.keys.include?(param)
70
+ end
71
+ end
72
+
73
+ def valid_iconset?(iconset_path)
74
+ REQUIRED_ICONSET_FILES.all? do |file|
75
+ File.exist?(File.join(iconset_path, file))
76
+ end
77
+ end
4
78
  end
@@ -1,3 +1,3 @@
1
- module PushPackage
2
- VERSION = '0.0.1'.freeze
1
+ class PushPackage
2
+ VERSION = '0.0.2'.freeze
3
3
  end
data/push_package.gemspec CHANGED
@@ -21,4 +21,5 @@ Gem::Specification.new do |gem|
21
21
 
22
22
  gem.add_development_dependency 'minitest', '~> 4.7.0'
23
23
  gem.add_development_dependency 'rake', '~> 10.0.3'
24
+ gem.add_development_dependency 'pry'
24
25
  end
@@ -0,0 +1 @@
1
+ {"icon.iconset/icon_128x128.png":"28969578f1788252807a7d8205db269cb7699fa8","icon.iconset/icon_128x128@2x.png":"dd2bf0e3cb998467b0e5f5ae11675a454ad77601","icon.iconset/icon_16x16.png":"48e791d0c88b92fae51ffa8363821857210fca01","icon.iconset/icon_16x16@2x.png":"5a74d295cc09ca5896a4ceb7cac0d030cc85e894","icon.iconset/icon_32x32.png":"8c71bc22f4cfe12ad98aabe94da6a70fe9f15741","icon.iconset/icon_32x32@2x.png":"750e080d38efe1c227b2498f73f006007f3da24b","website.json":"3eaed6475443b895a49e3a1220e547f2be90434a"}
Binary file
Binary file
@@ -1,10 +1,131 @@
1
1
  require 'spec_helper'
2
+ require 'fileutils'
2
3
 
3
4
  describe PushPackage do
4
5
 
6
+ let(:iconset_path) { fixture_path 'iconset' }
7
+
8
+ let(:website_params) do
9
+ {
10
+ 'websiteName' => 'Push Package Test',
11
+ 'websitePushID' => 'web.com.symmetricinfinity.push_package',
12
+ 'allowedDomains' => ['http://symmetricinfinity.com/push_package/', 'http://lvh.me'],
13
+ 'urlFormatString' => 'http://symmetricinfinity.com/push_package/?%@=%@',
14
+ 'authenticationToken' => 'nr2o1spn515949r5q54so22o8rq95575',
15
+ 'webServiceURL' => 'https://api.zeropush.com/safari'
16
+ }
17
+ end
18
+
19
+ let(:expected_manifest) do
20
+ {
21
+ 'icon.iconset/icon_128x128.png' => '28969578f1788252807a7d8205db269cb7699fa8',
22
+ 'icon.iconset/icon_128x128@2x.png' => 'dd2bf0e3cb998467b0e5f5ae11675a454ad77601',
23
+ 'icon.iconset/icon_16x16.png' => '48e791d0c88b92fae51ffa8363821857210fca01',
24
+ 'icon.iconset/icon_16x16@2x.png' => '5a74d295cc09ca5896a4ceb7cac0d030cc85e894',
25
+ 'icon.iconset/icon_32x32.png' => '8c71bc22f4cfe12ad98aabe94da6a70fe9f15741',
26
+ 'icon.iconset/icon_32x32@2x.png' => '750e080d38efe1c227b2498f73f006007f3da24b',
27
+ 'website.json' => '3eaed6475443b895a49e3a1220e547f2be90434a'
28
+ }
29
+ end
30
+
31
+ let(:certificate) { File.open(fixture_path('self-signed.p12')) }
32
+
5
33
  describe 'the truth' do
6
34
  it 'should pass' do
7
35
  'test'.must_equal('test')
8
36
  end
9
37
  end
38
+
39
+ describe '.new' do
40
+ it 'should check website_params' do
41
+ lambda do
42
+ PushPackage.new({}, iconset_path, certificate)
43
+ end.must_raise(PushPackage::InvalidParameterError)
44
+ end
45
+
46
+ it 'must have a valid iconset' do
47
+ lambda do
48
+ PushPackage.new(website_params, '/tmp', certificate)
49
+ end.must_raise(PushPackage::InvalidIconsetError)
50
+ end
51
+
52
+ it 'should support a certificate path' do
53
+ lambda do
54
+ PushPackage.new(website_params, iconset_path, nil)
55
+ end.must_raise(ArgumentError)
56
+ end
57
+
58
+ it 'should support certificate path' do
59
+ lambda do
60
+ PushPackage.new(website_params, iconset_path, '/some/file.p12')
61
+ end.must_raise(Errno::ENOENT)
62
+ end
63
+ end
64
+
65
+ describe '#save' do
66
+ let(:output_path) { '/tmp/pushPackage.zip' }
67
+ let(:tmp_path) { '/tmp/pushPackage' }
68
+ let(:extracted_package) do
69
+ `unzip #{output_path} -d #{tmp_path}`
70
+ Dir.glob(tmp_path + '/**/*').map do |d|
71
+ d.gsub(tmp_path + '/', '')
72
+ end
73
+ end
74
+
75
+ let(:push_package) { PushPackage.new(website_params, iconset_path, certificate) }
76
+
77
+ before do
78
+ push_package.save(output_path)
79
+ end
80
+
81
+ after do
82
+ File.delete(output_path) if File.exist?(output_path)
83
+ FileUtils.rm_rf(tmp_path)
84
+ end
85
+
86
+ it 'should save to the file system' do
87
+ File.exist?(output_path).must_equal(true)
88
+ end
89
+
90
+ it 'should return the file handle' do
91
+ file = push_package.save(output_path)
92
+ file.must_be_instance_of File
93
+ File.exists?(file.path).must_equal true
94
+ end
95
+
96
+ it 'should be a zip file' do
97
+ extracted_package.wont_be_empty
98
+ $?.success?.must_equal true
99
+ end
100
+
101
+ it 'should have a valid manifest.json file' do
102
+ extracted_package.must_include('manifest.json')
103
+ manifest = JSON.load(File.open(tmp_path + '/manifest.json', 'r'))
104
+ manifest.sort.must_equal(expected_manifest.sort)
105
+ end
106
+
107
+ it 'should have the iconset in icon.iconset subdirectory' do
108
+ icons = extracted_package.select {|file| file.start_with?('icon.iconset/') }
109
+ icons = icons.map {|i| i.gsub('icon.iconset/', '') }
110
+ icons.sort.must_equal(PushPackage::REQUIRED_ICONSET_FILES.sort)
111
+ end
112
+
113
+ it 'should have a website.json file' do
114
+ extracted_package.must_include('website.json')
115
+ end
116
+
117
+ it 'should have a valid signature' do
118
+ extracted_package.must_include('signature')
119
+ signature = File.read(tmp_path + '/signature')
120
+ p7 = OpenSSL::PKCS7.new(signature)
121
+ store = OpenSSL::X509::Store.new
122
+ store.add_cert(push_package.p12.certificate)
123
+ p7.verify(
124
+ [push_package.p12.certificate],
125
+ store,
126
+ File.read(tmp_path + '/manifest.json'),
127
+ OpenSSL::PKCS7::DETACHED
128
+ ).must_equal true
129
+ end
130
+ end
10
131
  end
data/spec/spec_helper.rb CHANGED
@@ -2,3 +2,6 @@ require 'minitest/spec'
2
2
  require 'minitest/autorun'
3
3
  require 'push_package'
4
4
 
5
+ def fixture_path(*paths)
6
+ File.join(File.dirname(__FILE__), 'fixtures', *paths)
7
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: push_package
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.1
4
+ version: 0.0.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Stefan Natchev
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2013-10-29 00:00:00.000000000 Z
12
+ date: 2013-11-13 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: minitest
@@ -39,6 +39,20 @@ dependencies:
39
39
  - - ~>
40
40
  - !ruby/object:Gem::Version
41
41
  version: 10.0.3
42
+ - !ruby/object:Gem::Dependency
43
+ name: pry
44
+ requirement: !ruby/object:Gem::Requirement
45
+ requirements:
46
+ - - ! '>='
47
+ - !ruby/object:Gem::Version
48
+ version: '0'
49
+ type: :development
50
+ prerelease: false
51
+ version_requirements: !ruby/object:Gem::Requirement
52
+ requirements:
53
+ - - ! '>='
54
+ - !ruby/object:Gem::Version
55
+ version: '0'
42
56
  description: As of OSX 10.9 Safari can receive push notifications when it is closed.
43
57
  email:
44
58
  - stefan.natchev@gmail.com
@@ -56,6 +70,15 @@ files:
56
70
  - lib/push_package.rb
57
71
  - lib/push_package/version.rb
58
72
  - push_package.gemspec
73
+ - spec/fixtures/iconset/icon_128x128.png
74
+ - spec/fixtures/iconset/icon_128x128@2x.png
75
+ - spec/fixtures/iconset/icon_16x16.png
76
+ - spec/fixtures/iconset/icon_16x16@2x.png
77
+ - spec/fixtures/iconset/icon_32x32.png
78
+ - spec/fixtures/iconset/icon_32x32@2x.png
79
+ - spec/fixtures/manifest.json
80
+ - spec/fixtures/self-signed.p12
81
+ - spec/fixtures/signature
59
82
  - spec/push_package_spec.rb
60
83
  - spec/spec_helper.rb
61
84
  homepage: https://github.com/symmetricinfinity/push_package
@@ -83,5 +106,14 @@ signing_key:
83
106
  specification_version: 4
84
107
  summary: A gem for creating Safari push notification push packages.
85
108
  test_files:
109
+ - spec/fixtures/iconset/icon_128x128.png
110
+ - spec/fixtures/iconset/icon_128x128@2x.png
111
+ - spec/fixtures/iconset/icon_16x16.png
112
+ - spec/fixtures/iconset/icon_16x16@2x.png
113
+ - spec/fixtures/iconset/icon_32x32.png
114
+ - spec/fixtures/iconset/icon_32x32@2x.png
115
+ - spec/fixtures/manifest.json
116
+ - spec/fixtures/self-signed.p12
117
+ - spec/fixtures/signature
86
118
  - spec/push_package_spec.rb
87
119
  - spec/spec_helper.rb