web-push 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +10 -0
- data/.rspec +2 -0
- data/.rubocop.yml +30 -0
- data/.travis.yml +24 -0
- data/CHANGELOG.md +183 -0
- data/Gemfile +4 -0
- data/LICENSE +21 -0
- data/README.md +356 -0
- data/Rakefile +8 -0
- data/bin/console +14 -0
- data/bin/rake +16 -0
- data/bin/rspec +16 -0
- data/bin/setup +8 -0
- data/lib/tasks/web_push.rake +14 -0
- data/lib/web-push.rb +3 -0
- data/lib/web_push/encryption.rb +77 -0
- data/lib/web_push/errors.rb +29 -0
- data/lib/web_push/railtie.rb +9 -0
- data/lib/web_push/request.rb +189 -0
- data/lib/web_push/vapid_key.rb +105 -0
- data/lib/web_push/version.rb +5 -0
- data/lib/web_push.rb +80 -0
- data/spec/spec_helper.rb +23 -0
- data/spec/web_push/encryption_spec.rb +95 -0
- data/spec/web_push/request_spec.rb +162 -0
- data/spec/web_push/vapid_key_spec.rb +66 -0
- data/spec/web_push_spec.rb +253 -0
- data/web-push.gemspec +25 -0
- metadata +183 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: a165b29c06bb5d9a9aab0b65de25bd913ef7926909773485e97f0778bda4299d
|
4
|
+
data.tar.gz: c3f9727392a4049e27ac6bf83718749d5110cd290fa37718ee5b988d2c9c16e3
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: ca5db1201aa140ed1abe235d217183270b8b171d8b368ea7b5392c9cb04a2bf923c1c0e468788e1c2846dbd5c38bc32af53d427dbf307193ccaa00efbf6dd7d6
|
7
|
+
data.tar.gz: 8f179fd84cc0bd0f9e4899353d95af62e9e716552ae0bec86cdc7be2782056fcfb08b06a7efd3297e7468f1bb72ab6f5b16a29e31fc5ed0eb615117e790b8885
|
data/.gitignore
ADDED
data/.rspec
ADDED
data/.rubocop.yml
ADDED
@@ -0,0 +1,30 @@
|
|
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
ADDED
@@ -0,0 +1,24 @@
|
|
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
ADDED
@@ -0,0 +1,183 @@
|
|
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/Gemfile
ADDED
data/LICENSE
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
Copyright (c) 2016 Hiroyuki Sakuraba
|
2
|
+
Copyright (c) 2022 Marco Colli, Pushpad (https://pushpad.xyz)
|
3
|
+
|
4
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
5
|
+
a copy of this software and associated documentation files (the
|
6
|
+
"Software"), to deal in the Software without restriction, including
|
7
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
8
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
9
|
+
permit persons to whom the Software is furnished to do so, subject to
|
10
|
+
the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be
|
13
|
+
included in all copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
16
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
17
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
18
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
19
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
20
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
21
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,356 @@
|
|
1
|
+
# WebPush
|
2
|
+
|
3
|
+
[![Code Climate](https://codeclimate.com/github/zaru/webpush/badges/gpa.svg)](https://codeclimate.com/github/zaru/webpush)
|
4
|
+
[![Test Coverage](https://codeclimate.com/github/zaru/webpush/badges/coverage.svg)](https://codeclimate.com/github/zaru/webpush/coverage)
|
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)
|
7
|
+
|
8
|
+
This gem makes it possible to send push messages to web browsers from Ruby backends using the [Web Push Protocol](https://tools.ietf.org/html/draft-ietf-webpush-protocol-10). It supports [Message Encryption for Web Push](https://tools.ietf.org/html/draft-ietf-webpush-encryption) to send messages securely from server to user agent.
|
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)
|
13
|
+
|
14
|
+
## Installation
|
15
|
+
|
16
|
+
Add this line to your application's Gemfile:
|
17
|
+
|
18
|
+
```ruby
|
19
|
+
gem 'web-push'
|
20
|
+
```
|
21
|
+
|
22
|
+
And then execute:
|
23
|
+
|
24
|
+
$ bundle
|
25
|
+
|
26
|
+
Or install it yourself as:
|
27
|
+
|
28
|
+
$ gem install web-push
|
29
|
+
|
30
|
+
## Usage
|
31
|
+
|
32
|
+
Sending a web push message to a visitor of your website requires a number of steps:
|
33
|
+
|
34
|
+
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.
|
35
|
+
2. A `manifest.json` file, linked from your user's page, identifies your app settings.
|
36
|
+
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.
|
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.
|
39
|
+
|
40
|
+
### Generating VAPID keys
|
41
|
+
|
42
|
+
Use `web-push` to generate a VAPID key that has both a `public_key` and `private_key` attribute to be saved on the server side.
|
43
|
+
|
44
|
+
```ruby
|
45
|
+
# One-time, on the server
|
46
|
+
vapid_key = WebPush.generate_key
|
47
|
+
|
48
|
+
# Save these in your application server settings
|
49
|
+
vapid_key.public_key
|
50
|
+
vapid_key.private_key
|
51
|
+
|
52
|
+
# Or you can save in PEM format if you prefer
|
53
|
+
vapid_key.to_pem
|
54
|
+
```
|
55
|
+
|
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
|
+
### Installing a service worker
|
82
|
+
|
83
|
+
Your application javascript must register a service worker script at an appropriate scope (we're sticking with the root).
|
84
|
+
|
85
|
+
```javascript
|
86
|
+
// application.js
|
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
|
+
}
|
98
|
+
```
|
99
|
+
|
100
|
+
### Subscribing to push notifications
|
101
|
+
|
102
|
+
#### With VAPID
|
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).
|
105
|
+
|
106
|
+
```javascript
|
107
|
+
window.vapidPublicKey = new Uint8Array(<%= Base64.urlsafe_decode64(ENV['VAPID_PUBLIC_KEY']).bytes %>);
|
108
|
+
```
|
109
|
+
|
110
|
+
Your application javascript uses the `navigator.serviceWorker.pushManager` to subscribe to push notifications, passing the VAPID public key to the subscription settings.
|
111
|
+
|
112
|
+
```javascript
|
113
|
+
// application.js
|
114
|
+
// When serviceWorker is supported, installed, and activated,
|
115
|
+
// subscribe the pushManager property with the vapidPublicKey
|
116
|
+
navigator.serviceWorker.ready.then((serviceWorkerRegistration) => {
|
117
|
+
serviceWorkerRegistration.pushManager
|
118
|
+
.subscribe({
|
119
|
+
userVisibleOnly: true,
|
120
|
+
applicationServerKey: window.vapidPublicKey
|
121
|
+
});
|
122
|
+
});
|
123
|
+
```
|
124
|
+
|
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
|
+
### Triggering a web push notification
|
142
|
+
|
143
|
+
Hook into an client-side or backend event in your app to deliver a push message. The server must be made aware of the `subscription`. In the example below, we send the JSON generated subscription object to our backend at the "/push" endpoint with a message.
|
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
|
+
```
|
159
|
+
|
160
|
+
Imagine a Ruby app endpoint that responds to the request by triggering notification through the `web-push` gem.
|
161
|
+
|
162
|
+
```ruby
|
163
|
+
# app.rb
|
164
|
+
# Use the web-push gem API to deliver a push notiifcation merging
|
165
|
+
# the message, subscription values, and vapid options
|
166
|
+
post "/push" do
|
167
|
+
WebPush.payload_send(
|
168
|
+
message: params[:message],
|
169
|
+
endpoint: params[:subscription][:endpoint],
|
170
|
+
p256dh: params[:subscription][:keys][:p256dh],
|
171
|
+
auth: params[:subscription][:keys][:auth],
|
172
|
+
vapid: {
|
173
|
+
subject: "mailto:sender@example.com",
|
174
|
+
public_key: ENV['VAPID_PUBLIC_KEY'],
|
175
|
+
private_key: ENV['VAPID_PRIVATE_KEY']
|
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
|
182
|
+
```
|
183
|
+
|
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
|
+
### Receiving the push event
|
190
|
+
|
191
|
+
Your `/serviceworker.js` script may respond to `'push'` events. One action it can take is to trigger desktop notifications by calling `showNotification` on the `registration` property.
|
192
|
+
|
193
|
+
```javascript
|
194
|
+
// serviceworker.js
|
195
|
+
// The serviceworker context can respond to 'push' events and trigger
|
196
|
+
// notifications on the registration property
|
197
|
+
self.addEventListener("push", (event) => {
|
198
|
+
let title = (event.data && event.data.text()) || "Yay a message";
|
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
|
+
)
|
206
|
+
});
|
207
|
+
```
|
208
|
+
|
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, using something like the example below.
|
210
|
+
|
211
|
+
```javascript
|
212
|
+
// application.js
|
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
|
+
}
|
233
|
+
```
|
234
|
+
|
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.
|
239
|
+
|
240
|
+
## API
|
241
|
+
|
242
|
+
### With a payload
|
243
|
+
|
244
|
+
```ruby
|
245
|
+
message = {
|
246
|
+
title: "title",
|
247
|
+
body: "body",
|
248
|
+
icon: "http://example.com/icon.pn"
|
249
|
+
}
|
250
|
+
|
251
|
+
WebPush.payload_send(
|
252
|
+
endpoint: "https://fcm.googleapis.com/gcm/send/eah7hak....",
|
253
|
+
message: JSON.generate(message),
|
254
|
+
p256dh: "BO/aG9nYXNkZmFkc2ZmZHNmYWRzZmFl...",
|
255
|
+
auth: "aW1hcmthcmFpa3V6ZQ==",
|
256
|
+
ttl: 600, # optional, ttl in seconds, defaults to 2419200 (4 weeks)
|
257
|
+
urgency: 'normal' # optional, it can be very-low, low, normal, high, defaults to normal
|
258
|
+
)
|
259
|
+
```
|
260
|
+
|
261
|
+
### Without a payload
|
262
|
+
|
263
|
+
```ruby
|
264
|
+
WebPush.payload_send(
|
265
|
+
endpoint: "https://fcm.googleapis.com/gcm/send/eah7hak....",
|
266
|
+
p256dh: "BO/aG9nYXNkZmFkc2ZmZHNmYWRzZmFl...",
|
267
|
+
auth: "aW1hcmthcmFpa3V6ZQ=="
|
268
|
+
)
|
269
|
+
```
|
270
|
+
|
271
|
+
### With VAPID
|
272
|
+
|
273
|
+
VAPID details are given as a hash with `:subject`, `:public_key`, and
|
274
|
+
`:private_key`. The `:subject` is a contact URI for the application server as either a "mailto:" or an "https:" address. The `:public_key` and `:private_key` should be passed as the base64-encoded values generated with `WebPush.generate_key`.
|
275
|
+
|
276
|
+
```ruby
|
277
|
+
WebPush.payload_send(
|
278
|
+
endpoint: "https://fcm.googleapis.com/gcm/send/eah7hak....",
|
279
|
+
message: "A message",
|
280
|
+
p256dh: "BO/aG9nYXNkZmFkc2ZmZHNmYWRzZmFl...",
|
281
|
+
auth: "aW1hcmthcmFpa3V6ZQ==",
|
282
|
+
vapid: {
|
283
|
+
subject: "mailto:sender@example.com",
|
284
|
+
public_key: ENV['VAPID_PUBLIC_KEY'],
|
285
|
+
private_key: ENV['VAPID_PRIVATE_KEY']
|
286
|
+
}
|
287
|
+
)
|
288
|
+
```
|
289
|
+
|
290
|
+
### With VAPID in PEM format
|
291
|
+
|
292
|
+
This library also supports the PEM format for the VAPID keys:
|
293
|
+
|
294
|
+
```ruby
|
295
|
+
WebPush.payload_send(
|
296
|
+
endpoint: "https://fcm.googleapis.com/gcm/send/eah7hak....",
|
297
|
+
message: "A message",
|
298
|
+
p256dh: "BO/aG9nYXNkZmFkc2ZmZHNmYWRzZmFl...",
|
299
|
+
auth: "aW1hcmthcmFpa3V6ZQ==",
|
300
|
+
vapid: {
|
301
|
+
subject: "mailto:sender@example.com"
|
302
|
+
pem: ENV['VAPID_KEYS']
|
303
|
+
}
|
304
|
+
)
|
305
|
+
```
|
306
|
+
|
307
|
+
### With GCM api key
|
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
|
+
```
|
341
|
+
|
342
|
+
payloads received sample code.
|
343
|
+
|
344
|
+
```javascript
|
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
|
355
|
+
|
356
|
+
Bug reports and pull requests are welcome on GitHub at https://github.com/zaru/webpush.
|
data/Rakefile
ADDED
data/bin/console
ADDED
@@ -0,0 +1,14 @@
|
|
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
|