Skip to content
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

chore: Update dependencies & tests #89

Merged
merged 2 commits into from
Mar 12, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 0 additions & 16 deletions .travis.yml

This file was deleted.

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.

}