webpush 0.1.5 → 0.1.6

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 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.