webpush 0.3.1 → 0.3.2
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 +4 -4
- data/README.md +33 -11
- data/lib/webpush.rb +4 -2
- data/lib/webpush/errors.rb +15 -1
- data/lib/webpush/request.rb +9 -3
- data/lib/webpush/vapid_key.rb +18 -9
- data/lib/webpush/version.rb +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 94a1cc5374ad048519b130a97e805a863f682636
|
4
|
+
data.tar.gz: 43fda03427649b0fe51fd091859fe6cb32a9104a
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 8e0efe569336570bce2edaf163f22d7fcfb7cfa3dcf6583297d062971d0ea338e58f1545a003f6cabea25243a739d61efa1c129db0d67ab07ec1908f9b612f1f
|
7
|
+
data.tar.gz: edbd2f55346dd918927ee512a4d8097641f934abc4df89f2598ee655650ccefe30eefda863207b319f574f0f7e441af36791b265023757c44fe424ce47f3111f
|
data/README.md
CHANGED
@@ -28,12 +28,11 @@ Or install it yourself as:
|
|
28
28
|
|
29
29
|
Sending a web push message to a visitor of your website requires a number of steps:
|
30
30
|
|
31
|
-
1. Your server has (optionally) generated (one-time) a set of [Voluntary Application server Identification (VAPID)](https://tools.ietf.org/html/draft-ietf-webpush-vapid-01) keys.
|
32
|
-
2.
|
33
|
-
3.
|
34
|
-
|
35
|
-
|
36
|
-
7. 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.
|
31
|
+
1. Your server has (optionally) generated (one-time) a set of [Voluntary Application server Identification (VAPID)](https://tools.ietf.org/html/draft-ietf-webpush-vapid-01) keys. Otherwise, to send messages through Chrome, you have registered your site through the [Google Developer Console](https://console.developers.google.com/) and have obtained a GCM sender id and GCM API key from your app settings.
|
32
|
+
2. A `manifest.json` file, linked from your user's page, identifies your app settings.
|
33
|
+
3. Also 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, with creates a `subscription` JSON object on the client side.
|
34
|
+
4. Your server uses the `webpush` gem to send a notification with the `subscription` obtained from the client and an optional payload (the message).
|
35
|
+
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.
|
37
36
|
|
38
37
|
### Generating VAPID keys
|
39
38
|
|
@@ -50,7 +49,14 @@ vapid_key.private_key
|
|
50
49
|
|
51
50
|
### Declaring manifest.json
|
52
51
|
|
53
|
-
|
52
|
+
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.
|
53
|
+
|
54
|
+
```javascript
|
55
|
+
{
|
56
|
+
"name": "My Website"
|
57
|
+
}
|
58
|
+
```
|
59
|
+
For Chrome web push, add the GCM sender id to a `manifest.json`.
|
54
60
|
|
55
61
|
```javascript
|
56
62
|
{
|
@@ -59,7 +65,7 @@ For Chrome web push, add the GCM sender id to a `manifest.json` file served at t
|
|
59
65
|
}
|
60
66
|
```
|
61
67
|
|
62
|
-
|
68
|
+
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:
|
63
69
|
|
64
70
|
```html
|
65
71
|
<!-- index.html -->
|
@@ -141,6 +147,7 @@ $(".webpush-button").on("click", (e) => {
|
|
141
147
|
.then((subscription) => {
|
142
148
|
$.post("/push", { subscription: subscription.toJSON(), message: "You clicked a button!" });
|
143
149
|
});
|
150
|
+
});
|
144
151
|
});
|
145
152
|
```
|
146
153
|
|
@@ -152,10 +159,10 @@ Imagine a Ruby app endpoint that responds to the request by triggering notificat
|
|
152
159
|
# the message, subscription values, and vapid options
|
153
160
|
post "/push" do
|
154
161
|
Webpush.payload_send(
|
155
|
-
message: params[:message]
|
162
|
+
message: params[:message],
|
156
163
|
endpoint: params[:subscription][:endpoint],
|
157
164
|
p256dh: params[:subscription][:keys][:p256dh],
|
158
|
-
auth: params[:subscription][:keys][:
|
165
|
+
auth: params[:subscription][:keys][:auth],
|
159
166
|
vapid: {
|
160
167
|
subject: "mailto:sender@example.com",
|
161
168
|
public_key: ENV['VAPID_PUBLIC_KEY'],
|
@@ -166,7 +173,9 @@ end
|
|
166
173
|
```
|
167
174
|
|
168
175
|
Note: the VAPID options should be omitted if the client-side subscription was
|
169
|
-
generated without the `applicationServerKey` parameter described earlier.
|
176
|
+
generated without the `applicationServerKey` parameter described earlier. You
|
177
|
+
would instead pass the GCM api key along with the api request as shown in the
|
178
|
+
Usage section below.
|
170
179
|
|
171
180
|
### Receiving the push event
|
172
181
|
|
@@ -266,6 +275,19 @@ Webpush.payload_send(
|
|
266
275
|
private_key: ENV['VAPID_PRIVATE_KEY']
|
267
276
|
}
|
268
277
|
)
|
278
|
+
```
|
279
|
+
|
280
|
+
### With GCM api key
|
281
|
+
|
282
|
+
```ruby
|
283
|
+
Webpush.payload_send(
|
284
|
+
endpoint: "https://fcm.googleapis.com/gcm/send/eah7hak....",
|
285
|
+
message: "A message",
|
286
|
+
p256dh: "BO/aG9nYXNkZmFkc2ZmZHNmYWRzZmFl...",
|
287
|
+
auth: "aW1hcmthcmFpa3V6ZQ==",
|
288
|
+
api_key: "<GCM API KEY>"
|
289
|
+
)
|
290
|
+
```
|
269
291
|
|
270
292
|
### ServiceWorker sample
|
271
293
|
|
data/lib/webpush.rb
CHANGED
@@ -42,8 +42,10 @@ module Webpush
|
|
42
42
|
).perform
|
43
43
|
end
|
44
44
|
|
45
|
-
#
|
46
|
-
#
|
45
|
+
# Generate a VapidKey instance to obtain base64 encoded public and private keys
|
46
|
+
# suitable for VAPID protocol JSON web token signing
|
47
|
+
#
|
48
|
+
# @return [Webpush::VapidKey] a new VapidKey instance
|
47
49
|
def generate_key
|
48
50
|
VapidKey.new
|
49
51
|
end
|
data/lib/webpush/errors.rb
CHANGED
@@ -3,7 +3,21 @@ module Webpush
|
|
3
3
|
|
4
4
|
class ConfigurationError < Error; end
|
5
5
|
|
6
|
-
class ResponseError < Error;
|
6
|
+
class ResponseError < Error;
|
7
|
+
attr_reader :response, :host
|
8
|
+
|
9
|
+
def initialize(response, host)
|
10
|
+
@response = response
|
11
|
+
@host = host
|
12
|
+
super "host: #{host}, #{@response.inspect}\nbody:\n#{@response.body}"
|
13
|
+
end
|
14
|
+
end
|
7
15
|
|
8
16
|
class InvalidSubscription < ResponseError; end
|
17
|
+
|
18
|
+
class ExpiredSubscription < ResponseError; end
|
19
|
+
|
20
|
+
class PayloadTooLarge < ResponseError; end
|
21
|
+
|
22
|
+
class TooManyRequests < ResponseError; end
|
9
23
|
end
|
data/lib/webpush/request.rb
CHANGED
@@ -24,9 +24,15 @@ module Webpush
|
|
24
24
|
|
25
25
|
if resp.is_a?(Net::HTTPGone) || #Firefox unsubscribed response
|
26
26
|
(resp.is_a?(Net::HTTPBadRequest) && resp.message == "UnauthorizedRegistration") #Chrome unsubscribed response
|
27
|
-
raise InvalidSubscription.new(resp.
|
28
|
-
elsif
|
29
|
-
raise
|
27
|
+
raise InvalidSubscription.new(resp, uri.host)
|
28
|
+
elsif resp.is_a?(Net::HTTPNotFound) # 404
|
29
|
+
raise ExpiredSubscription.new(resp, uri.host)
|
30
|
+
elsif resp.is_a?(Net::HTTPRequestEntityTooLarge) # 413
|
31
|
+
raise PayloadTooLarge.new(resp, uri.host)
|
32
|
+
elsif resp.is_a?(Net::HTTPTooManyRequests) # 429, try again later!
|
33
|
+
raise TooManyRequests.new(resp, uri.host)
|
34
|
+
elsif !resp.is_a?(Net::HTTPSuccess) # unknown/unhandled response error
|
35
|
+
raise ResponseError.new(resp, uri.host)
|
30
36
|
end
|
31
37
|
|
32
38
|
resp
|
data/lib/webpush/vapid_key.rb
CHANGED
@@ -1,5 +1,11 @@
|
|
1
1
|
module Webpush
|
2
|
+
# Class for abstracting the generation and encoding of elliptic curve public and private keys for use with the VAPID protocol
|
3
|
+
#
|
4
|
+
# @attr_reader [OpenSSL::PKey::EC] :curve the OpenSSL elliptic curve instance
|
2
5
|
class VapidKey
|
6
|
+
# Create a VapidKey instance from encoded elliptic curve public and private keys
|
7
|
+
#
|
8
|
+
# @return [Webpush::VapidKey] a VapidKey instance for the given public and private keys
|
3
9
|
def self.from_keys(public_key, private_key)
|
4
10
|
key = new
|
5
11
|
key.public_key = public_key
|
@@ -15,30 +21,33 @@ module Webpush
|
|
15
21
|
@curve.generate_key
|
16
22
|
end
|
17
23
|
|
18
|
-
# Retrieve the encoded
|
19
|
-
#
|
24
|
+
# Retrieve the encoded elliptic curve public key for VAPID protocol
|
25
|
+
#
|
26
|
+
# @return [String] encoded binary representation of 65-byte VAPID public key
|
20
27
|
def public_key
|
21
28
|
encode64(curve.public_key.to_bn.to_s(2))
|
22
29
|
end
|
23
30
|
|
24
|
-
# Retrieve
|
25
|
-
#
|
31
|
+
# Retrieve the encoded elliptic curve public key suitable for the Web Push request
|
32
|
+
#
|
33
|
+
# @return [String] the encoded VAPID public key for us in 'Encryption' header
|
26
34
|
def public_key_for_push_header
|
27
35
|
trim_encode64(curve.public_key.to_bn.to_s(2))
|
28
36
|
end
|
29
37
|
|
30
|
-
#
|
31
|
-
#
|
38
|
+
# Retrive the encoded elliptic curve private key for VAPID protocol
|
39
|
+
#
|
40
|
+
# @return [String] base64 urlsafe-encoded binary representation of 32-byte VAPID private key
|
32
41
|
def private_key
|
33
|
-
|
42
|
+
encode64(curve.private_key.to_s(2))
|
34
43
|
end
|
35
44
|
|
36
45
|
def public_key=(key)
|
37
|
-
|
46
|
+
curve.public_key = OpenSSL::PKey::EC::Point.new(group, to_big_num(key))
|
38
47
|
end
|
39
48
|
|
40
49
|
def private_key=(key)
|
41
|
-
|
50
|
+
curve.private_key = to_big_num(key)
|
42
51
|
end
|
43
52
|
|
44
53
|
def curve_name
|
data/lib/webpush/version.rb
CHANGED
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.3.
|
4
|
+
version: 0.3.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- zaru@sakuraba
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2017-07-01 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: hkdf
|