Skip to content

Commit 796f707

Browse files
python-ecosys/ujwt: Add ujwt module.
1 parent 70e422d commit 796f707

File tree

5 files changed

+134
-3
lines changed

5 files changed

+134
-3
lines changed

python-ecosys/ujwt/metadata.txt

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
srctype = micropython-lib
2+
type = module
3+
version = 0.1.0

python-ecosys/ujwt/setup.py

+25
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
import sys
2+
3+
# Remove current dir from sys.path, otherwise setuptools will peek up our
4+
# module instead of system's.
5+
sys.path.pop(0)
6+
from setuptools import setup
7+
8+
sys.path.append("..")
9+
import sdist_upip
10+
11+
setup(
12+
name="micropython-ujwt",
13+
version="0.1",
14+
description="ujwt module for MicroPython",
15+
long_description="This is a module reimplemented specifically for MicroPython standard library,\nwith efficient and lean design in mind. Note that this module is likely work\nin progress and likely supports just a subset of CPython's corresponding\nmodule. Please help with the development if you are interested in this\nmodule.",
16+
url="https://github.com/micropython/micropython-lib",
17+
author="micropython-lib Developers",
18+
author_email="micro-python@googlegroups.com",
19+
maintainer="micropython-lib Developers",
20+
maintainer_email="micro-python@googlegroups.com",
21+
license="MIT",
22+
cmdclass={"sdist": sdist_upip.sdist},
23+
py_modules=["ujwt"],
24+
install_requires=["micropython-hmac"],
25+
)

python-ecosys/ujwt/test_ujwt.py

+26
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
import ujwt
2+
from time import time
3+
4+
secret_key = "top-secret!"
5+
6+
jwt = ujwt.encode({"user": "joe"}, secret_key)
7+
decoded = ujwt.decode(jwt, secret_key)
8+
if decoded != {"user": "joe"}:
9+
raise Exception("Invalid decoded JWT")
10+
else:
11+
print("Encode/decode test: OK")
12+
13+
try:
14+
decoded = ujwt.decode(jwt, "wrong-secret")
15+
except ujwt.exceptions.InvalidSignatureError:
16+
print("Invalid signature test: OK")
17+
else:
18+
raise Exception("Invalid JWT should have failed decoding")
19+
20+
jwt = ujwt.encode({"user": "joe", "exp": time() - 1}, secret_key)
21+
try:
22+
decoded = ujwt.decode(jwt, secret_key)
23+
except ujwt.exceptions.ExpiredTokenError:
24+
print("Expired token test: OK")
25+
else:
26+
raise Exception("Expired JWT should have failed decoding")

python-ecosys/ujwt/ujwt.py

+76
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
import binascii
2+
import hashlib
3+
import hmac
4+
import json
5+
from time import time
6+
7+
8+
def _to_b64url(data):
9+
return (
10+
binascii.b2a_base64(data)
11+
.rstrip(b"\n")
12+
.rstrip(b"=")
13+
.replace(b"+", b"-")
14+
.replace(b"/", b"_")
15+
)
16+
17+
18+
def _from_b64url(data):
19+
return binascii.a2b_base64(data.replace(b"-", b"+").replace(b"_", b"/") + b"===")
20+
21+
22+
class exceptions:
23+
class PyJWTError(Exception):
24+
pass
25+
26+
class InvalidTokenError(PyJWTError):
27+
pass
28+
29+
class InvalidAlgorithmError(PyJWTError):
30+
pass
31+
32+
class InvalidSignatureError(PyJWTError):
33+
pass
34+
35+
class ExpiredTokenError(PyJWTError):
36+
pass
37+
38+
39+
def encode(payload, key, algorithm="HS256"):
40+
if algorithm != "HS256":
41+
raise exceptions.InvalidAlgorithmError()
42+
43+
if isinstance(key, str):
44+
key = key.encode()
45+
header = _to_b64url(json.dumps({"typ": "JWT", "alg": algorithm}).encode())
46+
payload = _to_b64url(json.dumps(payload).encode())
47+
signature = _to_b64url(hmac.new(key, header + b"." + payload, hashlib.sha256).digest())
48+
return (header + b"." + payload + b"." + signature).decode()
49+
50+
51+
def decode(token, key, algorithms=["HS256"]):
52+
if "HS256" not in algorithms:
53+
raise exceptions.InvalidAlgorithmError()
54+
55+
parts = token.encode().split(b".")
56+
if len(parts) != 3:
57+
raise exceptions.InvalidTokenError()
58+
59+
header = json.loads(_from_b64url(parts[0]).decode())
60+
payload = json.loads(_from_b64url(parts[1]).decode())
61+
signature = _from_b64url(parts[2])
62+
63+
if header["alg"] not in algorithms or header["alg"] != "HS256":
64+
raise exceptions.InvalidAlgorithmError()
65+
66+
if isinstance(key, str):
67+
key = key.encode()
68+
calculated_signature = hmac.new(key, parts[0] + b"." + parts[1], hashlib.sha256).digest()
69+
if signature != calculated_signature:
70+
raise exceptions.InvalidSignatureError()
71+
72+
if "exp" in payload:
73+
if time() > payload["exp"]:
74+
raise exceptions.ExpiredTokenError()
75+
76+
return payload

python-stdlib/hashlib/hashlib/__init__.py

+4-3
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,11 @@
66

77
def init():
88
for i in ("sha1", "sha224", "sha256", "sha384", "sha512"):
9-
c = getattr(uhashlib, i, None)
10-
if not c:
9+
try:
1110
c = __import__("_" + i, None, None, (), 1)
12-
c = getattr(c, i)
11+
except ImportError:
12+
c = uhashlib
13+
c = getattr(c, i, None)
1314
globals()[i] = c
1415

1516

0 commit comments

Comments
 (0)