Class: WebPush
- Inherits:
-
Object
- Object
- WebPush
- Defined in:
- lib/web_push.rb,
lib/web_push/version.rb
Defined Under Namespace
Modules: Utils
Constant Summary collapse
- GROUP_NAME =
'prime256v1'- DEFAULT_TTL =
4 weeks
60 * 60 * 24 * 7 * 4
- DEFAULT_EXP =
1 day
60 * 60 * 24
- VERSION =
"0.1.2"
Instance Method Summary collapse
- #encrypt(p256dh, auth, payload) ⇒ Object
- #generate_http_request(payload) ⇒ Object
- #generate_vapid_headers(audience, sub: @vapid_subject, exp: @exp) ⇒ Object
- #generate_vapid_pkey(public_key, private_key) ⇒ Object
-
#initialize(subscription, ttl: DEFAULT_TTL, exp: DEFAULT_EXP) ⇒ WebPush
constructor
A new instance of WebPush.
- #send_notification(payload) ⇒ Object
- #set_vapid_details(subject, public_key, private_key) ⇒ Object
- #urlsafe_decode64(bin) ⇒ Object
- #urlsafe_encode64(bin) ⇒ Object
Constructor Details
#initialize(subscription, ttl: DEFAULT_TTL, exp: DEFAULT_EXP) ⇒ WebPush
Returns a new instance of WebPush.
26 27 28 29 30 31 32 33 |
# File 'lib/web_push.rb', line 26 def initialize(subscription, ttl: DEFAULT_TTL, exp: DEFAULT_EXP) @subscription = subscription @endpoint = @subscription[:endpoint] @p256dh = @subscription[:keys][:p256dh] @auth = @subscription[:keys][:auth] @ttl = ttl @exp = exp end |
Instance Method Details
#encrypt(p256dh, auth, payload) ⇒ Object
72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 |
# File 'lib/web_push.rb', line 72 def encrypt(p256dh, auth, payload) user_public_key = urlsafe_decode64 p256dh user_auth = urlsafe_decode64 auth local_curve = Utils.generate_vapid_pkey user_public_key_point = OpenSSL::PKey::EC::Point.new(local_curve.group, OpenSSL::BN.new(user_public_key, 2)) key = local_curve.dh_compute_key(user_public_key_point) server_public_key = local_curve.public_key.to_bn.to_s(2) params = { key: key, salt: SecureRandom.random_bytes(16), server_public_key: server_public_key, user_public_key: user_public_key, auth: user_auth } params[:cipher] = ECE.encrypt(payload, params) params end |
#generate_http_request(payload) ⇒ Object
48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 |
# File 'lib/web_push.rb', line 48 def generate_http_request(payload) { method: 'POST', headers: { 'TTL' => @ttl.to_s, 'Content-Type' => 'application/octet-stream', 'Content-Encoding' => 'aesgcm', }, body: nil, uri: URI(@endpoint), }.tap do |request| encrypted = encrypt(@p256dh, @auth, payload) request[:headers]['Content-Length'] = encrypted[:cipher].bytesize.to_s request[:headers]['Encryption'] = 'salt=' + urlsafe_encode64(encrypted[:salt]) request[:headers]['Crypto-Key'] = 'dh=' + urlsafe_encode64(encrypted[:server_public_key]) request[:body] = encrypted[:cipher] audience = request[:uri].scheme + "://" + request[:uri].host vapid_headers = generate_vapid_headers audience request[:headers]['Authorization'] = vapid_headers['Authorization'] request[:headers]['Crypto-Key'] += ';' + vapid_headers['Crypto-Key'] end end |
#generate_vapid_headers(audience, sub: @vapid_subject, exp: @exp) ⇒ Object
94 95 96 97 98 99 100 101 102 103 104 |
# File 'lib/web_push.rb', line 94 def generate_vapid_headers(audience, sub: @vapid_subject, exp: @exp) jwt = JWT.encode({ aud: audience, exp: Time.now.to_i + exp, sub: sub, }, @vapid_pkey, 'ES256') { 'Authorization' => 'WebPush ' + jwt, 'Crypto-Key' => 'p256ecdsa=' + urlsafe_encode64(@vapid_public_key_bn), } end |
#generate_vapid_pkey(public_key, private_key) ⇒ Object
114 115 116 117 118 119 120 121 122 123 |
# File 'lib/web_push.rb', line 114 def generate_vapid_pkey(public_key, private_key) pvtbn = OpenSSL::BN.new(urlsafe_decode64(private_key), 2) pubbn = OpenSSL::BN.new(urlsafe_decode64(public_key), 2) pkey = Utils.generate_vapid_pkey pkey.private_key = pvtbn pkey.public_key = OpenSSL::PKey::EC::Point.new(pkey.group, pubbn) pkey end |
#send_notification(payload) ⇒ Object
35 36 37 38 39 40 41 42 43 44 45 46 |
# File 'lib/web_push.rb', line 35 def send_notification(payload) params = generate_http_request(payload) uri = params[:uri] https = Net::HTTP.new uri.host, uri.port https.use_ssl = true request = Net::HTTP::Post.new uri.request_uri, params[:headers] request.body = params[:body] https.request request end |
#set_vapid_details(subject, public_key, private_key) ⇒ Object
106 107 108 109 110 111 112 |
# File 'lib/web_push.rb', line 106 def set_vapid_details(subject, public_key, private_key) @vapid_subject = subject @vapid_public_key = public_key @vapid_private_key = private_key @vapid_pkey = generate_vapid_pkey(@vapid_public_key, @vapid_private_key) @vapid_public_key_bn = @vapid_pkey.public_key.to_bn.to_s(2) end |
#urlsafe_decode64(bin) ⇒ Object
129 130 131 132 133 134 135 136 |
# File 'lib/web_push.rb', line 129 def urlsafe_decode64(bin) # take from ruby v2.3.3 base64.rb if !bin.end_with?("=") && bin.length % 4 != 0 Base64.urlsafe_decode64 bin.ljust((bin.length + 3) & ~3, "=") else Base64.urlsafe_decode64 bin end end |
#urlsafe_encode64(bin) ⇒ Object
125 126 127 |
# File 'lib/web_push.rb', line 125 def urlsafe_encode64(bin) Base64.urlsafe_encode64(bin).delete('=') end |