webpush 0.1.5 → 0.1.6

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 380725977abfa7cbf7b62f4a4ac5b34c1ba1877d
4
- data.tar.gz: 2c82b655b035f6b25c75346010d630564339269b
3
+ metadata.gz: b5006a4c889349920fc642e5e126f9a2bb986fa8
4
+ data.tar.gz: cc39101673ba4b9c52aa4482e1dbb554ccb51342
5
5
  SHA512:
6
- metadata.gz: b7c99af20b1caf248fe7def5e81e8f8eb9897b077f7f36157127a78e69611ad5a6e145214e6334fff7b7eb6d941b9157544e8c8ef40fa1534b014f2402396a21
7
- data.tar.gz: e04325bf879edc79cd740cde288495071f011c7a3b25d765b634ab58989f83298a4793b9934b7a6e8724bcc76a2832b5621b74dd372ed6c8d40f10ceb9a82e38
6
+ metadata.gz: 81560e7eabb65bac0fb4ce2972279654bdbcbca4719d815a40cd63994b20f59ba2430ad6835e6d5a0655df6897552344588948622399a405e9b4964bc2740b14
7
+ data.tar.gz: 4785dc7d17f520a0df9891dd1ada08b57e59b19e972a9308190c3025ba7491f27052b0163c5f4dfd4fb7361066539bc98b325ef47e5e81bfa0bce0bca2309cc0
data/README.md CHANGED
@@ -22,7 +22,7 @@ Or install it yourself as:
22
22
 
23
23
  ## Usage
24
24
 
25
- ```
25
+ ```ruby
26
26
  message = {
27
27
  title: "title",
28
28
  body: "body",
@@ -30,12 +30,12 @@ message = {
30
30
  }
31
31
 
32
32
  Webpush.payload_send(
33
- message: JSON.generate(message),
34
- endpoint: "https://android.googleapis.com/gcm/send/eah7hak....",
35
- p256dh: "BO/aG9nYXNkZmFkc2ZmZHNmYWRzZmFl...",
36
- auth: "aW1hcmthcmFpa3V6ZQ==",
37
- api_key: "[GoogleDeveloper APIKEY]" # optional, not used in Firefox.
38
- )
33
+ message: JSON.generate(message),
34
+ endpoint: "https://android.googleapis.com/gcm/send/eah7hak....",
35
+ p256dh: "BO/aG9nYXNkZmFkc2ZmZHNmYWRzZmFl...",
36
+ auth: "aW1hcmthcmFpa3V6ZQ==",
37
+ api_key: "[GoogleDeveloper APIKEY]" # optional, not used in Firefox.
38
+ )
39
39
  ```
40
40
 
41
41
  ### ServiceWorker sample
@@ -44,7 +44,7 @@ see. https://github.com/zaru/web-push-sample
44
44
 
45
45
  p256dh and auth generate sample code.
46
46
 
47
- ```
47
+ ```javascript
48
48
  navigator.serviceWorker.ready.then(function(sw) {
49
49
  Notification.requestPermission(function(permission) {
50
50
  if(permission !== 'denied') {
@@ -63,7 +63,7 @@ navigator.serviceWorker.ready.then(function(sw) {
63
63
 
64
64
  payloads received sample code.
65
65
 
66
- ```
66
+ ```javascript
67
67
  self.addEventListener("push", function(event) {
68
68
  var json = event.data.json();
69
69
  self.registration.showNotification(json.title, {
data/bin/rake ADDED
@@ -0,0 +1,16 @@
1
+ #!/usr/bin/env ruby
2
+ #
3
+ # This file was generated by Bundler.
4
+ #
5
+ # The application 'rake' is installed as part of a gem, and
6
+ # this file is here to facilitate running it.
7
+ #
8
+
9
+ require "pathname"
10
+ ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../../Gemfile",
11
+ Pathname.new(__FILE__).realpath)
12
+
13
+ require "rubygems"
14
+ require "bundler/setup"
15
+
16
+ load Gem.bin_path("rake", "rake")
data/lib/webpush.rb CHANGED
@@ -1,10 +1,12 @@
1
- require 'webpush/version'
2
1
  require 'openssl'
3
2
  require 'base64'
4
3
  require 'hkdf'
5
4
  require 'net/http'
6
5
  require 'json'
7
6
 
7
+ require 'webpush/version'
8
+ require 'webpush/encryption'
9
+
8
10
  module Webpush
9
11
 
10
12
  # It is temporary URL until supported by the GCM server.
@@ -14,10 +16,8 @@ module Webpush
14
16
  class << self
15
17
  def payload_send(message:, endpoint:, p256dh:, auth:, api_key: "")
16
18
  endpoint = endpoint.gsub(GCM_URL, TEMP_GCM_URL)
17
- p256dh = unescape_base64(p256dh)
18
- auth = unescape_base64(auth)
19
19
 
20
- payload = encrypt(message, p256dh, auth)
20
+ payload = Webpush::Encryption.encrypt(message, p256dh, auth)
21
21
  push_server_post(endpoint, payload, api_key)
22
22
  end
23
23
 
@@ -45,84 +45,5 @@ module Webpush
45
45
  return false
46
46
  end
47
47
  end
48
-
49
- def encrypt(message, p256dh, auth)
50
- group_name = "prime256v1"
51
- salt = Random.new.bytes(16)
52
-
53
- server = OpenSSL::PKey::EC.new(group_name)
54
- server.generate_key
55
- server_public_key_bn = server.public_key.to_bn
56
-
57
- group = OpenSSL::PKey::EC::Group.new(group_name)
58
- client_public_key_hex = Base64.decode64(p256dh).unpack("H*").first
59
- client_public_key_bn = OpenSSL::BN.new(client_public_key_hex, 16)
60
- client_public_key = OpenSSL::PKey::EC::Point.new(group, client_public_key_bn)
61
-
62
- shared_secret = server.dh_compute_key(client_public_key)
63
-
64
- clientAuthToken = Base64.decode64(auth)
65
-
66
- prk = HKDF.new(shared_secret, :salt => clientAuthToken, :algorithm => 'SHA256', :info => "Content-Encoding: auth\0").next_bytes(32)
67
-
68
- context = create_context(client_public_key_bn, server_public_key_bn)
69
-
70
- content_encryption_key_info = create_info('aesgcm', context)
71
- content_encryption_key = HKDF.new(prk, :salt => salt, :info => content_encryption_key_info).next_bytes(16)
72
-
73
- nonce_info = create_info('nonce', context)
74
- nonce = HKDF.new(prk, :salt => salt, :info => nonce_info).next_bytes(12)
75
-
76
- ciphertext = encrypt_payload(message, content_encryption_key, nonce)
77
-
78
- {
79
- ciphertext: ciphertext,
80
- salt: salt,
81
- server_public_key_bn: convert16bit(server_public_key_bn)
82
- }
83
- end
84
-
85
- def create_context(clientPublicKey, serverPublicKey)
86
- c = convert16bit(clientPublicKey)
87
- s = convert16bit(serverPublicKey)
88
- context = "\0"
89
- context += [c.bytesize].pack("n*")
90
- context += c
91
- context += [s.bytesize].pack("n*")
92
- context += s
93
- context
94
- end
95
-
96
- def encrypt_payload(plaintext, content_encryption_key, nonce)
97
- cipher = OpenSSL::Cipher.new('aes-128-gcm')
98
- cipher.encrypt
99
- cipher.key = content_encryption_key
100
- cipher.iv = nonce
101
- padding = cipher.update("\0\0")
102
- text = cipher.update(plaintext)
103
-
104
- e_text = padding + text + cipher.final
105
- e_tag = cipher.auth_tag
106
-
107
- e_text + e_tag
108
- end
109
-
110
- def create_info(type, context)
111
- info = "Content-Encoding: "
112
- info += type
113
- info += "\0"
114
- info += "P-256"
115
- info += context
116
- info
117
- end
118
-
119
- def convert16bit(key)
120
- [key.to_s(16)].pack("H*")
121
- end
122
-
123
- def unescape_base64(base64)
124
- base64.gsub(/_|\-/, "_" => "/", "-" => "+")
125
- end
126
48
  end
127
-
128
49
  end
@@ -0,0 +1,81 @@
1
+ module Webpush
2
+ module Encryption
3
+ extend self
4
+
5
+ def encrypt(message, p256dh, auth)
6
+ group_name = "prime256v1"
7
+ salt = Random.new.bytes(16)
8
+
9
+ server = OpenSSL::PKey::EC.new(group_name)
10
+ server.generate_key
11
+ server_public_key_bn = server.public_key.to_bn
12
+
13
+ group = OpenSSL::PKey::EC::Group.new(group_name)
14
+ client_public_key_bn = OpenSSL::BN.new(Base64.urlsafe_decode64(p256dh), 2)
15
+ client_public_key = OpenSSL::PKey::EC::Point.new(group, client_public_key_bn)
16
+
17
+ shared_secret = server.dh_compute_key(client_public_key)
18
+
19
+ client_auth_token = Base64.urlsafe_decode64(auth)
20
+
21
+ prk = HKDF.new(shared_secret, :salt => client_auth_token, :algorithm => 'SHA256', :info => "Content-Encoding: auth\0").next_bytes(32)
22
+
23
+ context = create_context(client_public_key_bn, server_public_key_bn)
24
+
25
+ content_encryption_key_info = create_info('aesgcm', context)
26
+ content_encryption_key = HKDF.new(prk, :salt => salt, :info => content_encryption_key_info).next_bytes(16)
27
+
28
+ nonce_info = create_info('nonce', context)
29
+ nonce = HKDF.new(prk, :salt => salt, :info => nonce_info).next_bytes(12)
30
+
31
+ ciphertext = encrypt_payload(message, content_encryption_key, nonce)
32
+
33
+ {
34
+ ciphertext: ciphertext,
35
+ salt: salt,
36
+ server_public_key_bn: convert16bit(server_public_key_bn),
37
+ shared_secret: shared_secret
38
+ }
39
+ end
40
+
41
+ private
42
+
43
+ def create_context(clientPublicKey, serverPublicKey)
44
+ c = convert16bit(clientPublicKey)
45
+ s = convert16bit(serverPublicKey)
46
+ context = "\0"
47
+ context += [c.bytesize].pack("n*")
48
+ context += c
49
+ context += [s.bytesize].pack("n*")
50
+ context += s
51
+ context
52
+ end
53
+
54
+ def encrypt_payload(plaintext, content_encryption_key, nonce)
55
+ cipher = OpenSSL::Cipher.new('aes-128-gcm')
56
+ cipher.encrypt
57
+ cipher.key = content_encryption_key
58
+ cipher.iv = nonce
59
+ padding = cipher.update("\0\0")
60
+ text = cipher.update(plaintext)
61
+
62
+ e_text = padding + text + cipher.final
63
+ e_tag = cipher.auth_tag
64
+
65
+ e_text + e_tag
66
+ end
67
+
68
+ def create_info(type, context)
69
+ info = "Content-Encoding: "
70
+ info += type
71
+ info += "\0"
72
+ info += "P-256"
73
+ info += context
74
+ info
75
+ end
76
+
77
+ def convert16bit(key)
78
+ [key.to_s(16)].pack("H*")
79
+ end
80
+ end
81
+ end
@@ -1,3 +1,3 @@
1
1
  module Webpush
2
- VERSION = "0.1.5"
2
+ VERSION = "0.1.6"
3
3
  end
data/webpush.gemspec CHANGED
@@ -20,6 +20,9 @@ Gem::Specification.new do |spec|
20
20
  spec.add_dependency "hkdf", "~> 0.2"
21
21
 
22
22
  spec.add_development_dependency "bundler", "~> 1.11"
23
+ spec.add_development_dependency 'pry'
23
24
  spec.add_development_dependency "rake", "~> 10.0"
24
25
  spec.add_development_dependency "rspec", "~> 3.0"
26
+ spec.add_development_dependency "webmock", "~> 1.24"
27
+ spec.add_development_dependency "ece", "~> 0.2"
25
28
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: webpush
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.5
4
+ version: 0.1.6
5
5
  platform: ruby
6
6
  authors:
7
7
  - zaru@sakuraba
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2016-04-29 00:00:00.000000000 Z
11
+ date: 2016-05-12 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: hkdf
@@ -38,6 +38,20 @@ dependencies:
38
38
  - - "~>"
39
39
  - !ruby/object:Gem::Version
40
40
  version: '1.11'
41
+ - !ruby/object:Gem::Dependency
42
+ name: pry
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
41
55
  - !ruby/object:Gem::Dependency
42
56
  name: rake
43
57
  requirement: !ruby/object:Gem::Requirement
@@ -66,6 +80,34 @@ dependencies:
66
80
  - - "~>"
67
81
  - !ruby/object:Gem::Version
68
82
  version: '3.0'
83
+ - !ruby/object:Gem::Dependency
84
+ name: webmock
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - "~>"
88
+ - !ruby/object:Gem::Version
89
+ version: '1.24'
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - "~>"
95
+ - !ruby/object:Gem::Version
96
+ version: '1.24'
97
+ - !ruby/object:Gem::Dependency
98
+ name: ece
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - "~>"
102
+ - !ruby/object:Gem::Version
103
+ version: '0.2'
104
+ type: :development
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - "~>"
109
+ - !ruby/object:Gem::Version
110
+ version: '0.2'
69
111
  description:
70
112
  email:
71
113
  - zarutofu@gmail.com
@@ -80,8 +122,10 @@ files:
80
122
  - README.md
81
123
  - Rakefile
82
124
  - bin/console
125
+ - bin/rake
83
126
  - bin/setup
84
127
  - lib/webpush.rb
128
+ - lib/webpush/encryption.rb
85
129
  - lib/webpush/version.rb
86
130
  - webpush.gemspec
87
131
  homepage: https://github.com/zaru/webpush
@@ -103,7 +147,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
103
147
  version: '0'
104
148
  requirements: []
105
149
  rubyforge_project:
106
- rubygems_version: 2.5.1
150
+ rubygems_version: 2.4.5.1
107
151
  signing_key:
108
152
  specification_version: 4
109
153
  summary: Encryption Utilities for Web Push payload.