-
Notifications
You must be signed in to change notification settings - Fork 75
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Implement VAPID authorization #26
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Tried to help by looking at a few issues I ran into implementing similar functionality.
One other note is that if these changes are taken, the README and example should be updated to reflect the need to .subscribe({}) with the server's public key and to pass the same public/private key into the VAPID stuff added here
headers["Encryption"] = "salt=#{salt_param}" | ||
headers["Crypto-Key"] = "dh=#{dh_param}" | ||
headers["Encryption"] = "keyid=p256dh;salt=#{salt_param}" | ||
headers["Crypto-Key"] = "keyid=p256dh;dh=#{dh_param}" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
keyid is no longer needed here
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks, removed!
headers["Crypto-Key"] = [ | ||
headers["Crypto-Key"], | ||
vapid_headers["Crypto-Key"] | ||
].compact.join(";") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Word is the ';' join was a bug in Chrome 52, should be using ',' here now I think :-?
@@ -36,17 +44,26 @@ def headers | |||
headers["Content-Type"] = "application/octet-stream" | |||
headers["Ttl"] = ttl | |||
|
|||
if encrypted_payload? | |||
if @payload.has_key?(:server_public_key) | |||
headers["Content-Encoding"] = "aesgcm" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
https://tools.ietf.org/html/draft-ietf-webpush-encryption-03 says "aesgcm128"
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for checking, made the change
end | ||
|
||
headers["Authorization"] = "key=#{api_key}" if api_key? | ||
vapid_headers = build_vapid_headers | ||
headers["Authorization"] = vapid_headers["Authorization"] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this still needs the previous case matching statement, or something to the effect of:
if (@endpoint =~ /\Ahttps:\/\/(android|gcm-http)\.googleapis\.com/) {
vapid_headers = api_key? ? {"Authorization": "key=#{api_key}" } : {}
} else {
vapid_headers = build_vapid_headers
}
Reason being that for backwards compatibility, people may still have old tokens saved. Basically iff the subscription is created with a VAPID public key in JS on the client, an FCM endpoint will be returned. Otherwise, you still get the old style and wouldn't be able to perform VAPID with it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good point. It was perhaps aggressive of me to remove this functionality so I've added an item to my checklist to reinstate.
Set 'Content-Encoding': 'aesgcm128' and remove 'keyid=p256dh' from 'Encryption' and 'Crypto-Key' headers
Quick update: I now have the VAPID implementation working in Chrome. I had to fix the The |
@rossta can you please help me. I'm not sure that I'm trying your branch right. Because when I try to push to new subscription from FF 49.0.1 I receive 400:
The code I use is the same for Chrome (which is works) and for FF subscriptions:
|
Extensive setup tutorial for using webpush with VAPID
@gazay Thanks for alerting me. I was able to reproduce in FF as well while it works in Chrome. Looking into it. |
@rossta I'll reach out to FF and see what the deal is with the content encoding header and try to get a more definitive answer. |
Update: This PR is now feature-complete and ready for closer review. I updated the description with more details about the changes and usage. |
@rossta when you were doing aesgcm128, which version of FF were you using? They said it should work, but may not in 46 or lower since the way encryption was done was different. I'm getting the sense that's the case for a lot of this (the ; vs ,'s, legacy GCM, etc.) so maybe we should just suggest that people do browser detection for appropriate versions of Chrome and FF? |
@comp615 Thanks for looking into it. I've tried in Firefox 49.0.1 and FirefoxNightly 52.0a1 with I haven't ruled out the possibility that perhaps something else might be incorrect about our encryption and encoding logic, but I haven't come across anything yet, other the changes we've already noted in this thread. I can continue trying to debug, but the response messages from both Chrome and FF don't always help us determine the root cause. |
I'm a dummy. Apparently the newer spec version is aesgcm, so that's definitely the correct way how you have it now. Sorry for the runaround. |
Ha, nice catch! I also missed that it wasn't the most recent spec. Glad you On Tuesday, October 11, 2016, Charlie Croom [email protected]
Ross Kaffenberger |
headers["Content-Encoding"] = "aesgcm" | ||
headers["Encryption"] = "salt=#{salt_param}" | ||
headers["Crypto-Key"] = "dh=#{dh_param}" | ||
end | ||
|
||
headers["Authorization"] = "key=#{api_key}" if api_key? | ||
if api_key? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@rossta Thank you for your great PR! 😀
I think that it cannot be sent to the FF endpoint is not a VAPID.
I think that judging by the vapid options.
What do you think?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hi @zaru - thanks!
I'm not sure I understand your question completely so please correct me if my answer is misdirected:
I believe one thing the PR is missing is to account for the fact that VAPID is optional so I'll need to add logic to allow the request to succeed if :vapid_options
and :api_key
are missing from the request as it should still be possible to send the notification. I've added that along with README updates as of de87c4c.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@rossta Thanks!
I tested your PR and it looks fine.
So I'm gonna merge them if you've got nothing else to check. Is that okay?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@zaru Yes, thank you! I'm sure there's a lot to improve on here, especially with request error handling, but I hope the community will find this changeset useful as a starting point with VAPID.
This PR is
a work-in-progress and not ready to mergeis ready for review. It is a fairly large set of changes internally that should be backwards compatible withwebpush
using GCM API key, while providing support for VAPID, now available in FF and Chrome, as the way moving forward for server identification.This is a rather large PR. I'm happy to take suggestions to break it down into smaller parts.
Fixes #25 Fixes #13
Usage
The server must store public and private VAPID keys. To generate (one-time):
The client needs the public key as a JavaScript
Uint8Array
initialized with the decoded bytes.Provide the public key with the
pushManager.subscribe
options.Provide VAPID details when sending a push notification from the backend along with the payload and subscription settings.
Notes
I have rewritten the
Webpush::Request
to set'Authorization
andCrypto-Key
headers using the VAPID protocol. I can successfully send push requests with VAPID through Firefox and Chrome.In Chrome, I frequently get a#<Net::HTTPBadRequest 400 UnauthorizedRegistration readbody=true>
response. I haven't found the root cause but would be interested in help to troubleshoot.Checklist
Vapid
module