diff --git a/.travis.yml b/.travis.yml
deleted file mode 100644
index 0b0def3..0000000
--- a/.travis.yml
+++ /dev/null
@@ -1,16 +0,0 @@
-dist: xenial
-language: python
-python:
-- "2.7"
-- "3.5"
-- "3.6"
-- "3.7"
-install:
-- cd python
-- pip install -r requirements.txt
-- pip install -r test-requirements.txt
-script:
-- nosetests
-- flake8 py_vapid
-after_success:
- - coverage report --omit py_vapid/main.py
diff --git a/python/README.rst b/python/README.rst
index d3d3645..e54c498 100644
--- a/python/README.rst
+++ b/python/README.rst
@@ -1,4 +1,3 @@
-`PyPI version py_vapid `__
Easy VAPID generation
=====================
@@ -95,3 +94,6 @@ that some User Agents may require you `to decode this string into a
Uint8Array `__.
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/
diff --git a/python/claims.json b/python/claims.json
index e4ddac4..a5bc959 100644
--- a/python/claims.json
+++ b/python/claims.json
@@ -1,6 +1,5 @@
{
"sub": "mailto:admin@example.com",
- "aud": "https://push.services.mozilla.com",
- "exp": "1463001340"
+ "aud": "https://push.services.mozilla.com"
}
diff --git a/python/py_vapid/__init__.py b/python/py_vapid/__init__.py
index 8adfffb..1103582 100644
--- a/python/py_vapid/__init__.py
+++ b/python/py_vapid/__init__.py
@@ -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)
diff --git a/python/py_vapid/tests/test_vapid.py b/python/py_vapid/tests/test_vapid.py
index bba60ef..d6fd743 100644
--- a/python/py_vapid/tests/test_vapid.py
+++ b/python/py_vapid/tests/test_vapid.py
@@ -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
@@ -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:
@@ -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")
@@ -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):
@@ -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()
@@ -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()
@@ -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(
@@ -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")
@@ -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")
@@ -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!
@@ -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!
@@ -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")
diff --git a/python/setup.py b/python/setup.py
index 0dceeef..c59bc07 100644
--- a/python/setup.py
+++ b/python/setup.py
@@ -3,7 +3,7 @@
from setuptools import setup, find_packages
-__version__ = "1.7.1"
+__version__ = "1.8.0"
def read_from(file):
@@ -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'),
diff --git a/python/test-requirements.txt b/python/test-requirements.txt
index 6cd2359..bfce84f 100644
--- a/python/test-requirements.txt
+++ b/python/test-requirements.txt
@@ -1,4 +1,5 @@
-nose
+-r requirements.txt
+pytest
coverage
mock>=1.0.1
flake8
diff --git a/python/upload.sh b/python/upload.sh
index a1dc144..088999b 100644
--- a/python/upload.sh
+++ b/python/upload.sh
@@ -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
diff --git a/rust/vapid/Cargo.toml b/rust/vapid/Cargo.toml
index 07d5d50..b002def 100644
--- a/rust/vapid/Cargo.toml
+++ b/rust/vapid/Cargo.toml
@@ -1,6 +1,6 @@
[package]
name = "vapid"
-version = "0.2.0"
+version = "0.3.0"
authors = ["jrconlin "]
edition = "2018"
description = "An implementation of the RFC 8292 Voluntary Application Server Identification (VAPID) Auth header generator"
@@ -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"
diff --git a/rust/vapid/src/error.rs b/rust/vapid/src/error.rs
index 8508234..6fd6505 100644
--- a/rust/vapid/src/error.rs
+++ b/rust/vapid/src/error.rs
@@ -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()
}
diff --git a/rust/vapid/src/lib.rs b/rust/vapid/src/lib.rs
index 3d9b181..b3e3c0f 100644
--- a/rust/vapid/src/lib.rs
+++ b/rust/vapid/src/lib.rs
@@ -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;
@@ -170,6 +166,12 @@ fn parse_auth_token(auth_token: &str) -> Result {
// 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()`.
@@ -194,21 +196,21 @@ pub fn sign(
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(),
)
@@ -273,7 +275,7 @@ pub fn sign(
let auth_t = format!(
"{}.{}",
- content.clone(),
+ content,
base64::encode_config(
unsafe { &String::from_utf8_unchecked(sigval) },
base64::URL_SAFE_NO_PAD,
@@ -289,7 +291,7 @@ pub fn sign(
pub fn verify(auth_token: String) -> Result, 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) {
@@ -487,5 +489,4 @@ mod tests {
}
//TODO: Add key input/output tests here.
-
}