Skip to content
This repository was archived by the owner on Apr 13, 2024. It is now read-only.

Commit e5e42a5

Browse files
committed
Code formatting cleanup
1 parent 959ae3d commit e5e42a5

File tree

10 files changed

+192
-132
lines changed

10 files changed

+192
-132
lines changed

CHANGELOG.rst

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,14 @@
11
httpsig Changes
22
---------------
33

4+
1.2.0 (2018-Mar-28)
5+
-------------------
6+
7+
* Switched to pycryptodome instead of PyCrypto
8+
* Updated tests with the test data from Draft 8 and verified it still passes.
9+
* Dropped official Python 3.2 support (pip dropped it so it can't be properly tested)
10+
* Cleaned up the code to be more PEP8-like.
11+
412
1.1.2 (2015-Feb-11)
513
-------------------
614

httpsig/_version.py

Lines changed: 18 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
21
# This file helps to compute a version number in source trees obtained from
32
# git-archive tarball (such as those provided by githubs download-from-tag
43
# feature). Distribution tarballs (build by setup.py sdist) and build
@@ -8,16 +7,17 @@
87
# This file is released into the public domain. Generated by
98
# versioneer-0.10 (https://github.com/warner/python-versioneer)
109

10+
import errno
11+
import os.path
12+
import re
13+
import subprocess
14+
import sys
15+
1116
# these strings will be replaced by git during git-archive
1217
git_refnames = "$Format:%d$"
1318
git_full = "$Format:%H$"
1419

1520

16-
import subprocess
17-
import sys
18-
import errno
19-
20-
2121
def run_command(commands, args, cwd=None, verbose=False, hide_stderr=False):
2222
assert isinstance(commands, list)
2323
p = None
@@ -50,18 +50,14 @@ def run_command(commands, args, cwd=None, verbose=False, hide_stderr=False):
5050
return stdout
5151

5252

53-
import sys
54-
import re
55-
import os.path
56-
5753
def get_expanded_variables(versionfile_abs):
5854
# the code embedded in _version.py can just fetch the value of these
5955
# variables. When used from setup.py, we don't want to import
6056
# _version.py, so we do it with a regexp instead. This function is not
6157
# used from _version.py.
6258
variables = {}
6359
try:
64-
f = open(versionfile_abs,"r")
60+
f = open(versionfile_abs, "r")
6561
for line in f.readlines():
6662
if line.strip().startswith("git_refnames ="):
6763
mo = re.search(r'=\s*"(.*)"', line)
@@ -76,12 +72,13 @@ def get_expanded_variables(versionfile_abs):
7672
pass
7773
return variables
7874

75+
7976
def versions_from_expanded_variables(variables, tag_prefix, verbose=False):
8077
refnames = variables["refnames"].strip()
8178
if refnames.startswith("$Format"):
8279
if verbose:
8380
print("variables are unexpanded, not using")
84-
return {} # unexpanded, so not in an unpacked git-archive tarball
81+
return {} # unexpanded, so not in an unpacked git-archive tarball
8582
refs = set([r.strip() for r in refnames.strip("()").split(",")])
8683
# starting in git-1.8.3, tags are listed as "tag: foo-1.0" instead of
8784
# just "foo-1.0". If we see a "tag: " prefix, prefer those.
@@ -97,7 +94,7 @@ def versions_from_expanded_variables(variables, tag_prefix, verbose=False):
9794
# "stabilization", as well as "HEAD" and "master".
9895
tags = set([r for r in refs if re.search(r'\d', r)])
9996
if verbose:
100-
print("discarding '%s', no digits" % ",".join(refs-tags))
97+
print("discarding '%s', no digits" % ",".join(refs - tags))
10198
if verbose:
10299
print("likely tags: %s" % ",".join(sorted(tags)))
103100
for ref in sorted(tags):
@@ -106,13 +103,14 @@ def versions_from_expanded_variables(variables, tag_prefix, verbose=False):
106103
r = ref[len(tag_prefix):]
107104
if verbose:
108105
print("picking %s" % r)
109-
return { "version": r,
110-
"full": variables["full"].strip() }
106+
return {"version": r,
107+
"full": variables["full"].strip()}
111108
# no suitable tags, so we use the full revision id
112109
if verbose:
113110
print("no suitable tags, using full revision id")
114-
return { "version": variables["full"].strip(),
115-
"full": variables["full"].strip() }
111+
return {"version": variables["full"].strip(),
112+
"full": variables["full"].strip()}
113+
116114

117115
def versions_from_vcs(tag_prefix, root, verbose=False):
118116
# this runs 'git' from the root of the source tree. This only gets called
@@ -157,17 +155,19 @@ def versions_from_parentdir(parentdir_prefix, root, verbose=False):
157155
return None
158156
return {"version": dirname[len(parentdir_prefix):], "full": ""}
159157

158+
160159
tag_prefix = "v"
161160
parentdir_prefix = "httpsig-"
162161
versionfile_source = "httpsig/_version.py"
163162

163+
164164
def get_versions(default={"version": "unknown", "full": ""}, verbose=False):
165165
# I am in _version.py, which lives at ROOT/VERSIONFILE_SOURCE. If we have
166166
# __file__, we can work backwards from there to the root. Some
167167
# py2exe/bbfreeze/non-CPython implementations don't do __file__, in which
168168
# case we can only use expanded variables.
169169

170-
variables = { "refnames": git_refnames, "full": git_full }
170+
variables = {"refnames": git_refnames, "full": git_full}
171171
ver = versions_from_expanded_variables(variables, tag_prefix, verbose)
172172
if ver:
173173
return ver
@@ -185,4 +185,3 @@ def get_versions(default={"version": "unknown", "full": ""}, verbose=False):
185185
return (versions_from_vcs(tag_prefix, root, verbose)
186186
or versions_from_parentdir(parentdir_prefix, root, verbose)
187187
or default)
188-

httpsig/requests_auth.py

Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
from requests.auth import AuthBase
1+
import requests.auth
22
try:
33
# Python 3
44
from urllib.parse import urlparse
@@ -9,20 +9,23 @@
99
from .sign import HeaderSigner
1010

1111

12-
class HTTPSignatureAuth(AuthBase):
12+
class HTTPSignatureAuth(requests.auth.AuthBase):
1313
'''
1414
Sign a request using the http-signature scheme.
1515
https://github.com/joyent/node-http-signature/blob/master/http_signing.md
1616
17-
key_id is the mandatory label indicating to the server which secret to use
18-
secret is the filename of a pem file in the case of rsa, a password string in the case of an hmac algorithm
19-
algorithm is one of the six specified algorithms
20-
headers is a list of http headers to be included in the signing string, defaulting to "Date" alone.
17+
`key_id` is the mandatory label indicating to the server which secret to
18+
use secret is the filename of a pem file in the case of rsa, a password
19+
string in the case of an hmac algorithm
20+
`algorithm` is one of the six specified algorithms
21+
headers is a list of http headers to be included in the signing string,
22+
defaulting to "Date" alone.
2123
'''
2224
def __init__(self, key_id='', secret='', algorithm=None, headers=None):
2325
headers = headers or []
24-
self.header_signer = HeaderSigner(key_id=key_id, secret=secret,
25-
algorithm=algorithm, headers=headers)
26+
self.header_signer = HeaderSigner(
27+
key_id=key_id, secret=secret,
28+
algorithm=algorithm, headers=headers)
2629
self.uses_host = 'host' in [h.lower() for h in headers]
2730

2831
def __call__(self, r):

httpsig/sign.py

Lines changed: 35 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -15,49 +15,54 @@ class Signer(object):
1515
"""
1616
When using an RSA algo, the secret is a PEM-encoded private key.
1717
When using an HMAC algo, the secret is the HMAC signing secret.
18-
18+
1919
Password-protected keyfiles are not supported.
2020
"""
2121
def __init__(self, secret, algorithm=None):
2222
if algorithm is None:
2323
algorithm = DEFAULT_SIGN_ALGORITHM
24-
24+
2525
assert algorithm in ALGORITHMS, "Unknown algorithm"
26-
if isinstance(secret, six.string_types): secret = secret.encode("ascii")
27-
26+
if isinstance(secret, six.string_types):
27+
secret = secret.encode("ascii")
28+
2829
self._rsa = None
2930
self._hash = None
3031
self.sign_algorithm, self.hash_algorithm = algorithm.split('-')
31-
32+
3233
if self.sign_algorithm == 'rsa':
3334
try:
3435
rsa_key = RSA.importKey(secret)
3536
self._rsa = PKCS1_v1_5.new(rsa_key)
3637
self._hash = HASHES[self.hash_algorithm]
3738
except ValueError:
3839
raise HttpSigException("Invalid key.")
39-
40+
4041
elif self.sign_algorithm == 'hmac':
41-
self._hash = HMAC.new(secret, digestmod=HASHES[self.hash_algorithm])
42+
self._hash = HMAC.new(secret,
43+
digestmod=HASHES[self.hash_algorithm])
4244

4345
@property
4446
def algorithm(self):
4547
return '%s-%s' % (self.sign_algorithm, self.hash_algorithm)
4648

4749
def _sign_rsa(self, data):
48-
if isinstance(data, six.string_types): data = data.encode("ascii")
50+
if isinstance(data, six.string_types):
51+
data = data.encode("ascii")
4952
h = self._hash.new()
5053
h.update(data)
5154
return self._rsa.sign(h)
5255

5356
def _sign_hmac(self, data):
54-
if isinstance(data, six.string_types): data = data.encode("ascii")
57+
if isinstance(data, six.string_types):
58+
data = data.encode("ascii")
5559
hmac = self._hash.copy()
5660
hmac.update(data)
5761
return hmac.digest()
5862

5963
def _sign(self, data):
60-
if isinstance(data, six.string_types): data = data.encode("ascii")
64+
if isinstance(data, six.string_types):
65+
data = data.encode("ascii")
6166
signed = None
6267
if self._rsa:
6368
signed = self._sign_rsa(data)
@@ -70,37 +75,43 @@ def _sign(self, data):
7075

7176
class HeaderSigner(Signer):
7277
'''
73-
Generic object that will sign headers as a dictionary using the http-signature scheme.
78+
Generic object that will sign headers as a dictionary using the
79+
http-signature scheme.
7480
https://github.com/joyent/node-http-signature/blob/master/http_signing.md
7581
76-
:arg key_id: the mandatory label indicating to the server which secret to use
77-
:arg secret: a PEM-encoded RSA private key or an HMAC secret (must match the algorithm)
82+
:arg key_id: the mandatory label indicating to the server which secret
83+
to use
84+
:arg secret: a PEM-encoded RSA private key or an HMAC secret (must
85+
match the algorithm)
7886
:arg algorithm: one of the six specified algorithms
79-
:arg headers: a list of http headers to be included in the signing string, defaulting to ['date'].
87+
:arg headers: a list of http headers to be included in the signing
88+
string, defaulting to ['date'].
8089
'''
8190
def __init__(self, key_id, secret, algorithm=None, headers=None):
8291
if algorithm is None:
8392
algorithm = DEFAULT_SIGN_ALGORITHM
84-
93+
8594
super(HeaderSigner, self).__init__(secret=secret, algorithm=algorithm)
8695
self.headers = headers or ['date']
87-
self.signature_template = build_signature_template(key_id, algorithm, headers)
96+
self.signature_template = build_signature_template(
97+
key_id, algorithm, headers)
8898

8999
def sign(self, headers, host=None, method=None, path=None):
90100
"""
91101
Add Signature Authorization header to case-insensitive header dict.
92102
93-
headers is a case-insensitive dict of mutable headers.
94-
host is a override for the 'host' header (defaults to value in headers).
95-
method is the HTTP method (required when using '(request-target)').
96-
path is the HTTP path (required when using '(request-target)').
103+
`headers` is a case-insensitive dict of mutable headers.
104+
`host` is a override for the 'host' header (defaults to value in
105+
headers).
106+
`method` is the HTTP method (required when using '(request-target)').
107+
`path` is the HTTP path (required when using '(request-target)').
97108
"""
98109
headers = CaseInsensitiveDict(headers)
99110
required_headers = self.headers or ['date']
100-
signable = generate_message(required_headers, headers, host, method, path)
101-
111+
signable = generate_message(
112+
required_headers, headers, host, method, path)
113+
102114
signature = self._sign(signable)
103115
headers['authorization'] = self.signature_template % signature
104-
105-
return headers
106116

117+
return headers

httpsig/tests/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11
from .test_signature import *
22
from .test_utils import *
3-
from .test_verify import *
3+
from .test_verify import *

httpsig/tests/test_signature.py

Lines changed: 16 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,15 @@
11
#!/usr/bin/env python
22
import sys
33
import os
4-
sys.path.insert(0, os.path.join(os.path.dirname(__file__), '..'))
54

6-
import json
75
import unittest
86

97
import httpsig.sign as sign
108
from httpsig.utils import parse_authorization_header
119

1210

11+
sys.path.insert(0, os.path.join(os.path.dirname(__file__), '..'))
12+
1313
sign.DEFAULT_SIGN_ALGORITHM = "rsa-sha256"
1414

1515

@@ -21,9 +21,10 @@ class TestSign(unittest.TestCase):
2121
header_content_type = 'application/json'
2222
header_digest = 'SHA-256=X48E9qOokqqrvdts8nOJRJN3OWDUoyWxBf7kbu9DBPE='
2323
header_content_length = '18'
24-
24+
2525
def setUp(self):
26-
self.key_path = os.path.join(os.path.dirname(__file__), 'rsa_private.pem')
26+
self.key_path = os.path.join(
27+
os.path.dirname(__file__), 'rsa_private.pem')
2728
with open(self.key_path, 'rb') as f:
2829
self.key = f.read()
2930

@@ -55,8 +56,9 @@ def test_basic(self):
5556
'Host': self.header_host,
5657
'Date': self.header_date,
5758
}
58-
signed = hs.sign(unsigned, method=self.test_method, path=self.test_path)
59-
59+
signed = hs.sign(
60+
unsigned, method=self.test_method, path=self.test_path)
61+
6062
self.assertIn('Date', signed)
6163
self.assertEqual(unsigned['Date'], signed['Date'])
6264
self.assertIn('Authorization', signed)
@@ -67,8 +69,8 @@ def test_basic(self):
6769
self.assertIn('signature', params)
6870
self.assertEqual(params['keyId'], 'Test')
6971
self.assertEqual(params['algorithm'], 'rsa-sha256')
70-
self.assertEqual(params['headers'],
71-
'(request-target) host date')
72+
self.assertEqual(
73+
params['headers'], '(request-target) host date')
7274
self.assertEqual(params['signature'], 'HUxc9BS3P/kPhSmJo+0pQ4IsCo007vkv6bUm4Qehrx+B1Eo4Mq5/6KylET72ZpMUS80XvjlOPjKzxfeTQj4DiKbAzwJAb4HX3qX6obQTa00/qPDXlMepD2JtTw33yNnm/0xV7fQuvILN/ys+378Ysi082+4xBQFwvhNvSoVsGv4=')
7375

7476
def test_all(self):
@@ -87,8 +89,9 @@ def test_all(self):
8789
'Digest': self.header_digest,
8890
'Content-Length': self.header_content_length,
8991
}
90-
signed = hs.sign(unsigned, method=self.test_method, path=self.test_path)
91-
92+
signed = hs.sign(
93+
unsigned, method=self.test_method, path=self.test_path)
94+
9295
self.assertIn('Date', signed)
9396
self.assertEqual(unsigned['Date'], signed['Date'])
9497
self.assertIn('Authorization', signed)
@@ -99,5 +102,7 @@ def test_all(self):
99102
self.assertIn('signature', params)
100103
self.assertEqual(params['keyId'], 'Test')
101104
self.assertEqual(params['algorithm'], 'rsa-sha256')
102-
self.assertEqual(params['headers'], '(request-target) host date content-type digest content-length')
105+
self.assertEqual(
106+
params['headers'],
107+
'(request-target) host date content-type digest content-length')
103108
self.assertEqual(params['signature'], 'Ef7MlxLXoBovhil3AlyjtBwAL9g4TN3tibLj7uuNB3CROat/9KaeQ4hW2NiJ+pZ6HQEOx9vYZAyi+7cmIkmJszJCut5kQLAwuX+Ms/mUFvpKlSo9StS2bMXDBNjOh4Auj774GFj4gwjS+3NhFeoqyr/MuN6HsEnkvn6zdgfE2i0=')

httpsig/tests/test_utils.py

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,18 @@
11
#!/usr/bin/env python
22
import os
3-
import re
43
import sys
5-
sys.path.insert(0, os.path.join(os.path.dirname(__file__), '..'))
6-
74
import unittest
8-
95
from httpsig.utils import get_fingerprint
106

7+
sys.path.insert(0, os.path.join(os.path.dirname(__file__), '..'))
8+
9+
1110
class TestUtils(unittest.TestCase):
1211

1312
def test_get_fingerprint(self):
14-
with open(os.path.join(os.path.dirname(__file__), 'rsa_public.pem'), 'r') as k:
13+
with open(os.path.join(
14+
os.path.dirname(__file__), 'rsa_public.pem'), 'r') as k:
1515
key = k.read()
1616
fingerprint = get_fingerprint(key)
17-
self.assertEqual(fingerprint, "73:61:a2:21:67:e0:df:be:7e:4b:93:1e:15:98:a5:b7")
17+
self.assertEqual(
18+
fingerprint, "73:61:a2:21:67:e0:df:be:7e:4b:93:1e:15:98:a5:b7")

0 commit comments

Comments
 (0)