web-push 1.0.0 → 2.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.github/workflows/ci.yml +22 -0
- data/.gitignore +1 -9
- data/README.md +48 -211
- data/lib/web_push/encryption.rb +3 -5
- data/lib/web_push/request.rb +5 -33
- data/lib/web_push/vapid_key.rb +8 -3
- data/lib/web_push/version.rb +1 -1
- data/lib/web_push.rb +2 -3
- data/spec/spec_helper.rb +1 -2
- data/spec/web_push/encryption_spec.rb +3 -3
- data/spec/web_push/request_spec.rb +1 -46
- data/spec/web_push/vapid_key_spec.rb +29 -0
- data/spec/web_push_spec.rb +4 -4
- data/web-push.gemspec +5 -6
- metadata +19 -56
- data/.rspec +0 -2
- data/.rubocop.yml +0 -30
- data/.travis.yml +0 -24
- data/CHANGELOG.md +0 -183
- data/Rakefile +0 -8
- data/bin/console +0 -14
- data/bin/rake +0 -16
- data/bin/rspec +0 -16
- data/bin/setup +0 -8
- data/lib/tasks/web_push.rake +0 -14
- data/lib/web_push/railtie.rb +0 -9
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 0ce88ebd076b697f1933784607d0e7d743e66c0fe2a3522b2d91fbf8f7d674b4
|
4
|
+
data.tar.gz: b8eede6dba32f1933ab8ea706dd27dcc7d54fcc2a1bafb6c63249accc2e335f5
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 8cfedadf6aa0335ac451df3b47358b801802aed8e81f49ab869826eef67ff64bb06950095fd8764c259b37165dd5cdd7537521f23957cde359bb41e14661f53d
|
7
|
+
data.tar.gz: 8cb1d4e8711c0356dd22b10befaf535cbe9fbc3878bb18414f708dfa378472f2728d576641831822c63928320c10b79ded83cc888542280a9161eb83b194df86
|
@@ -0,0 +1,22 @@
|
|
1
|
+
name: CI
|
2
|
+
on:
|
3
|
+
push:
|
4
|
+
branches: [ master ]
|
5
|
+
pull_request:
|
6
|
+
branches: [ master ]
|
7
|
+
jobs:
|
8
|
+
test:
|
9
|
+
runs-on: ubuntu-latest
|
10
|
+
strategy:
|
11
|
+
fail-fast: false
|
12
|
+
matrix:
|
13
|
+
ruby-version: ['3.0', '3.1']
|
14
|
+
steps:
|
15
|
+
- uses: actions/checkout@v3
|
16
|
+
- name: Set up Ruby
|
17
|
+
uses: ruby/setup-ruby@v1
|
18
|
+
with:
|
19
|
+
ruby-version: ${{ matrix.ruby-version }}
|
20
|
+
bundler-cache: true
|
21
|
+
- name: Run tests
|
22
|
+
run: bundle exec rspec
|
data/.gitignore
CHANGED
data/README.md
CHANGED
@@ -1,45 +1,35 @@
|
|
1
1
|
# WebPush
|
2
2
|
|
3
|
-
[![
|
4
|
-
|
5
|
-
[![Build Status](https://travis-ci.org/zaru/webpush.svg?branch=master)](https://travis-ci.org/zaru/webpush)
|
6
|
-
[![Gem Version](https://badge.fury.io/rb/webpush.svg)](https://badge.fury.io/rb/webpush)
|
3
|
+
[![Gem Version](https://badge.fury.io/rb/web-push.svg)](https://badge.fury.io/rb/web-push)
|
4
|
+
![Build Status](https://github.com/pushpad/web-push/workflows/CI/badge.svg)
|
7
5
|
|
8
|
-
This gem makes it possible to send push messages to web browsers from Ruby backends using the [Web Push Protocol](https://
|
9
|
-
|
10
|
-
Payload is supported by Chrome 50+, Firefox 48+, Edge 79+.
|
11
|
-
|
12
|
-
[webpush Demo app here (building by Sinatra app).](https://github.com/zaru/webpush_demo_ruby)
|
6
|
+
This gem makes it possible to send push messages to web browsers from Ruby backends using the [Web Push Protocol](https://datatracker.ietf.org/doc/html/rfc8030). It supports [Message Encryption for Web Push](https://datatracker.ietf.org/doc/html/rfc8291) and [VAPID](https://datatracker.ietf.org/doc/html/rfc8292).
|
13
7
|
|
14
8
|
## Installation
|
15
9
|
|
16
|
-
Add this line to
|
10
|
+
Add this line to the Gemfile:
|
17
11
|
|
18
12
|
```ruby
|
19
13
|
gem 'web-push'
|
20
14
|
```
|
21
15
|
|
22
|
-
|
23
|
-
|
24
|
-
$ bundle
|
16
|
+
Or install the gem:
|
25
17
|
|
26
|
-
|
27
|
-
|
28
|
-
|
18
|
+
```console
|
19
|
+
$ gem install web-push
|
20
|
+
```
|
29
21
|
|
30
22
|
## Usage
|
31
23
|
|
32
24
|
Sending a web push message to a visitor of your website requires a number of steps:
|
33
25
|
|
34
|
-
1.
|
35
|
-
2.
|
36
|
-
3.
|
37
|
-
4. Your server uses the `web-push` gem to send a notification with the `subscription` obtained from the client and an optional payload (the message).
|
38
|
-
5. Your service worker is set up to receive `'push'` events. To trigger a desktop notification, the user has accepted the prompt to receive notifications from your site.
|
26
|
+
1. In the user's web browser, a `serviceWorker` is installed and activated and its `pushManager` property is subscribed to push events with your VAPID public key, which creates a `subscription` JSON object on the client side.
|
27
|
+
2. Your server uses the `web-push` gem to send a notification with the `subscription` obtained from the client and an optional payload (the message).
|
28
|
+
3. Your service worker is set up to receive `'push'` events. To trigger a desktop notification, the user has accepted the prompt to receive notifications from your site.
|
39
29
|
|
40
30
|
### Generating VAPID keys
|
41
31
|
|
42
|
-
Use `web-push` to generate a VAPID key that has both a `public_key` and `private_key`
|
32
|
+
Use `web-push` to generate a VAPID key pair (that has both a `public_key` and `private_key`) and save it on the server side.
|
43
33
|
|
44
34
|
```ruby
|
45
35
|
# One-time, on the server
|
@@ -53,64 +43,25 @@ vapid_key.private_key
|
|
53
43
|
vapid_key.to_pem
|
54
44
|
```
|
55
45
|
|
56
|
-
### Declaring manifest.json
|
57
|
-
|
58
|
-
Check out the [Web Manifest docs](https://developer.mozilla.org/en-US/docs/Web/Manifest) for details on what to include in your `manifest.json` file. If using VAPID, no app credentials are needed.
|
59
|
-
|
60
|
-
```javascript
|
61
|
-
{
|
62
|
-
"name": "My Website"
|
63
|
-
}
|
64
|
-
```
|
65
|
-
For Chrome web push, add the GCM sender id to a `manifest.json`.
|
66
|
-
|
67
|
-
```javascript
|
68
|
-
{
|
69
|
-
"name": "My Website",
|
70
|
-
"gcm_sender_id": "1006629465533"
|
71
|
-
}
|
72
|
-
```
|
73
|
-
|
74
|
-
The file is served within the scope of your service worker script, like at the root, and link to it somewhere in the `<head>` tag:
|
75
|
-
|
76
|
-
```html
|
77
|
-
<!-- index.html -->
|
78
|
-
<link rel="manifest" href="/manifest.json" />
|
79
|
-
```
|
80
|
-
|
81
46
|
### Installing a service worker
|
82
47
|
|
83
|
-
Your application
|
48
|
+
Your application must use JavaScript to register a service worker script at an appropriate scope (root is recommended).
|
84
49
|
|
85
50
|
```javascript
|
86
|
-
|
87
|
-
// Register the serviceWorker script at /serviceworker.js from your server if supported
|
88
|
-
if (navigator.serviceWorker) {
|
89
|
-
navigator.serviceWorker.register('/serviceworker.js')
|
90
|
-
.then(function(reg) {
|
91
|
-
console.log('Service worker change, registered the service worker');
|
92
|
-
});
|
93
|
-
}
|
94
|
-
// Otherwise, no push notifications :(
|
95
|
-
else {
|
96
|
-
console.error('Service worker is not supported in this browser');
|
97
|
-
}
|
51
|
+
navigator.serviceWorker.register('/service-worker.js')
|
98
52
|
```
|
99
53
|
|
100
54
|
### Subscribing to push notifications
|
101
55
|
|
102
|
-
|
103
|
-
|
104
|
-
The VAPID public key you generated earlier is made available to the client as a `UInt8Array`. To do this, one way would be to expose the urlsafe-decoded bytes from Ruby to JavaScript when rendering the HTML template. (Global variables used here for simplicity).
|
56
|
+
The VAPID public key you generated earlier is made available to the client as a `UInt8Array`. To do this, one way would be to expose the urlsafe-decoded bytes from Ruby to JavaScript when rendering the HTML template.
|
105
57
|
|
106
58
|
```javascript
|
107
59
|
window.vapidPublicKey = new Uint8Array(<%= Base64.urlsafe_decode64(ENV['VAPID_PUBLIC_KEY']).bytes %>);
|
108
60
|
```
|
109
61
|
|
110
|
-
Your
|
62
|
+
Your JavaScript code uses the `pushManager` interface to subscribe to push notifications, passing the VAPID public key to the subscription settings.
|
111
63
|
|
112
64
|
```javascript
|
113
|
-
// application.js
|
114
65
|
// When serviceWorker is supported, installed, and activated,
|
115
66
|
// subscribe the pushManager property with the vapidPublicKey
|
116
67
|
navigator.serviceWorker.ready.then((serviceWorkerRegistration) => {
|
@@ -122,120 +73,49 @@ navigator.serviceWorker.ready.then((serviceWorkerRegistration) => {
|
|
122
73
|
});
|
123
74
|
```
|
124
75
|
|
125
|
-
#### Without VAPID
|
126
|
-
|
127
|
-
If you will not be sending VAPID details, then there is no need generate VAPID keys, and the `applicationServerKey` parameter may be omitted from the `pushManager.subscribe` call.
|
128
|
-
|
129
|
-
```javascript
|
130
|
-
// application.js
|
131
|
-
// When serviceWorker is supported, installed, and activated,
|
132
|
-
// subscribe the pushManager property with the vapidPublicKey
|
133
|
-
navigator.serviceWorker.ready.then((serviceWorkerRegistration) => {
|
134
|
-
serviceWorkerRegistration.pushManager
|
135
|
-
.subscribe({
|
136
|
-
userVisibleOnly: true
|
137
|
-
});
|
138
|
-
});
|
139
|
-
```
|
140
|
-
|
141
76
|
### Triggering a web push notification
|
142
77
|
|
143
|
-
|
144
|
-
|
145
|
-
```javascript
|
146
|
-
// application.js
|
147
|
-
// Send the subscription and message from the client for the backend
|
148
|
-
// to set up a push notification
|
149
|
-
$(".web-push-button").on("click", (e) => {
|
150
|
-
navigator.serviceWorker.ready
|
151
|
-
.then((serviceWorkerRegistration) => {
|
152
|
-
serviceWorkerRegistration.pushManager.getSubscription()
|
153
|
-
.then((subscription) => {
|
154
|
-
$.post("/push", { subscription: subscription.toJSON(), message: "You clicked a button!" });
|
155
|
-
});
|
156
|
-
});
|
157
|
-
});
|
158
|
-
```
|
78
|
+
In order to send web push notifications, the push subscription must be stored in the backend. Get the subscription with `pushManager.getSubscription()` and store it in your database.
|
159
79
|
|
160
|
-
|
80
|
+
Then you can use this gem to send web push messages:
|
161
81
|
|
162
82
|
```ruby
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
ssl_timeout: 5, # value for Net::HTTP#ssl_timeout=, optional
|
178
|
-
open_timeout: 5, # value for Net::HTTP#open_timeout=, optional
|
179
|
-
read_timeout: 5 # value for Net::HTTP#read_timeout=, optional
|
180
|
-
)
|
181
|
-
end
|
83
|
+
WebPush.payload_send(
|
84
|
+
message: message,
|
85
|
+
endpoint: subscription['endpoint'],
|
86
|
+
p256dh: subscription['keys']['p256dh'],
|
87
|
+
auth: subscription['keys']['auth'],
|
88
|
+
vapid: {
|
89
|
+
subject: "mailto:sender@example.com",
|
90
|
+
public_key: ENV['VAPID_PUBLIC_KEY'],
|
91
|
+
private_key: ENV['VAPID_PRIVATE_KEY']
|
92
|
+
},
|
93
|
+
ssl_timeout: 5, # optional value for Net::HTTP#ssl_timeout=
|
94
|
+
open_timeout: 5, # optional value for Net::HTTP#open_timeout=
|
95
|
+
read_timeout: 5 # optional value for Net::HTTP#read_timeout=
|
96
|
+
)
|
182
97
|
```
|
183
98
|
|
184
|
-
Note: the VAPID options should be omitted if the client-side subscription was
|
185
|
-
generated without the `applicationServerKey` parameter described earlier. You
|
186
|
-
would instead pass the GCM api key along with the api request as shown in the
|
187
|
-
Usage section below.
|
188
|
-
|
189
99
|
### Receiving the push event
|
190
100
|
|
191
|
-
Your
|
101
|
+
Your `service-worker.js` script should respond to `'push'` events. One action it can take is to trigger desktop notifications by calling `showNotification` on the `registration` property.
|
192
102
|
|
193
103
|
```javascript
|
194
|
-
|
195
|
-
//
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
let body = "We have received a push message";
|
200
|
-
let tag = "push-simple-demo-notification-tag";
|
201
|
-
let icon = '/assets/my-logo-120x120.png';
|
202
|
-
|
203
|
-
event.waitUntil(
|
204
|
-
self.registration.showNotification(title, { body, icon, tag })
|
205
|
-
)
|
104
|
+
self.addEventListener('push', (event) => {
|
105
|
+
// Get the push message
|
106
|
+
var message = event.data;
|
107
|
+
// Display a notification
|
108
|
+
event.waitUntil(self.registration.showNotification('Example'));
|
206
109
|
});
|
207
110
|
```
|
208
111
|
|
209
|
-
Before the notifications can be displayed, the user must grant permission for [notifications](https://developer.mozilla.org/en-US/docs/Web/API/notification) in a browser prompt
|
112
|
+
Before the notifications can be displayed, the user must grant permission for [notifications](https://developer.mozilla.org/en-US/docs/Web/API/notification) in a browser prompt. Use something like this in your JavaScript code:
|
210
113
|
|
211
114
|
```javascript
|
212
|
-
|
213
|
-
|
214
|
-
// Let's check if the browser supports notifications
|
215
|
-
if (!("Notification" in window)) {
|
216
|
-
console.error("This browser does not support desktop notification");
|
217
|
-
}
|
218
|
-
|
219
|
-
// Let's check whether notification permissions have already been granted
|
220
|
-
else if (Notification.permission === "granted") {
|
221
|
-
console.log("Permission to receive notifications has been granted");
|
222
|
-
}
|
223
|
-
|
224
|
-
// Otherwise, we need to ask the user for permission
|
225
|
-
else if (Notification.permission !== 'denied') {
|
226
|
-
Notification.requestPermission(function (permission) {
|
227
|
-
// If the user accepts, let's create a notification
|
228
|
-
if (permission === "granted") {
|
229
|
-
console.log("Permission to receive notifications has been granted");
|
230
|
-
}
|
231
|
-
});
|
232
|
-
}
|
115
|
+
Notification.requestPermission();
|
233
116
|
```
|
234
117
|
|
235
|
-
If everything worked, you should see a desktop notification triggered via web
|
236
|
-
push. Yay!
|
237
|
-
|
238
|
-
Note: if you're using Rails, check out [serviceworker-rails](https://github.com/rossta/serviceworker-rails), a gem that makes it easier to host serviceworker scripts and manifest.json files at canonical endpoints (i.e., non-digested URLs) while taking advantage of the asset pipeline.
|
118
|
+
If everything worked, you should see a desktop notification triggered via web push. Yay!
|
239
119
|
|
240
120
|
## API
|
241
121
|
|
@@ -243,9 +123,9 @@ Note: if you're using Rails, check out [serviceworker-rails](https://github.com/
|
|
243
123
|
|
244
124
|
```ruby
|
245
125
|
message = {
|
246
|
-
title: "
|
247
|
-
body: "
|
248
|
-
icon: "
|
126
|
+
title: "Example",
|
127
|
+
body: "Hello, world!",
|
128
|
+
icon: "https://example.com/icon.png"
|
249
129
|
}
|
250
130
|
|
251
131
|
WebPush.payload_send(
|
@@ -304,53 +184,10 @@ WebPush.payload_send(
|
|
304
184
|
)
|
305
185
|
```
|
306
186
|
|
307
|
-
|
308
|
-
|
309
|
-
```ruby
|
310
|
-
WebPush.payload_send(
|
311
|
-
endpoint: "https://fcm.googleapis.com/gcm/send/eah7hak....",
|
312
|
-
message: "A message",
|
313
|
-
p256dh: "BO/aG9nYXNkZmFkc2ZmZHNmYWRzZmFl...",
|
314
|
-
auth: "aW1hcmthcmFpa3V6ZQ==",
|
315
|
-
api_key: "<GCM API KEY>"
|
316
|
-
)
|
317
|
-
```
|
318
|
-
|
319
|
-
### ServiceWorker sample
|
320
|
-
|
321
|
-
see. https://github.com/zaru/web-push-sample
|
322
|
-
|
323
|
-
p256dh and auth generate sample code.
|
324
|
-
|
325
|
-
```javascript
|
326
|
-
navigator.serviceWorker.ready.then(function(sw) {
|
327
|
-
Notification.requestPermission(function(permission) {
|
328
|
-
if(permission !== 'denied') {
|
329
|
-
sw.pushManager.subscribe({userVisibleOnly: true}).then(function(s) {
|
330
|
-
var data = {
|
331
|
-
endpoint: s.endpoint,
|
332
|
-
p256dh: btoa(String.fromCharCode.apply(null, new Uint8Array(s.getKey('p256dh')))).replace(/\+/g, '-').replace(/\//g, '_'),
|
333
|
-
auth: btoa(String.fromCharCode.apply(null, new Uint8Array(s.getKey('auth')))).replace(/\+/g, '-').replace(/\//g, '_')
|
334
|
-
}
|
335
|
-
console.log(data);
|
336
|
-
});
|
337
|
-
}
|
338
|
-
});
|
339
|
-
});
|
340
|
-
```
|
187
|
+
## Contributing
|
341
188
|
|
342
|
-
|
189
|
+
Bug reports and pull requests are welcome on GitHub at https://github.com/pushpad/web-push.
|
343
190
|
|
344
|
-
|
345
|
-
self.addEventListener("push", function(event) {
|
346
|
-
var json = event.data.json();
|
347
|
-
self.registration.showNotification(json.title, {
|
348
|
-
body: json.body,
|
349
|
-
icon: json.icon
|
350
|
-
});
|
351
|
-
});
|
352
|
-
```
|
353
|
-
|
354
|
-
## Contributing
|
191
|
+
## Credits
|
355
192
|
|
356
|
-
|
193
|
+
This library is a fork of [zaru/webpush](https://github.com/zaru/webpush) actively maintained by [Pushpad](https://pushpad.xyz) with many improvements, bug fixes and frequent updates.
|
data/lib/web_push/encryption.rb
CHANGED
@@ -4,7 +4,6 @@ module WebPush
|
|
4
4
|
module Encryption
|
5
5
|
extend self
|
6
6
|
|
7
|
-
# rubocop:disable Metrics/AbcSize, Metrics/MethodLength
|
8
7
|
def encrypt(message, p256dh, auth)
|
9
8
|
assert_arguments(message, p256dh, auth)
|
10
9
|
|
@@ -27,11 +26,11 @@ module WebPush
|
|
27
26
|
content_encryption_key_info = "Content-Encoding: aes128gcm\0"
|
28
27
|
nonce_info = "Content-Encoding: nonce\0"
|
29
28
|
|
30
|
-
prk = HKDF.new(shared_secret, salt: client_auth_token, algorithm: 'SHA256', info: info).
|
29
|
+
prk = HKDF.new(shared_secret, salt: client_auth_token, algorithm: 'SHA256', info: info).read(32)
|
31
30
|
|
32
|
-
content_encryption_key = HKDF.new(prk, salt: salt, info: content_encryption_key_info).
|
31
|
+
content_encryption_key = HKDF.new(prk, salt: salt, info: content_encryption_key_info).read(16)
|
33
32
|
|
34
|
-
nonce = HKDF.new(prk, salt: salt, info: nonce_info).
|
33
|
+
nonce = HKDF.new(prk, salt: salt, info: nonce_info).read(12)
|
35
34
|
|
36
35
|
ciphertext = encrypt_payload(message, content_encryption_key, nonce)
|
37
36
|
|
@@ -43,7 +42,6 @@ module WebPush
|
|
43
42
|
|
44
43
|
aes128gcmheader + ciphertext
|
45
44
|
end
|
46
|
-
# rubocop:enable Metrics/AbcSize, Metrics/MethodLength
|
47
45
|
|
48
46
|
private
|
49
47
|
|
data/lib/web_push/request.rb
CHANGED
@@ -1,25 +1,16 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require 'uri'
|
4
|
-
require 'jwt'
|
5
|
-
require 'base64'
|
6
|
-
|
7
3
|
module WebPush
|
8
|
-
# It is temporary URL until supported by the GCM server.
|
9
|
-
GCM_URL = 'https://android.googleapis.com/gcm/send'.freeze
|
10
|
-
TEMP_GCM_URL = 'https://fcm.googleapis.com/fcm'.freeze
|
11
4
|
|
12
|
-
# rubocop:disable Metrics/ClassLength
|
13
5
|
class Request
|
14
6
|
def initialize(message: '', subscription:, vapid:, **options)
|
15
7
|
endpoint = subscription.fetch(:endpoint)
|
16
|
-
@endpoint = endpoint
|
8
|
+
@endpoint = endpoint
|
17
9
|
@payload = build_payload(message, subscription)
|
18
10
|
@vapid_options = vapid
|
19
11
|
@options = default_options.merge(options)
|
20
12
|
end
|
21
13
|
|
22
|
-
# rubocop:disable Metrics/AbcSize
|
23
14
|
def perform
|
24
15
|
http = Net::HTTP.new(uri.host, uri.port, *proxy_options)
|
25
16
|
http.use_ssl = true
|
@@ -35,7 +26,6 @@ module WebPush
|
|
35
26
|
|
36
27
|
resp
|
37
28
|
end
|
38
|
-
# rubocop:enable Metrics/AbcSize
|
39
29
|
|
40
30
|
def proxy_options
|
41
31
|
return [] unless @options[:proxy]
|
@@ -45,7 +35,6 @@ module WebPush
|
|
45
35
|
[proxy_uri.host, proxy_uri.port, proxy_uri.user, proxy_uri.password]
|
46
36
|
end
|
47
37
|
|
48
|
-
# rubocop:disable Metrics/MethodLength
|
49
38
|
def headers
|
50
39
|
headers = {}
|
51
40
|
headers['Content-Type'] = 'application/octet-stream'
|
@@ -57,24 +46,18 @@ module WebPush
|
|
57
46
|
headers["Content-Length"] = @payload.length.to_s
|
58
47
|
end
|
59
48
|
|
60
|
-
if
|
61
|
-
headers['Authorization'] = "key=#{api_key}"
|
62
|
-
elsif vapid?
|
49
|
+
if vapid?
|
63
50
|
headers["Authorization"] = build_vapid_header
|
64
51
|
end
|
65
52
|
|
66
53
|
headers
|
67
54
|
end
|
68
|
-
# rubocop:enable Metrics/MethodLength
|
69
55
|
|
70
56
|
def build_vapid_header
|
71
|
-
# https://tools.ietf.org/id/draft-ietf-webpush-vapid-03.html
|
72
|
-
|
73
57
|
vapid_key = vapid_pem ? VapidKey.from_pem(vapid_pem) : VapidKey.from_keys(vapid_public_key, vapid_private_key)
|
74
58
|
jwt = JWT.encode(jwt_payload, vapid_key.curve, 'ES256', jwt_header_fields)
|
75
59
|
p256ecdsa = vapid_key.public_key_for_push_header
|
76
|
-
|
77
|
-
"vapid t=#{jwt},k=#{p256ecdsa}"
|
60
|
+
"vapid t=#{jwt},k=#{p256ecdsa}"
|
78
61
|
end
|
79
62
|
|
80
63
|
def body
|
@@ -112,11 +95,11 @@ module WebPush
|
|
112
95
|
end
|
113
96
|
|
114
97
|
def expiration
|
115
|
-
@vapid_options.fetch(:expiration,
|
98
|
+
@vapid_options.fetch(:expiration, 12 * 60 * 60)
|
116
99
|
end
|
117
100
|
|
118
101
|
def subject
|
119
|
-
@vapid_options.fetch(:subject, 'sender@example.com')
|
102
|
+
@vapid_options.fetch(:subject, 'mailto:sender@example.com')
|
120
103
|
end
|
121
104
|
|
122
105
|
def vapid_public_key
|
@@ -148,14 +131,6 @@ module WebPush
|
|
148
131
|
Encryption.encrypt(message, p256dh, auth)
|
149
132
|
end
|
150
133
|
|
151
|
-
def api_key
|
152
|
-
@options.fetch(:api_key, nil)
|
153
|
-
end
|
154
|
-
|
155
|
-
def api_key?
|
156
|
-
!(api_key.nil? || api_key.empty?) && @endpoint =~ %r{\Ahttps://(android|gcm-http|fcm)\.googleapis\.com}
|
157
|
-
end
|
158
|
-
|
159
134
|
def vapid?
|
160
135
|
@vapid_options.any?
|
161
136
|
end
|
@@ -164,7 +139,6 @@ module WebPush
|
|
164
139
|
WebPush.encode64(bin).delete('=')
|
165
140
|
end
|
166
141
|
|
167
|
-
# rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/MethodLength, Metrics/PerceivedComplexity, Style/GuardClause
|
168
142
|
def verify_response(resp)
|
169
143
|
if resp.is_a?(Net::HTTPGone) # 410
|
170
144
|
raise ExpiredSubscription.new(resp, uri.host)
|
@@ -183,7 +157,5 @@ module WebPush
|
|
183
157
|
raise ResponseError.new(resp, uri.host)
|
184
158
|
end
|
185
159
|
end
|
186
|
-
# rubocop:enable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/MethodLength, Metrics/PerceivedComplexity, Style/GuardClause
|
187
160
|
end
|
188
|
-
# rubocop:enable Metrics/ClassLength
|
189
161
|
end
|
data/lib/web_push/vapid_key.rb
CHANGED
@@ -78,10 +78,15 @@ module WebPush
|
|
78
78
|
alias to_hash to_h
|
79
79
|
|
80
80
|
def to_pem
|
81
|
-
|
82
|
-
|
81
|
+
private_key_to_pem + public_key_to_pem
|
82
|
+
end
|
83
|
+
|
84
|
+
def private_key_to_pem
|
85
|
+
curve.to_pem
|
86
|
+
end
|
83
87
|
|
84
|
-
|
88
|
+
def public_key_to_pem
|
89
|
+
curve.public_to_pem
|
85
90
|
end
|
86
91
|
|
87
92
|
def inspect
|
data/lib/web_push/version.rb
CHANGED
data/lib/web_push.rb
CHANGED
@@ -3,6 +3,8 @@
|
|
3
3
|
require 'openssl'
|
4
4
|
require 'base64'
|
5
5
|
require 'hkdf'
|
6
|
+
require 'jwt'
|
7
|
+
require 'uri'
|
6
8
|
require 'net/http'
|
7
9
|
require 'json'
|
8
10
|
|
@@ -11,7 +13,6 @@ require 'web_push/errors'
|
|
11
13
|
require 'web_push/vapid_key'
|
12
14
|
require 'web_push/encryption'
|
13
15
|
require 'web_push/request'
|
14
|
-
require 'web_push/railtie' if defined?(Rails)
|
15
16
|
|
16
17
|
# Push API implementation
|
17
18
|
#
|
@@ -34,7 +35,6 @@ module WebPush
|
|
34
35
|
# @param options [Hash<Symbol,String>] additional options for the notification
|
35
36
|
# @option options [#to_s] :ttl Time-to-live in seconds
|
36
37
|
# @option options [#to_s] :urgency Urgency can be very-low, low, normal, high
|
37
|
-
# rubocop:disable Metrics/ParameterLists
|
38
38
|
def payload_send(message: '', endpoint:, p256dh: '', auth: '', vapid: {}, **options)
|
39
39
|
WebPush::Request.new(
|
40
40
|
message: message,
|
@@ -43,7 +43,6 @@ module WebPush
|
|
43
43
|
**options
|
44
44
|
).perform
|
45
45
|
end
|
46
|
-
# rubocop:enable Metrics/ParameterLists
|
47
46
|
|
48
47
|
# Generate a VapidKey instance to obtain base64 encoded public and private keys
|
49
48
|
# suitable for VAPID protocol JSON web token signing
|
data/spec/spec_helper.rb
CHANGED
@@ -67,10 +67,10 @@ describe WebPush::Encryption do
|
|
67
67
|
content_encryption_key_info = "Content-Encoding: aes128gcm\0"
|
68
68
|
nonce_info = "Content-Encoding: nonce\0"
|
69
69
|
|
70
|
-
prk = HKDF.new(shared_secret, salt: client_auth_token, algorithm: 'SHA256', info: info).
|
70
|
+
prk = HKDF.new(shared_secret, salt: client_auth_token, algorithm: 'SHA256', info: info).read(32)
|
71
71
|
|
72
|
-
content_encryption_key = HKDF.new(prk, salt: salt, info: content_encryption_key_info).
|
73
|
-
nonce = HKDF.new(prk, salt: salt, info: nonce_info).
|
72
|
+
content_encryption_key = HKDF.new(prk, salt: salt, info: content_encryption_key_info).read(16)
|
73
|
+
nonce = HKDF.new(prk, salt: salt, info: nonce_info).read(12)
|
74
74
|
|
75
75
|
decrypt_ciphertext(ciphertext, content_encryption_key, nonce)
|
76
76
|
end
|
@@ -18,51 +18,6 @@ describe WebPush::Request do
|
|
18
18
|
end
|
19
19
|
end
|
20
20
|
|
21
|
-
describe 'from :api_key' do
|
22
|
-
def build_request_with_api_key(endpoint, options = {})
|
23
|
-
subscription = {
|
24
|
-
endpoint: endpoint,
|
25
|
-
keys: {
|
26
|
-
p256dh: 'p256dh',
|
27
|
-
auth: 'auth'
|
28
|
-
}
|
29
|
-
}
|
30
|
-
WebPush::Request.new(message: '', subscription: subscription, vapid: {}, **options)
|
31
|
-
end
|
32
|
-
|
33
|
-
it 'inserts Authorization header when api_key present, and endpoint is for Chrome\'s non-standards-compliant GCM endpoints' do
|
34
|
-
request = build_request_with_api_key('https://gcm-http.googleapis.com/gcm/xyz', api_key: 'api_key')
|
35
|
-
|
36
|
-
expect(request.headers['Authorization']).to eq('key=api_key')
|
37
|
-
end
|
38
|
-
|
39
|
-
it 'insert Authorization header for Chrome\'s new standards-compliant endpoints, even if api_key is present' do
|
40
|
-
request = build_request_with_api_key('https://fcm.googleapis.com/fcm/send/ABCD1234', api_key: 'api_key')
|
41
|
-
|
42
|
-
expect(request.headers['Authorization']).to eq('key=api_key')
|
43
|
-
end
|
44
|
-
|
45
|
-
it 'does not insert Authorization header when endpoint is not for Chrome, even if api_key is present' do
|
46
|
-
request = build_request_with_api_key('https://some.random.endpoint.com/xyz', api_key: 'api_key')
|
47
|
-
|
48
|
-
expect(request.headers['Authorization']).to be_nil
|
49
|
-
end
|
50
|
-
|
51
|
-
it 'does not insert Authorization header when api_key blank' do
|
52
|
-
request = build_request_with_api_key('endpoint', api_key: nil)
|
53
|
-
|
54
|
-
expect(request.headers['Authorization']).to be_nil
|
55
|
-
|
56
|
-
request = build_request_with_api_key('endpoint', api_key: '')
|
57
|
-
|
58
|
-
expect(request.headers['Authorization']).to be_nil
|
59
|
-
|
60
|
-
request = build_request_with_api_key('endpoint')
|
61
|
-
|
62
|
-
expect(request.headers['Authorization']).to be_nil
|
63
|
-
end
|
64
|
-
end
|
65
|
-
|
66
21
|
describe 'from :ttl' do
|
67
22
|
it 'can override Ttl with :ttl option with string' do
|
68
23
|
request = build_request(ttl: '300')
|
@@ -91,7 +46,7 @@ describe WebPush::Request do
|
|
91
46
|
time = Time.at(1_476_150_897)
|
92
47
|
jwt_payload = {
|
93
48
|
aud: 'https://fcm.googleapis.com',
|
94
|
-
exp: time.to_i +
|
49
|
+
exp: time.to_i + 12 * 60 * 60,
|
95
50
|
sub: 'mailto:sender@example.com'
|
96
51
|
}
|
97
52
|
jwt_header_fields = { "typ": "JWT", "alg": "ES256" }
|
@@ -43,6 +43,35 @@ describe WebPush::VapidKey do
|
|
43
43
|
expect(pem).to include('-----BEGIN PUBLIC KEY-----')
|
44
44
|
end
|
45
45
|
|
46
|
+
it 'returns the correct public and private keys in pem format' do
|
47
|
+
public_key_base64 = 'BMA-wciFTkEq2waVGB2hg8cSyiRiMcsIvIYQb3LkLOmBheh3YC6NB2GtE9t6YgaXt428rp7bC9JjuPtAY9AQaR8='
|
48
|
+
private_key_base64 = '4MwLvN1Cpxe43AV9fa4BiS-SPp51gWlhv9c6bb_XSJ4='
|
49
|
+
key = WebPush::VapidKey.from_keys(public_key_base64, private_key_base64)
|
50
|
+
pem = key.to_pem
|
51
|
+
expected_pem = <<~PEM
|
52
|
+
-----BEGIN EC PRIVATE KEY-----
|
53
|
+
MHcCAQEEIODMC7zdQqcXuNwFfX2uAYkvkj6edYFpYb/XOm2/10ieoAoGCCqGSM49
|
54
|
+
AwEHoUQDQgAEwD7ByIVOQSrbBpUYHaGDxxLKJGIxywi8hhBvcuQs6YGF6HdgLo0H
|
55
|
+
Ya0T23piBpe3jbyuntsL0mO4+0Bj0BBpHw==
|
56
|
+
-----END EC PRIVATE KEY-----
|
57
|
+
-----BEGIN PUBLIC KEY-----
|
58
|
+
MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEwD7ByIVOQSrbBpUYHaGDxxLKJGIx
|
59
|
+
ywi8hhBvcuQs6YGF6HdgLo0HYa0T23piBpe3jbyuntsL0mO4+0Bj0BBpHw==
|
60
|
+
-----END PUBLIC KEY-----
|
61
|
+
PEM
|
62
|
+
expect(pem).to eq(expected_pem)
|
63
|
+
end
|
64
|
+
|
65
|
+
it 'can return the private key in pem format' do
|
66
|
+
pem = WebPush::VapidKey.new.private_key_to_pem
|
67
|
+
expect(pem).to include('-----BEGIN EC PRIVATE KEY-----')
|
68
|
+
end
|
69
|
+
|
70
|
+
it 'can return the public key in pem format' do
|
71
|
+
pem = WebPush::VapidKey.new.public_key_to_pem
|
72
|
+
expect(pem).to include('-----BEGIN PUBLIC KEY-----')
|
73
|
+
end
|
74
|
+
|
46
75
|
it 'imports pem of public and private keys' do
|
47
76
|
pem = WebPush::VapidKey.new.to_pem
|
48
77
|
key = WebPush::VapidKey.from_pem pem
|
data/spec/web_push_spec.rb
CHANGED
@@ -194,8 +194,8 @@ describe WebPush do
|
|
194
194
|
include_examples 'request headers with VAPID'
|
195
195
|
end
|
196
196
|
|
197
|
-
context 'chrome
|
198
|
-
let(:endpoint) { 'https://
|
197
|
+
context 'chrome endpoint: request headers without VAPID' do
|
198
|
+
let(:endpoint) { 'https://fcm.googleapis.com/fcm/subscription-id' }
|
199
199
|
let(:expected_endpoint) { 'https://fcm.googleapis.com/fcm/subscription-id' }
|
200
200
|
|
201
201
|
let(:message) { JSON.generate(body: 'body') }
|
@@ -221,7 +221,7 @@ describe WebPush do
|
|
221
221
|
allow(WebPush::Encryption).to receive(:encrypt).and_return(payload)
|
222
222
|
end
|
223
223
|
|
224
|
-
subject { WebPush.payload_send(message: message, endpoint: endpoint, p256dh: p256dh, auth: auth
|
224
|
+
subject { WebPush.payload_send(message: message, endpoint: endpoint, p256dh: p256dh, auth: auth) }
|
225
225
|
|
226
226
|
it 'calls the relevant service with the correct headers' do
|
227
227
|
expect(WebPush::Encryption).to receive(:encrypt).and_return(payload)
|
@@ -247,7 +247,7 @@ describe WebPush do
|
|
247
247
|
.with(body: nil, headers: expected_headers)
|
248
248
|
.to_return(status: 201, body: '', headers: {})
|
249
249
|
|
250
|
-
WebPush.payload_send(endpoint: endpoint
|
250
|
+
WebPush.payload_send(endpoint: endpoint)
|
251
251
|
end
|
252
252
|
end
|
253
253
|
end
|
data/web-push.gemspec
CHANGED
@@ -3,6 +3,7 @@ require_relative 'lib/web_push/version'
|
|
3
3
|
Gem::Specification.new do |spec|
|
4
4
|
spec.name = 'web-push'
|
5
5
|
spec.version = WebPush::VERSION
|
6
|
+
spec.license = 'MIT'
|
6
7
|
spec.authors = ['zaru', 'collimarco']
|
7
8
|
spec.email = ['support@pushpad.xyz']
|
8
9
|
|
@@ -11,15 +12,13 @@ Gem::Specification.new do |spec|
|
|
11
12
|
|
12
13
|
spec.files = `git ls-files`.split("\n")
|
13
14
|
|
14
|
-
spec.required_ruby_version = '>=
|
15
|
+
spec.required_ruby_version = '>= 3.0'
|
15
16
|
|
16
|
-
spec.add_dependency 'hkdf', '~> 0
|
17
|
+
spec.add_dependency 'hkdf', '~> 1.0'
|
17
18
|
spec.add_dependency 'jwt', '~> 2.0'
|
19
|
+
spec.add_dependency 'openssl', '~> 2.2'
|
18
20
|
|
19
|
-
spec.add_development_dependency 'bundler', '>= 1.17.3'
|
20
|
-
spec.add_development_dependency 'pry'
|
21
|
-
spec.add_development_dependency 'rake', '>= 10.0'
|
22
21
|
spec.add_development_dependency 'rspec', '~> 3.0'
|
23
|
-
spec.add_development_dependency 'simplecov'
|
22
|
+
spec.add_development_dependency 'simplecov', '~> 0.0'
|
24
23
|
spec.add_development_dependency 'webmock', '~> 3.0'
|
25
24
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: web-push
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version:
|
4
|
+
version: 2.0.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- zaru
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2022-11-
|
12
|
+
date: 2022-11-27 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: hkdf
|
@@ -17,14 +17,14 @@ dependencies:
|
|
17
17
|
requirements:
|
18
18
|
- - "~>"
|
19
19
|
- !ruby/object:Gem::Version
|
20
|
-
version: '0
|
20
|
+
version: '1.0'
|
21
21
|
type: :runtime
|
22
22
|
prerelease: false
|
23
23
|
version_requirements: !ruby/object:Gem::Requirement
|
24
24
|
requirements:
|
25
25
|
- - "~>"
|
26
26
|
- !ruby/object:Gem::Version
|
27
|
-
version: '0
|
27
|
+
version: '1.0'
|
28
28
|
- !ruby/object:Gem::Dependency
|
29
29
|
name: jwt
|
30
30
|
requirement: !ruby/object:Gem::Requirement
|
@@ -40,47 +40,19 @@ dependencies:
|
|
40
40
|
- !ruby/object:Gem::Version
|
41
41
|
version: '2.0'
|
42
42
|
- !ruby/object:Gem::Dependency
|
43
|
-
name:
|
43
|
+
name: openssl
|
44
44
|
requirement: !ruby/object:Gem::Requirement
|
45
45
|
requirements:
|
46
|
-
- - "
|
47
|
-
- !ruby/object:Gem::Version
|
48
|
-
version: 1.17.3
|
49
|
-
type: :development
|
50
|
-
prerelease: false
|
51
|
-
version_requirements: !ruby/object:Gem::Requirement
|
52
|
-
requirements:
|
53
|
-
- - ">="
|
54
|
-
- !ruby/object:Gem::Version
|
55
|
-
version: 1.17.3
|
56
|
-
- !ruby/object:Gem::Dependency
|
57
|
-
name: pry
|
58
|
-
requirement: !ruby/object:Gem::Requirement
|
59
|
-
requirements:
|
60
|
-
- - ">="
|
61
|
-
- !ruby/object:Gem::Version
|
62
|
-
version: '0'
|
63
|
-
type: :development
|
64
|
-
prerelease: false
|
65
|
-
version_requirements: !ruby/object:Gem::Requirement
|
66
|
-
requirements:
|
67
|
-
- - ">="
|
68
|
-
- !ruby/object:Gem::Version
|
69
|
-
version: '0'
|
70
|
-
- !ruby/object:Gem::Dependency
|
71
|
-
name: rake
|
72
|
-
requirement: !ruby/object:Gem::Requirement
|
73
|
-
requirements:
|
74
|
-
- - ">="
|
46
|
+
- - "~>"
|
75
47
|
- !ruby/object:Gem::Version
|
76
|
-
version: '
|
77
|
-
type: :
|
48
|
+
version: '2.2'
|
49
|
+
type: :runtime
|
78
50
|
prerelease: false
|
79
51
|
version_requirements: !ruby/object:Gem::Requirement
|
80
52
|
requirements:
|
81
|
-
- - "
|
53
|
+
- - "~>"
|
82
54
|
- !ruby/object:Gem::Version
|
83
|
-
version: '
|
55
|
+
version: '2.2'
|
84
56
|
- !ruby/object:Gem::Dependency
|
85
57
|
name: rspec
|
86
58
|
requirement: !ruby/object:Gem::Requirement
|
@@ -99,16 +71,16 @@ dependencies:
|
|
99
71
|
name: simplecov
|
100
72
|
requirement: !ruby/object:Gem::Requirement
|
101
73
|
requirements:
|
102
|
-
- - "
|
74
|
+
- - "~>"
|
103
75
|
- !ruby/object:Gem::Version
|
104
|
-
version: '0'
|
76
|
+
version: '0.0'
|
105
77
|
type: :development
|
106
78
|
prerelease: false
|
107
79
|
version_requirements: !ruby/object:Gem::Requirement
|
108
80
|
requirements:
|
109
|
-
- - "
|
81
|
+
- - "~>"
|
110
82
|
- !ruby/object:Gem::Version
|
111
|
-
version: '0'
|
83
|
+
version: '0.0'
|
112
84
|
- !ruby/object:Gem::Dependency
|
113
85
|
name: webmock
|
114
86
|
requirement: !ruby/object:Gem::Requirement
|
@@ -130,25 +102,15 @@ executables: []
|
|
130
102
|
extensions: []
|
131
103
|
extra_rdoc_files: []
|
132
104
|
files:
|
105
|
+
- ".github/workflows/ci.yml"
|
133
106
|
- ".gitignore"
|
134
|
-
- ".rspec"
|
135
|
-
- ".rubocop.yml"
|
136
|
-
- ".travis.yml"
|
137
|
-
- CHANGELOG.md
|
138
107
|
- Gemfile
|
139
108
|
- LICENSE
|
140
109
|
- README.md
|
141
|
-
- Rakefile
|
142
|
-
- bin/console
|
143
|
-
- bin/rake
|
144
|
-
- bin/rspec
|
145
|
-
- bin/setup
|
146
|
-
- lib/tasks/web_push.rake
|
147
110
|
- lib/web-push.rb
|
148
111
|
- lib/web_push.rb
|
149
112
|
- lib/web_push/encryption.rb
|
150
113
|
- lib/web_push/errors.rb
|
151
|
-
- lib/web_push/railtie.rb
|
152
114
|
- lib/web_push/request.rb
|
153
115
|
- lib/web_push/vapid_key.rb
|
154
116
|
- lib/web_push/version.rb
|
@@ -159,7 +121,8 @@ files:
|
|
159
121
|
- spec/web_push_spec.rb
|
160
122
|
- web-push.gemspec
|
161
123
|
homepage: https://github.com/pushpad/web-push
|
162
|
-
licenses:
|
124
|
+
licenses:
|
125
|
+
- MIT
|
163
126
|
metadata: {}
|
164
127
|
post_install_message:
|
165
128
|
rdoc_options: []
|
@@ -169,14 +132,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
169
132
|
requirements:
|
170
133
|
- - ">="
|
171
134
|
- !ruby/object:Gem::Version
|
172
|
-
version: '
|
135
|
+
version: '3.0'
|
173
136
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
174
137
|
requirements:
|
175
138
|
- - ">="
|
176
139
|
- !ruby/object:Gem::Version
|
177
140
|
version: '0'
|
178
141
|
requirements: []
|
179
|
-
rubygems_version: 3.
|
142
|
+
rubygems_version: 3.3.26
|
180
143
|
signing_key:
|
181
144
|
specification_version: 4
|
182
145
|
summary: Web Push library for Ruby (RFC8030)
|
data/.rspec
DELETED
data/.rubocop.yml
DELETED
@@ -1,30 +0,0 @@
|
|
1
|
-
require: rubocop-performance
|
2
|
-
|
3
|
-
AllCops:
|
4
|
-
Exclude:
|
5
|
-
- 'bin/**/*'
|
6
|
-
|
7
|
-
Metrics/AbcSize:
|
8
|
-
Max: 20
|
9
|
-
|
10
|
-
Metrics/ClassLength:
|
11
|
-
Max: 100
|
12
|
-
|
13
|
-
Metrics/ModuleLength:
|
14
|
-
Max: 100
|
15
|
-
|
16
|
-
Metrics/LineLength:
|
17
|
-
Enabled: false
|
18
|
-
|
19
|
-
Metrics/BlockLength:
|
20
|
-
Exclude:
|
21
|
-
- spec/**/*_spec.rb
|
22
|
-
|
23
|
-
Lint/AmbiguousBlockAssociation:
|
24
|
-
Enabled: false
|
25
|
-
|
26
|
-
Style/Documentation:
|
27
|
-
Enabled: false
|
28
|
-
|
29
|
-
Style/IndentHeredoc:
|
30
|
-
Enabled: false
|
data/.travis.yml
DELETED
@@ -1,24 +0,0 @@
|
|
1
|
-
env:
|
2
|
-
global:
|
3
|
-
- CC_TEST_REPORTER_ID=155202524386dfebe0c3267a5c868b5417ff4cc2cde8ed301fb36b177d46a458
|
4
|
-
language: ruby
|
5
|
-
rvm:
|
6
|
-
- 2.2
|
7
|
-
- 2.3
|
8
|
-
- 2.4
|
9
|
-
- 2.5
|
10
|
-
- 2.6
|
11
|
-
- 2.7
|
12
|
-
before_install:
|
13
|
-
- gem uninstall -v '>= 2' -i $(rvm gemdir)@global -ax bundler || true
|
14
|
-
- gem install bundler -v 1.17.3
|
15
|
-
before_script:
|
16
|
-
- curl -L https://codeclimate.com/downloads/test-reporter/test-reporter-latest-linux-amd64 > ./cc-test-reporter
|
17
|
-
- chmod +x ./cc-test-reporter
|
18
|
-
- ./cc-test-reporter before-build
|
19
|
-
script: "bundle exec rake spec"
|
20
|
-
after_script:
|
21
|
-
- ./cc-test-reporter after-build --exit-code $TRAVIS_TEST_RESULT
|
22
|
-
addons:
|
23
|
-
code_climate:
|
24
|
-
repo_token: 155202524386dfebe0c3267a5c868b5417ff4cc2cde8ed301fb36b177d46a458
|
data/CHANGELOG.md
DELETED
@@ -1,183 +0,0 @@
|
|
1
|
-
# Changelog
|
2
|
-
|
3
|
-
## [v1.1.0](https://github.com/zaru/webpush/tree/v1.1.0) (2020-11-16)
|
4
|
-
|
5
|
-
[Full Changelog](https://github.com/zaru/webpush/compare/v1.0.0...v1.1.0)
|
6
|
-
|
7
|
-
**Merged pull requests:**
|
8
|
-
|
9
|
-
- Eliminate Ruby 2.7 warnings. [\#95](https://github.com/zaru/webpush/pull/95) ([morgoth](https://github.com/morgoth))
|
10
|
-
- set minimum ruby version is 2.2 [\#94](https://github.com/zaru/webpush/pull/94) ([Wolfer](https://github.com/Wolfer))
|
11
|
-
- Add proxy support [\#93](https://github.com/zaru/webpush/pull/93) ([Bugagazavr](https://github.com/Bugagazavr))
|
12
|
-
- fix syntax error [\#91](https://github.com/zaru/webpush/pull/91) ([tonytonyjan](https://github.com/tonytonyjan))
|
13
|
-
- change dependency gem versions [\#88](https://github.com/zaru/webpush/pull/88) ([zaru](https://github.com/zaru))
|
14
|
-
|
15
|
-
## [v1.0.0](https://github.com/zaru/webpush/tree/v1.0.0) (2019-08-15)
|
16
|
-
|
17
|
-
A stable version 1.0.0 has been released.
|
18
|
-
|
19
|
-
Thanks @mohamedhafez, @mplatov and @MedetaiAkaru for everything!
|
20
|
-
|
21
|
-
[Full Changelog](https://github.com/zaru/webpush/compare/v0.3.8...v1.0.0)
|
22
|
-
|
23
|
-
**Merged pull requests:**
|
24
|
-
|
25
|
-
- switch to aes128gcm encoding [\#84](https://github.com/zaru/webpush/pull/84) ([mohamedhafez](https://github.com/mohamedhafez))
|
26
|
-
- Fixed fcm spec [\#77](https://github.com/zaru/webpush/pull/77) ([zaru](https://github.com/zaru))
|
27
|
-
- add fcm endpoints [\#76](https://github.com/zaru/webpush/pull/76) ([MedetaiAkaru](https://github.com/MedetaiAkaru))
|
28
|
-
- Add Rubocop and fix [\#74](https://github.com/zaru/webpush/pull/74) ([zaru](https://github.com/zaru))
|
29
|
-
- Fix TravisCI bundler version [\#73](https://github.com/zaru/webpush/pull/73) ([zaru](https://github.com/zaru))
|
30
|
-
|
31
|
-
## [v0.3.8](https://github.com/zaru/webpush/tree/v0.3.8) (2019-04-16)
|
32
|
-
[Full Changelog](https://github.com/zaru/webpush/compare/v0.3.7...v0.3.8)
|
33
|
-
|
34
|
-
**Merged pull requests:**
|
35
|
-
|
36
|
-
- Fix authorization header [\#72](https://github.com/zaru/webpush/pull/72) ([xronos-i-am](https://github.com/xronos-i-am))
|
37
|
-
|
38
|
-
## [v0.3.7](https://github.com/zaru/webpush/tree/v0.3.7) (2019-03-06)
|
39
|
-
[Full Changelog](https://github.com/zaru/webpush/compare/v0.3.6...v0.3.7)
|
40
|
-
|
41
|
-
**Merged pull requests:**
|
42
|
-
|
43
|
-
- Add PEM support to import / export keys [\#65](https://github.com/zaru/webpush/pull/65) ([collimarco](https://github.com/collimarco))
|
44
|
-
|
45
|
-
## [v0.3.6](https://github.com/zaru/webpush/tree/v0.3.6) (2019-01-09)
|
46
|
-
[Full Changelog](https://github.com/zaru/webpush/compare/v0.3.5...v0.3.6)
|
47
|
-
|
48
|
-
**Merged pull requests:**
|
49
|
-
|
50
|
-
- Added a error class to arguments of raise\_error [\#62](https://github.com/zaru/webpush/pull/62) ([zaru](https://github.com/zaru))
|
51
|
-
- Fix TravisCI bundler version [\#61](https://github.com/zaru/webpush/pull/61) ([zaru](https://github.com/zaru))
|
52
|
-
- Raise Webpush::Unauthorized on HTTP 403 [\#59](https://github.com/zaru/webpush/pull/59) ([collimarco](https://github.com/collimarco))
|
53
|
-
|
54
|
-
## [v0.3.5](https://github.com/zaru/webpush/tree/v0.3.5) (2019-01-02)
|
55
|
-
[Full Changelog](https://github.com/zaru/webpush/compare/v0.3.4...v0.3.5)
|
56
|
-
|
57
|
-
**Merged pull requests:**
|
58
|
-
|
59
|
-
- Fix \#55 and \#51: raise the proper error based on the HTTP status code [\#58](https://github.com/zaru/webpush/pull/58) ([collimarco](https://github.com/collimarco))
|
60
|
-
- Add urgency option [\#57](https://github.com/zaru/webpush/pull/57) ([collimarco](https://github.com/collimarco))
|
61
|
-
- Add Rake task to generate VAPID keys [\#54](https://github.com/zaru/webpush/pull/54) ([stevenharman](https://github.com/stevenharman))
|
62
|
-
|
63
|
-
## [v0.3.4](https://github.com/zaru/webpush/tree/v0.3.4) (2018-05-25)
|
64
|
-
[Full Changelog](https://github.com/zaru/webpush/compare/v0.3.3...v0.3.4)
|
65
|
-
|
66
|
-
**Merged pull requests:**
|
67
|
-
|
68
|
-
- add http timeout options [\#50](https://github.com/zaru/webpush/pull/50) ([aishek](https://github.com/aishek))
|
69
|
-
|
70
|
-
## [v0.3.3](https://github.com/zaru/webpush/tree/v0.3.3) (2017-11-06)
|
71
|
-
[Full Changelog](https://github.com/zaru/webpush/compare/v0.3.2...v0.3.3)
|
72
|
-
|
73
|
-
**Merged pull requests:**
|
74
|
-
|
75
|
-
- Add typ to JWT header fields [\#46](https://github.com/zaru/webpush/pull/46) ([ykzts](https://github.com/ykzts))
|
76
|
-
- Specify the version of JWT strictly [\#45](https://github.com/zaru/webpush/pull/45) ([ykzts](https://github.com/ykzts))
|
77
|
-
|
78
|
-
## [v0.3.2](https://github.com/zaru/webpush/tree/v0.3.2) (2017-07-01)
|
79
|
-
[Full Changelog](https://github.com/zaru/webpush/compare/v0.3.1...v0.3.2)
|
80
|
-
|
81
|
-
**Merged pull requests:**
|
82
|
-
|
83
|
-
- feat: improve response error codes [\#39](https://github.com/zaru/webpush/pull/39) ([glennr](https://github.com/glennr))
|
84
|
-
- Update README.md [\#38](https://github.com/zaru/webpush/pull/38) ([kitaindia](https://github.com/kitaindia))
|
85
|
-
- Fix code example: Add close bracket [\#37](https://github.com/zaru/webpush/pull/37) ([kuranari](https://github.com/kuranari))
|
86
|
-
- fix code in README [\#36](https://github.com/zaru/webpush/pull/36) ([kuranari](https://github.com/kuranari))
|
87
|
-
- Minor fix in README: Close code blocks [\#32](https://github.com/zaru/webpush/pull/32) ([nicolas-fricke](https://github.com/nicolas-fricke))
|
88
|
-
- Copy edits for README clarifying GCM requirements [\#30](https://github.com/zaru/webpush/pull/30) ([rossta](https://github.com/rossta))
|
89
|
-
- Adding VAPID documentation [\#28](https://github.com/zaru/webpush/pull/28) ([rossta](https://github.com/rossta))
|
90
|
-
|
91
|
-
## [v0.3.1](https://github.com/zaru/webpush/tree/v0.3.1) (2016-10-24)
|
92
|
-
[Full Changelog](https://github.com/zaru/webpush/compare/v0.3.0...v0.3.1)
|
93
|
-
|
94
|
-
**Merged pull requests:**
|
95
|
-
|
96
|
-
- Bug fix invalid base64 [\#29](https://github.com/zaru/webpush/pull/29) ([rossta](https://github.com/rossta))
|
97
|
-
- Clarify VAPID usage further in README [\#27](https://github.com/zaru/webpush/pull/27) ([rossta](https://github.com/rossta))
|
98
|
-
|
99
|
-
## [v0.3.0](https://github.com/zaru/webpush/tree/v0.3.0) (2016-10-14)
|
100
|
-
[Full Changelog](https://github.com/zaru/webpush/compare/v0.2.5...v0.3.0)
|
101
|
-
|
102
|
-
**Merged pull requests:**
|
103
|
-
|
104
|
-
- Implement VAPID authorization [\#26](https://github.com/zaru/webpush/pull/26) ([rossta](https://github.com/rossta))
|
105
|
-
|
106
|
-
## [v0.2.5](https://github.com/zaru/webpush/tree/v0.2.5) (2016-09-14)
|
107
|
-
[Full Changelog](https://github.com/zaru/webpush/compare/v0.2.4...v0.2.5)
|
108
|
-
|
109
|
-
**Merged pull requests:**
|
110
|
-
|
111
|
-
- api key only needed for old google apis [\#24](https://github.com/zaru/webpush/pull/24) ([mohamedhafez](https://github.com/mohamedhafez))
|
112
|
-
|
113
|
-
## [v0.2.4](https://github.com/zaru/webpush/tree/v0.2.4) (2016-08-29)
|
114
|
-
[Full Changelog](https://github.com/zaru/webpush/compare/v0.2.3...v0.2.4)
|
115
|
-
|
116
|
-
**Merged pull requests:**
|
117
|
-
|
118
|
-
- VERIFY\_PEER by default - no need for a cert\_store option [\#20](https://github.com/zaru/webpush/pull/20) ([mohamedhafez](https://github.com/mohamedhafez))
|
119
|
-
|
120
|
-
## [v0.2.3](https://github.com/zaru/webpush/tree/v0.2.3) (2016-06-19)
|
121
|
-
[Full Changelog](https://github.com/zaru/webpush/compare/v0.2.2...v0.2.3)
|
122
|
-
|
123
|
-
**Merged pull requests:**
|
124
|
-
|
125
|
-
- detect and handle response errors [\#18](https://github.com/zaru/webpush/pull/18) ([mohamedhafez](https://github.com/mohamedhafez))
|
126
|
-
|
127
|
-
## [v0.2.2](https://github.com/zaru/webpush/tree/v0.2.2) (2016-06-13)
|
128
|
-
[Full Changelog](https://github.com/zaru/webpush/compare/v0.2.1...v0.2.2)
|
129
|
-
|
130
|
-
**Merged pull requests:**
|
131
|
-
|
132
|
-
- Don't include API key for firefox or other browsers [\#16](https://github.com/zaru/webpush/pull/16) ([mohamedhafez](https://github.com/mohamedhafez))
|
133
|
-
- Option to specify a cert store [\#15](https://github.com/zaru/webpush/pull/15) ([mohamedhafez](https://github.com/mohamedhafez))
|
134
|
-
- show ttl option in README [\#14](https://github.com/zaru/webpush/pull/14) ([mohamedhafez](https://github.com/mohamedhafez))
|
135
|
-
|
136
|
-
## [v0.2.1](https://github.com/zaru/webpush/tree/v0.2.1) (2016-05-23)
|
137
|
-
[Full Changelog](https://github.com/zaru/webpush/compare/v0.2.0...v0.2.1)
|
138
|
-
|
139
|
-
**Merged pull requests:**
|
140
|
-
|
141
|
-
- Make the response more detailed. [\#10](https://github.com/zaru/webpush/pull/10) ([kevinjom](https://github.com/kevinjom))
|
142
|
-
|
143
|
-
## [v0.2.0](https://github.com/zaru/webpush/tree/v0.2.0) (2016-05-16)
|
144
|
-
[Full Changelog](https://github.com/zaru/webpush/compare/v0.1.6...v0.2.0)
|
145
|
-
|
146
|
-
**Merged pull requests:**
|
147
|
-
|
148
|
-
- Make message payload optional [\#8](https://github.com/zaru/webpush/pull/8) ([rossta](https://github.com/rossta))
|
149
|
-
- Add specs [\#7](https://github.com/zaru/webpush/pull/7) ([rossta](https://github.com/rossta))
|
150
|
-
|
151
|
-
## [v0.1.6](https://github.com/zaru/webpush/tree/v0.1.6) (2016-05-12)
|
152
|
-
[Full Changelog](https://github.com/zaru/webpush/compare/v0.1.5...v0.1.6)
|
153
|
-
|
154
|
-
**Merged pull requests:**
|
155
|
-
|
156
|
-
- Add rake binstub [\#6](https://github.com/zaru/webpush/pull/6) ([rossta](https://github.com/rossta))
|
157
|
-
- Add syntax highlighting to README snippets [\#5](https://github.com/zaru/webpush/pull/5) ([rossta](https://github.com/rossta))
|
158
|
-
- Extract encryption module [\#4](https://github.com/zaru/webpush/pull/4) ([rossta](https://github.com/rossta))
|
159
|
-
- Add some happy case specs [\#3](https://github.com/zaru/webpush/pull/3) ([waheedel](https://github.com/waheedel))
|
160
|
-
|
161
|
-
## [v0.1.5](https://github.com/zaru/webpush/tree/v0.1.5) (2016-04-29)
|
162
|
-
[Full Changelog](https://github.com/zaru/webpush/compare/v0.1.4...v0.1.5)
|
163
|
-
|
164
|
-
**Merged pull requests:**
|
165
|
-
|
166
|
-
- add Ttl header parameter [\#1](https://github.com/zaru/webpush/pull/1) ([shouta-dev](https://github.com/shouta-dev))
|
167
|
-
|
168
|
-
## [v0.1.4](https://github.com/zaru/webpush/tree/v0.1.4) (2016-04-27)
|
169
|
-
[Full Changelog](https://github.com/zaru/webpush/compare/v0.1.3...v0.1.4)
|
170
|
-
|
171
|
-
## [v0.1.3](https://github.com/zaru/webpush/tree/v0.1.3) (2016-04-13)
|
172
|
-
[Full Changelog](https://github.com/zaru/webpush/compare/v0.1.2...v0.1.3)
|
173
|
-
|
174
|
-
## [v0.1.2](https://github.com/zaru/webpush/tree/v0.1.2) (2016-04-12)
|
175
|
-
[Full Changelog](https://github.com/zaru/webpush/compare/v0.1.1...v0.1.2)
|
176
|
-
|
177
|
-
## [v0.1.1](https://github.com/zaru/webpush/tree/v0.1.1) (2016-03-31)
|
178
|
-
[Full Changelog](https://github.com/zaru/webpush/compare/v0.1.0...v0.1.1)
|
179
|
-
|
180
|
-
## [v0.1.0](https://github.com/zaru/webpush/tree/v0.1.0) (2016-03-31)
|
181
|
-
|
182
|
-
|
183
|
-
\* *This Change Log was automatically generated by [github_changelog_generator](https://github.com/skywinder/Github-Changelog-Generator)*
|
data/Rakefile
DELETED
data/bin/console
DELETED
@@ -1,14 +0,0 @@
|
|
1
|
-
#!/usr/bin/env ruby
|
2
|
-
|
3
|
-
require "bundler/setup"
|
4
|
-
require "web_push"
|
5
|
-
|
6
|
-
# You can add fixtures and/or initialization code here to make experimenting
|
7
|
-
# with your gem easier. You can also use a different console, if you like.
|
8
|
-
|
9
|
-
# (If you use this, don't forget to add pry to your Gemfile!)
|
10
|
-
# require "pry"
|
11
|
-
# Pry.start
|
12
|
-
|
13
|
-
require "irb"
|
14
|
-
IRB.start
|
data/bin/rake
DELETED
@@ -1,16 +0,0 @@
|
|
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/bin/rspec
DELETED
@@ -1,16 +0,0 @@
|
|
1
|
-
#!/usr/bin/env ruby
|
2
|
-
#
|
3
|
-
# This file was generated by Bundler.
|
4
|
-
#
|
5
|
-
# The application 'rspec' 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("rspec-core", "rspec")
|
data/bin/setup
DELETED
data/lib/tasks/web_push.rake
DELETED
@@ -1,14 +0,0 @@
|
|
1
|
-
namespace :web_push do
|
2
|
-
desc 'Generate VAPID public/private key pair'
|
3
|
-
task :generate_keys do
|
4
|
-
require 'web_push'
|
5
|
-
|
6
|
-
WebPush.generate_key.tap do |keypair|
|
7
|
-
puts <<-KEYS
|
8
|
-
Generated VAPID keypair:
|
9
|
-
Public -> #{keypair.public_key}
|
10
|
-
Private -> #{keypair.private_key}
|
11
|
-
KEYS
|
12
|
-
end
|
13
|
-
end
|
14
|
-
end
|