forked from jrconlin/vapid
-
Notifications
You must be signed in to change notification settings - Fork 30
Feat: 3.4 support and JSON dump #31
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
Merged
Changes from all commits
Commits
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,6 +1,7 @@ | ||
| language: python | ||
| python: | ||
| - "2.7" | ||
| - "3.5" | ||
| install: | ||
| - cd python | ||
| - pip install -r requirements.txt | ||
|
|
||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -4,8 +4,50 @@ This minimal library contains the minimal set of functions you need to | |
| generate a VAPID key set and get the headers you'll need to sign a | ||
| WebPush subscription update. | ||
|
|
||
| This can either be installed as a library or used as a stand along | ||
| app. | ||
| VAPID is a voluntary standard for WebPush subscription providers | ||
| (sites that send WebPush updates to remote customers) to self-identify | ||
| to Push Servers (the servers that convey the push notifications). | ||
|
|
||
| The VAPID "claims" are a set of JSON keys and values. There are two | ||
| required fields, one semi-optional and several optional additional | ||
| fields. | ||
|
|
||
| At a minimum a VAPID claim set should look like: | ||
| ``` | ||
| {"sub":"mailto:[email protected]","aud":"https://PushServerURL","exp":"ExpirationTimestamp"} | ||
| ``` | ||
| A few notes: | ||
|
|
||
| ***sub*** is the email address you wish to have on record for this | ||
| request, prefixed with "`mailto:`". If things go wrong, this is the | ||
| email that will be used to contact you (for instance). This can be a | ||
| general delivery address like "`mailto:[email protected]`" or a | ||
| specific address like "`mailto:[email protected]`". | ||
|
|
||
| ***aud*** is the audience for the VAPID. This it the host path you use to | ||
| send subscription endpoints and generally coincides with the | ||
| `endpoint` specified in the Subscription Info block. | ||
|
|
||
| As example, if a WebPush subscription info contains: | ||
| `{"endpoint": "https://push.example.com:8012/v1/push/...", ...}` | ||
|
|
||
| then the `aud` would be "`https://push.example.com:8012/`" | ||
|
|
||
| While some Push Services consider this an optional field, others may | ||
| be stricter. | ||
|
|
||
| ***exp*** This is the UTC timestamp for when this VAPID request will | ||
| expire. The maximum period is 24 hours. Setting a shorter period can | ||
| prevent "replay" attacks. Setting a longer period allows you to reuse | ||
| headers for multiple sends (e.g. if you're sending hundreds of updates | ||
| within an hour or so.) If no `exp` is included, one that will expire | ||
| in 24 hours will be auto-generated for you. | ||
|
|
||
| Claims should be stored in a JSON compatible file. In the examples | ||
| below, we've stored the claims into a file named `claims.json`. | ||
|
|
||
| py_vapid can either be installed as a library or used as a stand along | ||
| app, `bin/vapid`. | ||
|
|
||
| ## App Installation | ||
|
|
||
|
|
@@ -15,18 +57,24 @@ Then run | |
| ``` | ||
| bin/pip install -r requirements.txt | ||
|
|
||
| bin/python setup.py`install | ||
| bin/python setup.py install | ||
| ``` | ||
| ## App Usage | ||
|
|
||
| Run by itself, `bin/vapid` will check and optionally create the | ||
| public_key.pem and private_key.pem files. | ||
|
|
||
| `bin/vapid --sign _claims.json_` will generate a set of HTTP headers | ||
| `bin/vapid -gen` can be used to generate a new set of public and | ||
| private key PEM files. These will overwrite the contents of | ||
| `private_key.pem` and `public_key.pem`. | ||
|
|
||
| `bin/vapid --sign claims.json` will generate a set of HTTP headers | ||
| from a JSON formatted claims file. A sample `claims.json` is included | ||
| with this distribution. | ||
|
|
||
| `bin/vapid --validate _token_` will generate a token response for the | ||
| Mozilla WebPush dashboard. | ||
| `bin/vapid --sign claims.json --json` will output the headers in | ||
| JSON format, which may be useful for other programs. | ||
|
|
||
| See `bin/vapid -h` for all options and commands. | ||
|
|
||
|
|
||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,85 @@ | ||
| Easy VAPID generation | ||
| ===================== | ||
|
|
||
| This minimal library contains the minimal set of functions you need to | ||
| generate a VAPID key set and get the headers you'll need to sign a | ||
| WebPush subscription update. | ||
|
|
||
| VAPID is a voluntary standard for WebPush subscription providers (sites | ||
| that send WebPush updates to remote customers) to self-identify to Push | ||
| Servers (the servers that convey the push notifications). | ||
|
|
||
| The VAPID "claims" are a set of JSON keys and values. There are two | ||
| required fields, one semi-optional and several optional additional | ||
| fields. | ||
|
|
||
| At a minimum a VAPID claim set should look like: | ||
|
|
||
| :: | ||
|
|
||
| {"sub":"mailto:[email protected]","aud":"https://PushServerURL","exp":"ExpirationTimestamp"} | ||
|
|
||
| A few notes: | ||
|
|
||
| ***sub*** is the email address you wish to have on record for this | ||
| request, prefixed with "``mailto:``". If things go wrong, this is the | ||
| email that will be used to contact you (for instance). This can be a | ||
| general delivery address like "``mailto:[email protected]``" | ||
| or a specific address like "``mailto:[email protected]``". | ||
|
|
||
| ***aud*** is the audience for the VAPID. This it the host path you use | ||
| to send subscription endpoints and generally coincides with the | ||
| ``endpoint`` specified in the Subscription Info block. | ||
|
|
||
| As example, if a WebPush subscription info contains: | ||
| ``{"endpoint": "https://push.example.com:8012/v1/push/...", ...}`` | ||
|
|
||
| then the ``aud`` would be "``https://push.example.com:8012/``" | ||
|
|
||
| While some Push Services consider this an optional field, others may be | ||
| stricter. | ||
|
|
||
| ***exp*** This is the UTC timestamp for when this VAPID request will | ||
| expire. The maximum period is 24 hours. Setting a shorter period can | ||
| prevent "replay" attacks. Setting a longer period allows you to reuse | ||
| headers for multiple sends (e.g. if you're sending hundreds of updates | ||
| within an hour or so.) If no ``exp`` is included, one that will expire | ||
| in 24 hours will be auto-generated for you. | ||
|
|
||
| Claims should be stored in a JSON compatible file. In the examples | ||
| below, we've stored the claims into a file named ``claims.json``. | ||
|
|
||
| py\_vapid can either be installed as a library or used as a stand along | ||
| app, ``bin/vapid``. | ||
|
|
||
| App Installation | ||
| ---------------- | ||
|
|
||
| You'll need ``python virtualenv`` Run that in the current directory. | ||
|
|
||
| Then run | ||
|
|
||
| :: | ||
|
|
||
| bin/pip install -r requirements.txt | ||
|
|
||
| bin/python setup.py install | ||
|
|
||
| App Usage | ||
| --------- | ||
|
|
||
| Run by itself, ``bin/vapid`` will check and optionally create the | ||
| public\_key.pem and private\_key.pem files. | ||
|
|
||
| ``bin/vapid -gen`` can be used to generate a new set of public and | ||
| private key PEM files. These will overwrite the contents of | ||
| ``private_key.pem`` and ``public_key.pem``. | ||
|
|
||
| ``bin/vapid --sign claims.json`` will generate a set of HTTP headers | ||
| from a JSON formatted claims file. A sample ``claims.json`` is included | ||
| with this distribution. | ||
|
|
||
| ``bin/vapid --sign claims.json --json`` will output the headers in JSON | ||
| format, which may be useful for other programs. | ||
|
|
||
| See ``bin/vapid -h`` for all options and commands. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -12,46 +12,54 @@ | |
| def main(): | ||
| parser = argparse.ArgumentParser(description="VAPID tool") | ||
| parser.add_argument('--sign', '-s', help='claims file to sign') | ||
| parser.add_argument('--gen', '-g', help='generate new key pairs', | ||
| default=False, action="store_true") | ||
| parser.add_argument('--validate', '-v', help='dashboard token to validate') | ||
| parser.add_argument('--version2', '-2', help="use VAPID spec Draft-02", | ||
| default=False, action="store_true") | ||
| parser.add_argument('--version1', '-1', help="use VAPID spec Draft-01", | ||
| default=True, action="store_true") | ||
| parser.add_argument('--json', help="dump as json", | ||
| default=False, action="store_true") | ||
| args = parser.parse_args() | ||
| Vapid = Vapid01 | ||
| if args.version2: | ||
| Vapid = Vapid02 | ||
| if not os.path.exists('private_key.pem'): | ||
| print "No private_key.pem file found." | ||
| answer = None | ||
| while answer not in ['y', 'n']: | ||
| answer = raw_input("Do you want me to create one for you? (Y/n)") | ||
| if not answer: | ||
| answer = 'y' | ||
| answer = answer.lower()[0] | ||
| if answer == 'n': | ||
| print "Sorry, can't do much for you then." | ||
| exit | ||
| if answer == 'y': | ||
| break | ||
| if args.gen or not os.path.exists('private_key.pem'): | ||
| if not args.gen: | ||
| print("No private_key.pem file found.") | ||
| answer = None | ||
| while answer not in ['y', 'n']: | ||
| answer = input("Do you want me to create one for you? (Y/n)") | ||
| if not answer: | ||
| answer = 'y' | ||
| answer = answer.lower()[0] | ||
| if answer == 'n': | ||
| print ("Sorry, can't do much for you then.") | ||
| exit | ||
| print("Generating private_key.pem") | ||
| Vapid().save_key('private_key.pem') | ||
| vapid = Vapid('private_key.pem') | ||
| if not os.path.exists('public_key.pem'): | ||
| print "No public_key.pem file found. You'll need this to access " | ||
| print "the developer dashboard." | ||
| answer = None | ||
| while answer not in ['y', 'n']: | ||
| answer = raw_input("Do you want me to create one for you? (Y/n)") | ||
| if not answer: | ||
| answer = 'y' | ||
| answer = answer.lower()[0] | ||
| if answer == 'y': | ||
| vapid.save_public_key('public_key.pem') | ||
| if args.gen or not os.path.exists('public_key.pem'): | ||
| if not args.gen: | ||
| print("No public_key.pem file found. You'll need this to access " | ||
| "the developer dashboard.") | ||
| answer = None | ||
| while answer not in ['y', 'n']: | ||
| answer = input("Do you want me to create one for you? (Y/n)") | ||
| if not answer: | ||
| answer = 'y' | ||
| answer = answer.lower()[0] | ||
| if answer == 'n': | ||
| print ("Exiting...") | ||
| exit | ||
| print("Generating public_key.pem") | ||
| vapid.save_public_key('public_key.pem') | ||
| claim_file = args.sign | ||
| if claim_file: | ||
| if not os.path.exists(claim_file): | ||
| print "No %s file found." % claim_file | ||
| print """ | ||
| print("No {} file found.".format(claim_file)) | ||
| print(""" | ||
| The claims file should be a JSON formatted file that holds the | ||
| information that describes you. There are three elements in the claims | ||
| file you'll need: | ||
|
|
@@ -70,25 +78,27 @@ def main(): | |
| For example, a claims.json file could contain: | ||
|
|
||
| {"sub": "mailto:[email protected]"} | ||
| """ | ||
| """) | ||
| exit | ||
| try: | ||
| claims = json.loads(open(claim_file).read()) | ||
| result = vapid.sign(claims) | ||
| except Exception, exc: | ||
| print "Crap, something went wrong: %s", repr(exc) | ||
| except Exception as exc: | ||
| print("Crap, something went wrong: {}".format(repr(exc))) | ||
| raise exc | ||
|
|
||
| print "Include the following headers in your request:\n" | ||
| if args.json: | ||
| print(json.dumps(result)) | ||
| return | ||
| print("Include the following headers in your request:\n") | ||
| for key, value in result.items(): | ||
| print "%s: %s" % (key, value) | ||
| print "\n" | ||
| print("{}: {}\n".format(key, value)) | ||
| print("\n") | ||
|
|
||
| token = args.validate | ||
| if token: | ||
| print "signed token for dashboard validation:\n" | ||
| print vapid.validate(token) | ||
| print "\n" | ||
| print("signed token for dashboard validation:\n") | ||
| print(vapid.validate(token)) | ||
| print("\n") | ||
|
|
||
|
|
||
| if __name__ == '__main__': | ||
|
|
||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -24,8 +24,12 @@ | |
| -----END PUBLIC KEY----- | ||
| """ | ||
|
|
||
| T_PUBLIC_RAW = """EJwJZq_GN8jJbo1GGpyU70hmP2hbWAUpQFKDBy\ | ||
| KB81yldJ9GTklBM5xqEwuPM7VuQcyiLDhvovthPIXx-gsQRQ==""".strip('=') | ||
| # this is a DER RAW key ('\x04' + 2 32 octet digits) | ||
| # Remember, this should have any padding stripped. | ||
| T_PUBLIC_RAW = ( | ||
| "BBCcCWavxjfIyW6NRhqclO9IZj9oW1gFKUBSgwcigfNc" | ||
| "pXSfRk5JQTOcahMLjzO1bkHMoiw4b6L7YTyF8foLEEU" | ||
| ).strip('=') | ||
|
|
||
|
|
||
| def setUp(self): | ||
|
|
@@ -87,7 +91,7 @@ def test_save_key(self): | |
| v.save_key("/tmp/p2") | ||
| os.unlink("/tmp/p2") | ||
|
|
||
| def test_save_public_key(self): | ||
| def test_same_public_key(self): | ||
| v = Vapid01() | ||
| v.generate_keys() | ||
| v.save_public_key("/tmp/p2") | ||
|
|
@@ -108,8 +112,7 @@ def test_sign_01(self): | |
| claims = {"aud": "example.com", "sub": "[email protected]"} | ||
| result = v.sign(claims, "id=previous") | ||
| eq_(result['Crypto-Key'], | ||
| 'id=previous,' | ||
| 'p256ecdsa=' + T_PUBLIC_RAW) | ||
| 'id=previous;p256ecdsa=' + T_PUBLIC_RAW) | ||
| items = jws.verify(result['Authorization'].split(' ')[1], | ||
| v.public_key, | ||
| algorithms=["ES256"]) | ||
|
|
||
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
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.
Looks like you're moving the .md -> .rst but forgot to delete the .md?
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.
Keeping it as well. There are a lot of apps that like .md more than .rst, and it's a simple script to convert. (In fact, it's part of my publish script
pandoc --from=markdown --to=rst --output README.rst README.md) I'm ok with dropping the .rst from the repo, but since it's part of the python packaging, I'd rather keep it.