Skip to content

Commit

Permalink
chore: Update dependencies & tests
Browse files Browse the repository at this point in the history
Closes #86
  • Loading branch information
jrconlin committed Mar 12, 2021
1 parent 6699d06 commit ff25810
Show file tree
Hide file tree
Showing 10 changed files with 64 additions and 64 deletions.
4 changes: 3 additions & 1 deletion python/README.rst
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
`PyPI version py_vapid <https://pypi.org/project/py-vapid/>`__

Easy VAPID generation
=====================
Expand Down Expand Up @@ -95,3 +94,6 @@ that some User Agents may require you `to decode this string into a
Uint8Array <https://github.com/GoogleChrome/push-notifications/blob/master/app/scripts/main.js>`__.

See ``bin/vapid -h`` for all options and commands.

.. |PyPI version py_vapid| image:: https://badge.fury.io/py/py-vapid.svg
:target: https://pypi.org/project/py-vapid/
3 changes: 1 addition & 2 deletions python/claims.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
{
"sub": "mailto:admin@example.com",
"aud": "https://push.services.mozilla.com",
"exp": "1463001340"
"aud": "https://push.services.mozilla.com"
}

1 change: 1 addition & 0 deletions python/py_vapid/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,7 @@ def from_file(cls, private_key_file=None):
"""
if not os.path.isfile(private_key_file):
logging.info("Private key not found, generating key...")
vapid = cls()
vapid.generate_keys()
vapid.save_key(private_key_file)
Expand Down
61 changes: 30 additions & 31 deletions python/py_vapid/tests/test_vapid.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
import json
import unittest
from cryptography.hazmat.primitives import serialization
from nose.tools import eq_, ok_
from mock import patch, Mock

from py_vapid import Vapid01, Vapid02, VapidException
Expand Down Expand Up @@ -49,7 +48,7 @@
).strip('=').encode('utf8')


def setUp(self):
def setup_module(self):
with open('/tmp/private', 'w') as ff:
ff.write(TEST_KEY_PRIVATE_PEM)
with open('/tmp/public', 'w') as ff:
Expand All @@ -58,16 +57,16 @@ def setUp(self):
ff.write(TEST_KEY_PRIVATE_DER)


def tearDown(self):
def teardown_module(self):
os.unlink('/tmp/private')
os.unlink('/tmp/public')


class VapidTestCase(unittest.TestCase):
def check_keys(self, v):
eq_(v.private_key.private_numbers().private_value, key.get('d'))
eq_(v.public_key.public_numbers().x, key.get('x'))
eq_(v.public_key.public_numbers().y, key.get('y'))
assert v.private_key.private_numbers().private_value == key.get('d')
assert v.public_key.public_numbers().x == key.get('x')
assert v.public_key.public_numbers().y == key.get('y')

def test_init(self):
v1 = Vapid01.from_file("/tmp/private")
Expand All @@ -80,7 +79,7 @@ def test_init(self):
self.check_keys(v4)
no_exist = '/tmp/not_exist'
Vapid01.from_file(no_exist)
ok_(os.path.isfile(no_exist))
assert os.path.isfile(no_exist)
os.unlink(no_exist)

def repad(self, data):
Expand All @@ -95,8 +94,8 @@ def test_init_bad_read(self, mm):
def test_gen_key(self):
v = Vapid01()
v.generate_keys()
ok_(v.public_key)
ok_(v.private_key)
assert v.public_key
assert v.private_key

def test_private_key(self):
v = Vapid01()
Expand All @@ -105,8 +104,8 @@ def test_private_key(self):

def test_public_key(self):
v = Vapid01()
eq_(v._private_key, None)
eq_(v._public_key, None)
assert v._private_key is None
assert v._public_key is None

def test_save_key(self):
v = Vapid01()
Expand Down Expand Up @@ -135,7 +134,7 @@ def test_sign_01(self):
claims = {"aud": "https://example.com",
"sub": "mailto:admin@example.com"}
result = v.sign(claims, "id=previous")
eq_(result['Crypto-Key'],
assert result['Crypto-Key'] == (
'id=previous;p256ecdsa=' + TEST_KEY_PUBLIC_RAW.decode('utf8'))
pkey = binascii.b2a_base64(
v.public_key.public_bytes(
Expand All @@ -145,16 +144,16 @@ def test_sign_01(self):
).decode('utf8').replace('+', '-').replace('/', '_').strip()
items = decode(result['Authorization'].split(' ')[1], pkey)
for k in claims:
eq_(items[k], claims[k])
assert items[k] == claims[k]
result = v.sign(claims)
eq_(result['Crypto-Key'],
'p256ecdsa=' + TEST_KEY_PUBLIC_RAW.decode('utf8'))
assert result['Crypto-Key'] == ('p256ecdsa=' +
TEST_KEY_PUBLIC_RAW.decode('utf8'))
# Verify using the same function as Integration
# this should ensure that the r,s sign values are correctly formed
ok_(Vapid01.verify(
assert Vapid01.verify(
key=result['Crypto-Key'].split('=')[1],
auth=result['Authorization']
))
)

def test_sign_02(self):
v = Vapid02.from_file("/tmp/private")
Expand All @@ -164,20 +163,20 @@ def test_sign_02(self):
claim_check = copy.deepcopy(claims)
result = v.sign(claims, "id=previous")
auth = result['Authorization']
eq_(auth[:6], 'vapid ')
ok_(' t=' in auth)
ok_(',k=' in auth)
assert auth[:6] == 'vapid '
assert ' t=' in auth
assert ',k=' in auth
parts = auth[6:].split(',')
eq_(len(parts), 2)
assert len(parts) == 2
t_val = json.loads(base64.urlsafe_b64decode(
self.repad(parts[0][2:].split('.')[1])
).decode('utf8'))
k_val = binascii.a2b_base64(self.repad(parts[1][2:]))
eq_(binascii.hexlify(k_val)[:2], b'04')
eq_(len(k_val), 65)
eq_(claims, claim_check)
assert binascii.hexlify(k_val)[:2] == b'04'
assert len(k_val) == 65
assert claims == claim_check
for k in claims:
eq_(t_val[k], claims[k])
assert t_val[k] == claims[k]

def test_sign_02_localhost(self):
v = Vapid02.from_file("/tmp/private")
Expand All @@ -186,9 +185,9 @@ def test_sign_02_localhost(self):
"foo": "extra value"}
result = v.sign(claims, "id=previous")
auth = result['Authorization']
eq_(auth[:6], 'vapid ')
ok_(' t=' in auth)
ok_(',k=' in auth)
assert auth[:6] == 'vapid '
assert ' t=' in auth
assert ',k=' in auth

def test_integration(self):
# These values were taken from a test page. DO NOT ALTER!
Expand All @@ -199,8 +198,8 @@ def test_integration(self):
"4cCI6MTQ5NDY3MTQ3MCwic3ViIjoibWFpbHRvOnNpbXBsZS1wdXNoLWRlb"
"W9AZ2F1bnRmYWNlLmNvLnVrIn0.LqPi86T-HJ71TXHAYFptZEHD7Wlfjcc"
"4u5jYZ17WpqOlqDcW-5Wtx3x1OgYX19alhJ9oLumlS2VzEvNioZolQA")
ok_(Vapid01.verify(key=key, auth="webpush {}".format(auth)))
ok_(Vapid02.verify(auth="vapid t={},k={}".format(auth, key)))
assert Vapid01.verify(key=key, auth="webpush {}".format(auth))
assert Vapid02.verify(auth="vapid t={},k={}".format(auth, key))

def test_bad_integration(self):
# These values were taken from a test page. DO NOT ALTER!
Expand All @@ -211,7 +210,7 @@ def test_bad_integration(self):
"4cCI6MTQ5NDY3MTQ3MCwic3ViIjoibWFpbHRvOnNpbXBsZS1wdXNoLWRlb"
"W9AZ2F1bnRmYWNlLmNvLnVrIn0.LqPi86T-HJ71TXHAYFptZEHD7Wlfjcc"
"4u5jYZ17WpqOlqDcW-5Wtx3x1OgYX19alhJ9oLumlS2VzEvNioZ_BAD")
eq_(Vapid01.verify(key=key, auth=auth), False)
assert Vapid01.verify(key=key, auth=auth) == False

def test_bad_sign(self):
v = Vapid01.from_file("/tmp/private")
Expand Down
16 changes: 6 additions & 10 deletions python/setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@

from setuptools import setup, find_packages

__version__ = "1.7.1"
__version__ = "1.8.0"


def read_from(file):
Expand All @@ -24,31 +24,27 @@ def read_from(file):
here = os.path.abspath(os.path.dirname(__file__))
with io.open(os.path.join(here, 'README.rst'), encoding='utf8') as f:
README = f.read()
with io.open(os.path.join(here, 'CHANGELOG.md'), encoding='utf8') as f:
CHANGES = f.read()
#with io.open(os.path.join(here, 'CHANGELOG.md'), encoding='utf8') as f:
# CHANGES = f.read()

setup(name="py-vapid",
version=__version__,
description='Simple VAPID header generation library',
long_description=README + '\n\n' + CHANGES,
long_description=README,
long_description_content_type="text/x-rst",
classifiers=["Topic :: Internet :: WWW/HTTP",
"Programming Language :: Python",
"Programming Language :: Python :: 2",
"Programming Language :: Python :: 2.7",
"Programming Language :: Python :: 3",
"Programming Language :: Python :: 3.4",
"Programming Language :: Python :: 3.5",
],
keywords='vapid push webpush',
author="JR Conlin",
author_email="src+vapid@jrconlin.com",
url='https://github.com/mozilla-services/vapid',
license="MPL2",
test_suite="nose.collector",
include_package_data=True,
zip_safe=False,
packages=find_packages(),
package_data={'': ['README.md', 'CHANGELOG.md',
package_data={'': ['README.rst', 'CHANGELOG.rst',
'requirements.txt', 'test-requirements.txt']},
install_requires=read_from('requirements.txt'),
tests_require=read_from('test-requirements.txt'),
Expand Down
3 changes: 2 additions & 1 deletion python/test-requirements.txt
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
nose
-r requirements.txt
pytest
coverage
mock>=1.0.1
flake8
7 changes: 4 additions & 3 deletions python/upload.sh
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#!/bin/sh
# Package the current branch up to pypi
# remember to update the README.rst file
pandoc --from=markdown --to=rst --output README.rst README.md
bin/python setup.py sdist
bin/twine upload dist/*
#pandoc --from=markdown --to=rst --output README.rst README.md
#pandoc --from=markdown --to=rst --output CHANGELOG.rst CHANGELOG.md
venv/bin/python setup.py sdist
venv/bin/twine upload dist/* --verbose
6 changes: 3 additions & 3 deletions rust/vapid/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "vapid"
version = "0.2.0"
version = "0.3.0"
authors = ["jrconlin <jconlin+git@mozilla.com>"]
edition = "2018"
description = "An implementation of the RFC 8292 Voluntary Application Server Identification (VAPID) Auth header generator"
Expand All @@ -10,6 +10,6 @@ license = "MPL 2.0"
[dependencies]
openssl = "0.10"
serde_json = "1.0"
base64 = "0.10"
time = "0.1"
base64 = "0.13"
time = "0.2"
failure = "0.1"
2 changes: 1 addition & 1 deletion rust/vapid/src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ pub enum VapidErrorKind {
}

impl Fail for VapidError {
fn cause(&self) -> Option<&Fail> {
fn cause(&self) -> Option<&dyn Fail> {
self.inner.cause()
}

Expand Down
25 changes: 13 additions & 12 deletions rust/vapid/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,11 +30,7 @@
//!
//! ```

extern crate base64;
extern crate failure;
extern crate openssl;
extern crate serde_json;
extern crate time;
use std::time::SystemTime;

use std::collections::HashMap;
use std::fs;
Expand Down Expand Up @@ -170,6 +166,12 @@ fn parse_auth_token(auth_token: &str) -> Result<AuthElements, String> {
// Preferred schema
static SCHEMA: &str = "vapid";

fn to_secs(t: SystemTime) -> u64 {
t.duration_since(SystemTime::UNIX_EPOCH)
.unwrap_or_default()
.as_secs()
}

/// Convert the HashMap containing the claims into an Authorization header.
/// `key` must be generated or initialized before this is used. See `Key::from_pem()` or
/// `Key::generate()`.
Expand All @@ -194,21 +196,21 @@ pub fn sign<S: BuildHasher>(
return Err(error::VapidErrorKind::VapidError("'sub' not found".to_owned()).into());
}
}
let today = time::now_utc();
let today = SystemTime::now();
let tomorrow = today + time::Duration::hours(24);
claims
.entry(String::from("exp"))
.or_insert_with(|| serde_json::Value::from(tomorrow.to_timespec().sec));
.or_insert_with(|| serde_json::Value::from(to_secs(tomorrow)));
match claims.get("exp") {
Some(exp) => {
let exp_val = exp.as_i64().unwrap();
if exp_val < today.to_timespec().sec {
if (exp_val as u64) < to_secs(today) {
return Err(error::VapidErrorKind::VapidError(
r#""exp" already expired"#.to_owned(),
)
.into());
}
if exp_val > tomorrow.to_timespec().sec {
if (exp_val as u64) > to_secs(tomorrow) {
return Err(error::VapidErrorKind::VapidError(
r#""exp" set too far ahead"#.to_owned(),
)
Expand Down Expand Up @@ -273,7 +275,7 @@ pub fn sign<S: BuildHasher>(

let auth_t = format!(
"{}.{}",
content.clone(),
content,
base64::encode_config(
unsafe { &String::from_utf8_unchecked(sigval) },
base64::URL_SAFE_NO_PAD,
Expand All @@ -289,7 +291,7 @@ pub fn sign<S: BuildHasher>(
pub fn verify(auth_token: String) -> Result<HashMap<String, serde_json::Value>, String> {
//Verify that the auth token string matches for the verification token string
let auth_token =
parse_auth_token(&auth_token.clone()).expect("Authorization header is invalid.");
parse_auth_token(&auth_token).expect("Authorization header is invalid.");
let pub_ec_key =
Key::from_public_raw(auth_token.k).expect("'k' token is not a valid public key");
let pub_key = &match PKey::from_ec_key(pub_ec_key) {
Expand Down Expand Up @@ -487,5 +489,4 @@ mod tests {
}

//TODO: Add key input/output tests here.

}

0 comments on commit ff25810

Please sign in to comment.