jamlib 3.0.0rc2__tar.gz → 3.1.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {jamlib-3.0.0rc2/src/jamlib.egg-info → jamlib-3.1.0}/PKG-INFO +8 -7
- {jamlib-3.0.0rc2 → jamlib-3.1.0}/pyproject.toml +20 -18
- {jamlib-3.0.0rc2 → jamlib-3.1.0}/src/jam/__init__.py +2 -2
- jamlib-3.1.0/src/jam/cli/__init__.py +7 -0
- jamlib-3.1.0/src/jam/cli/cli.py +27 -0
- jamlib-3.1.0/src/jam/cli/commands/__init__.py +5 -0
- jamlib-3.1.0/src/jam/cli/commands/keys.py +103 -0
- jamlib-3.1.0/src/jam/cli/commands/password.py +53 -0
- {jamlib-3.0.0rc2 → jamlib-3.1.0}/src/jam/ext/litestar/middleware.py +4 -0
- {jamlib-3.0.0rc2 → jamlib-3.1.0}/src/jam/ext/litestar/plugins.py +6 -0
- {jamlib-3.0.0rc2 → jamlib-3.1.0}/src/jam/ext/starlette/backends.py +7 -1
- {jamlib-3.0.0rc2 → jamlib-3.1.0}/src/jam/jwt/lists/__base__.py +4 -4
- {jamlib-3.0.0rc2 → jamlib-3.1.0/src/jamlib.egg-info}/PKG-INFO +8 -7
- {jamlib-3.0.0rc2 → jamlib-3.1.0}/src/jamlib.egg-info/SOURCES.txt +6 -0
- jamlib-3.1.0/src/jamlib.egg-info/entry_points.txt +2 -0
- {jamlib-3.0.0rc2 → jamlib-3.1.0}/src/jamlib.egg-info/requires.txt +8 -5
- {jamlib-3.0.0rc2 → jamlib-3.1.0}/LICENSE.md +0 -0
- {jamlib-3.0.0rc2 → jamlib-3.1.0}/README.md +0 -0
- {jamlib-3.0.0rc2 → jamlib-3.1.0}/setup.cfg +0 -0
- {jamlib-3.0.0rc2 → jamlib-3.1.0}/src/jam/__base__.py +0 -0
- {jamlib-3.0.0rc2 → jamlib-3.1.0}/src/jam/__base_encoder__.py +0 -0
- {jamlib-3.0.0rc2 → jamlib-3.1.0}/src/jam/__deprecated__.py +0 -0
- {jamlib-3.0.0rc2 → jamlib-3.1.0}/src/jam/aio/__base__.py +0 -0
- {jamlib-3.0.0rc2 → jamlib-3.1.0}/src/jam/aio/__init__.py +0 -0
- {jamlib-3.0.0rc2 → jamlib-3.1.0}/src/jam/aio/instance.py +0 -0
- {jamlib-3.0.0rc2 → jamlib-3.1.0}/src/jam/aio/jwt/__init__.py +0 -0
- {jamlib-3.0.0rc2 → jamlib-3.1.0}/src/jam/aio/oauth2/__base__.py +0 -0
- {jamlib-3.0.0rc2 → jamlib-3.1.0}/src/jam/aio/oauth2/__init__.py +0 -0
- {jamlib-3.0.0rc2 → jamlib-3.1.0}/src/jam/aio/oauth2/builtin/__init__.py +0 -0
- {jamlib-3.0.0rc2 → jamlib-3.1.0}/src/jam/aio/oauth2/builtin/github.py +0 -0
- {jamlib-3.0.0rc2 → jamlib-3.1.0}/src/jam/aio/oauth2/builtin/gitlab.py +0 -0
- {jamlib-3.0.0rc2 → jamlib-3.1.0}/src/jam/aio/oauth2/builtin/google.py +0 -0
- {jamlib-3.0.0rc2 → jamlib-3.1.0}/src/jam/aio/oauth2/builtin/yandex.py +0 -0
- {jamlib-3.0.0rc2 → jamlib-3.1.0}/src/jam/aio/oauth2/client.py +0 -0
- {jamlib-3.0.0rc2 → jamlib-3.1.0}/src/jam/aio/sessions/__base__.py +0 -0
- {jamlib-3.0.0rc2 → jamlib-3.1.0}/src/jam/aio/sessions/__init__.py +0 -0
- {jamlib-3.0.0rc2 → jamlib-3.1.0}/src/jam/aio/sessions/json.py +0 -0
- {jamlib-3.0.0rc2 → jamlib-3.1.0}/src/jam/aio/sessions/redis.py +0 -0
- {jamlib-3.0.0rc2 → jamlib-3.1.0}/src/jam/encoders.py +0 -0
- {jamlib-3.0.0rc2 → jamlib-3.1.0}/src/jam/exceptions/__init__.py +0 -0
- {jamlib-3.0.0rc2 → jamlib-3.1.0}/src/jam/exceptions/base.py +0 -0
- {jamlib-3.0.0rc2 → jamlib-3.1.0}/src/jam/exceptions/jwt.py +0 -0
- {jamlib-3.0.0rc2 → jamlib-3.1.0}/src/jam/exceptions/oauth2.py +0 -0
- {jamlib-3.0.0rc2 → jamlib-3.1.0}/src/jam/exceptions/paseto.py +0 -0
- {jamlib-3.0.0rc2 → jamlib-3.1.0}/src/jam/exceptions/plugins.py +0 -0
- {jamlib-3.0.0rc2 → jamlib-3.1.0}/src/jam/exceptions/sessions.py +0 -0
- {jamlib-3.0.0rc2 → jamlib-3.1.0}/src/jam/ext/__init__.py +0 -0
- {jamlib-3.0.0rc2 → jamlib-3.1.0}/src/jam/ext/fastapi/__init__.py +0 -0
- {jamlib-3.0.0rc2 → jamlib-3.1.0}/src/jam/ext/flask/__init__.py +0 -0
- {jamlib-3.0.0rc2 → jamlib-3.1.0}/src/jam/ext/flask/extensions.py +0 -0
- {jamlib-3.0.0rc2 → jamlib-3.1.0}/src/jam/ext/flask/objects.py +0 -0
- {jamlib-3.0.0rc2 → jamlib-3.1.0}/src/jam/ext/litestar/__init__.py +0 -0
- {jamlib-3.0.0rc2 → jamlib-3.1.0}/src/jam/ext/litestar/objects.py +0 -0
- {jamlib-3.0.0rc2 → jamlib-3.1.0}/src/jam/ext/starlette/__init__.py +0 -0
- {jamlib-3.0.0rc2 → jamlib-3.1.0}/src/jam/ext/starlette/objects.py +0 -0
- {jamlib-3.0.0rc2 → jamlib-3.1.0}/src/jam/instance.py +0 -0
- {jamlib-3.0.0rc2 → jamlib-3.1.0}/src/jam/jwt/__algorithms__.py +0 -0
- {jamlib-3.0.0rc2 → jamlib-3.1.0}/src/jam/jwt/__base__.py +0 -0
- {jamlib-3.0.0rc2 → jamlib-3.1.0}/src/jam/jwt/__init__.py +0 -0
- {jamlib-3.0.0rc2 → jamlib-3.1.0}/src/jam/jwt/__types__.py +0 -0
- {jamlib-3.0.0rc2 → jamlib-3.1.0}/src/jam/jwt/lists/__init__.py +0 -0
- {jamlib-3.0.0rc2 → jamlib-3.1.0}/src/jam/jwt/lists/json.py +0 -0
- {jamlib-3.0.0rc2 → jamlib-3.1.0}/src/jam/jwt/lists/redis.py +0 -0
- {jamlib-3.0.0rc2 → jamlib-3.1.0}/src/jam/jwt/module.py +0 -0
- {jamlib-3.0.0rc2 → jamlib-3.1.0}/src/jam/jwt/utils.py +0 -0
- {jamlib-3.0.0rc2 → jamlib-3.1.0}/src/jam/logger.py +0 -0
- {jamlib-3.0.0rc2 → jamlib-3.1.0}/src/jam/oauth2/__base__.py +0 -0
- {jamlib-3.0.0rc2 → jamlib-3.1.0}/src/jam/oauth2/__init__.py +0 -0
- {jamlib-3.0.0rc2 → jamlib-3.1.0}/src/jam/oauth2/builtin/__init__.py +0 -0
- {jamlib-3.0.0rc2 → jamlib-3.1.0}/src/jam/oauth2/builtin/github.py +0 -0
- {jamlib-3.0.0rc2 → jamlib-3.1.0}/src/jam/oauth2/builtin/gitlab.py +0 -0
- {jamlib-3.0.0rc2 → jamlib-3.1.0}/src/jam/oauth2/builtin/google.py +0 -0
- {jamlib-3.0.0rc2 → jamlib-3.1.0}/src/jam/oauth2/builtin/yandex.py +0 -0
- {jamlib-3.0.0rc2 → jamlib-3.1.0}/src/jam/oauth2/client.py +0 -0
- {jamlib-3.0.0rc2 → jamlib-3.1.0}/src/jam/otp/__base__.py +0 -0
- {jamlib-3.0.0rc2 → jamlib-3.1.0}/src/jam/otp/__init__.py +0 -0
- {jamlib-3.0.0rc2 → jamlib-3.1.0}/src/jam/otp/hotp.py +0 -0
- {jamlib-3.0.0rc2 → jamlib-3.1.0}/src/jam/otp/totp.py +0 -0
- {jamlib-3.0.0rc2 → jamlib-3.1.0}/src/jam/paseto/__base__.py +0 -0
- {jamlib-3.0.0rc2 → jamlib-3.1.0}/src/jam/paseto/__init__.py +0 -0
- {jamlib-3.0.0rc2 → jamlib-3.1.0}/src/jam/paseto/utils.py +0 -0
- {jamlib-3.0.0rc2 → jamlib-3.1.0}/src/jam/paseto/v1.py +0 -0
- {jamlib-3.0.0rc2 → jamlib-3.1.0}/src/jam/paseto/v2.py +0 -0
- {jamlib-3.0.0rc2 → jamlib-3.1.0}/src/jam/paseto/v3.py +0 -0
- {jamlib-3.0.0rc2 → jamlib-3.1.0}/src/jam/paseto/v4.py +0 -0
- {jamlib-3.0.0rc2 → jamlib-3.1.0}/src/jam/py.typed +0 -0
- {jamlib-3.0.0rc2 → jamlib-3.1.0}/src/jam/sessions/__base__.py +0 -0
- {jamlib-3.0.0rc2 → jamlib-3.1.0}/src/jam/sessions/__init__.py +0 -0
- {jamlib-3.0.0rc2 → jamlib-3.1.0}/src/jam/sessions/json.py +0 -0
- {jamlib-3.0.0rc2 → jamlib-3.1.0}/src/jam/sessions/redis.py +0 -0
- {jamlib-3.0.0rc2 → jamlib-3.1.0}/src/jam/tests/__init__.py +0 -0
- {jamlib-3.0.0rc2 → jamlib-3.1.0}/src/jam/tests/clients.py +0 -0
- {jamlib-3.0.0rc2 → jamlib-3.1.0}/src/jam/tests/fakers.py +0 -0
- {jamlib-3.0.0rc2 → jamlib-3.1.0}/src/jam/utils/__init__.py +0 -0
- {jamlib-3.0.0rc2 → jamlib-3.1.0}/src/jam/utils/aes.py +0 -0
- {jamlib-3.0.0rc2 → jamlib-3.1.0}/src/jam/utils/await_maybe.py +0 -0
- {jamlib-3.0.0rc2 → jamlib-3.1.0}/src/jam/utils/basic_auth.py +0 -0
- {jamlib-3.0.0rc2 → jamlib-3.1.0}/src/jam/utils/config_maker.py +0 -0
- {jamlib-3.0.0rc2 → jamlib-3.1.0}/src/jam/utils/ed.py +0 -0
- {jamlib-3.0.0rc2 → jamlib-3.1.0}/src/jam/utils/otp_keys.py +0 -0
- {jamlib-3.0.0rc2 → jamlib-3.1.0}/src/jam/utils/rsa.py +0 -0
- {jamlib-3.0.0rc2 → jamlib-3.1.0}/src/jam/utils/salt_hash.py +0 -0
- {jamlib-3.0.0rc2 → jamlib-3.1.0}/src/jam/utils/symmetric.py +0 -0
- {jamlib-3.0.0rc2 → jamlib-3.1.0}/src/jam/utils/xchacha20poly1305.py +0 -0
- {jamlib-3.0.0rc2 → jamlib-3.1.0}/src/jam/utils/xor.py +0 -0
- {jamlib-3.0.0rc2 → jamlib-3.1.0}/src/jamlib.egg-info/dependency_links.txt +0 -0
- {jamlib-3.0.0rc2 → jamlib-3.1.0}/src/jamlib.egg-info/top_level.txt +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: jamlib
|
|
3
|
-
Version: 3.0
|
|
3
|
+
Version: 3.1.0
|
|
4
4
|
Summary: Simple and universal library for authorization.
|
|
5
5
|
Author-email: Makridenko Adrian <adrianmakridenko@duck.com>, Ksenia Travnikova <kseniatravnikova@duck.com>
|
|
6
6
|
License: Apache-2.0
|
|
@@ -16,7 +16,6 @@ Classifier: Intended Audience :: Developers
|
|
|
16
16
|
Classifier: Intended Audience :: Information Technology
|
|
17
17
|
Classifier: Programming Language :: Python
|
|
18
18
|
Classifier: Programming Language :: Python :: 3
|
|
19
|
-
Classifier: Programming Language :: Python :: 3.9
|
|
20
19
|
Classifier: Programming Language :: Python :: 3.10
|
|
21
20
|
Classifier: Programming Language :: Python :: 3.11
|
|
22
21
|
Classifier: Programming Language :: Python :: 3.12
|
|
@@ -32,20 +31,22 @@ Requires-Python: >=3.10
|
|
|
32
31
|
Description-Content-Type: text/markdown
|
|
33
32
|
License-File: LICENSE.md
|
|
34
33
|
Requires-Dist: cryptography>=46.0.5
|
|
34
|
+
Provides-Extra: cli
|
|
35
|
+
Requires-Dist: click>=8.3.1; extra == "cli"
|
|
35
36
|
Provides-Extra: redis
|
|
36
|
-
Requires-Dist: redis>=
|
|
37
|
+
Requires-Dist: redis>=7.3.0; extra == "redis"
|
|
37
38
|
Provides-Extra: json
|
|
38
39
|
Requires-Dist: tinydb>=4.8.2; extra == "json"
|
|
39
40
|
Provides-Extra: yaml
|
|
40
|
-
Requires-Dist: pyyaml>=6.0.
|
|
41
|
+
Requires-Dist: pyyaml>=6.0.3; extra == "yaml"
|
|
41
42
|
Provides-Extra: toml
|
|
42
43
|
Requires-Dist: toml>=0.10.2; extra == "toml"
|
|
43
44
|
Provides-Extra: litestar
|
|
44
|
-
Requires-Dist: litestar>=2.
|
|
45
|
+
Requires-Dist: litestar>=2.21.1; extra == "litestar"
|
|
45
46
|
Provides-Extra: starlette
|
|
46
|
-
Requires-Dist: starlette>=0.
|
|
47
|
+
Requires-Dist: starlette>=0.52.1; extra == "starlette"
|
|
47
48
|
Provides-Extra: fastapi
|
|
48
|
-
Requires-Dist: fastapi>=0.
|
|
49
|
+
Requires-Dist: fastapi>=0.135.1; extra == "fastapi"
|
|
49
50
|
Provides-Extra: flask
|
|
50
51
|
Requires-Dist: flask>=3.1.2; extra == "flask"
|
|
51
52
|
Dynamic: license-file
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "jamlib"
|
|
3
|
-
version = "3.
|
|
3
|
+
version = "3.1.0"
|
|
4
4
|
description = "Simple and universal library for authorization."
|
|
5
5
|
authors = [
|
|
6
6
|
{name = "Makridenko Adrian",email = "adrianmakridenko@duck.com"},
|
|
@@ -34,7 +34,6 @@ classifiers = [
|
|
|
34
34
|
"Intended Audience :: Information Technology",
|
|
35
35
|
"Programming Language :: Python",
|
|
36
36
|
"Programming Language :: Python :: 3",
|
|
37
|
-
"Programming Language :: Python :: 3.9",
|
|
38
37
|
"Programming Language :: Python :: 3.10",
|
|
39
38
|
"Programming Language :: Python :: 3.11",
|
|
40
39
|
"Programming Language :: Python :: 3.12",
|
|
@@ -55,18 +54,22 @@ Issues = "https://github.com/lyaguxafrog/jam/issues"
|
|
|
55
54
|
Changelog = "https://github.com/lyaguxafrog/jam/blob/master/CHANGELOG.md"
|
|
56
55
|
|
|
57
56
|
|
|
57
|
+
[project.scripts]
|
|
58
|
+
jam = "jam.cli:cli"
|
|
59
|
+
|
|
58
60
|
[project.optional-dependencies]
|
|
59
|
-
|
|
61
|
+
cli=["click>=8.3.1"]
|
|
62
|
+
redis=["redis>=7.3.0"]
|
|
60
63
|
json=["tinydb>=4.8.2"]
|
|
61
|
-
yaml=["pyyaml>=6.0.
|
|
64
|
+
yaml=["pyyaml>=6.0.3"]
|
|
62
65
|
toml=["toml>=0.10.2"]
|
|
63
|
-
litestar=["litestar>=2.
|
|
64
|
-
starlette=["starlette>=0.
|
|
65
|
-
fastapi=["fastapi>=0.
|
|
66
|
+
litestar=["litestar>=2.21.1"]
|
|
67
|
+
starlette=["starlette>=0.52.1"]
|
|
68
|
+
fastapi=["fastapi>=0.135.1"]
|
|
66
69
|
flask=["flask>=3.1.2"]
|
|
67
70
|
|
|
68
71
|
[build-system]
|
|
69
|
-
requires = ["setuptools>=
|
|
72
|
+
requires = ["setuptools>=82.0.1", "wheel"]
|
|
70
73
|
build-backend = "setuptools.build_meta"
|
|
71
74
|
|
|
72
75
|
[tool.setuptools.packages.find]
|
|
@@ -75,15 +78,14 @@ include = ["jam*"]
|
|
|
75
78
|
|
|
76
79
|
[dependency-groups]
|
|
77
80
|
dev = [
|
|
78
|
-
"
|
|
79
|
-
"fakeredis>=2.
|
|
80
|
-
"icecream>=2.1.
|
|
81
|
-
"
|
|
82
|
-
"
|
|
83
|
-
"
|
|
84
|
-
"ruff>=0.11.2",
|
|
81
|
+
"click>=8.3.1",
|
|
82
|
+
"fakeredis>=2.34.1",
|
|
83
|
+
"icecream>=2.1.10",
|
|
84
|
+
"pre-commit>=4.5.1",
|
|
85
|
+
"pyrefly>=0.56.0",
|
|
86
|
+
"ruff>=0.15.6",
|
|
85
87
|
"unicecream>=0.2.1",
|
|
86
|
-
"uvicorn>=0.
|
|
88
|
+
"uvicorn>=0.41.0",
|
|
87
89
|
]
|
|
88
90
|
docs = [
|
|
89
91
|
"mkdocs>=1.6.1",
|
|
@@ -95,8 +97,8 @@ docs = [
|
|
|
95
97
|
"termynal>=0.13.0",
|
|
96
98
|
]
|
|
97
99
|
tests = [
|
|
98
|
-
"pytest>=
|
|
99
|
-
"pytest-asyncio>=1.
|
|
100
|
+
"pytest>=9.0.2",
|
|
101
|
+
"pytest-asyncio>=1.3.0",
|
|
100
102
|
"coverage>=7.13.4"
|
|
101
103
|
]
|
|
102
104
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# -*- coding: utf-8 -*-
|
|
2
2
|
|
|
3
|
-
"""JAM - Universal auth* library
|
|
3
|
+
"""JAM - Universal auth* library.
|
|
4
4
|
|
|
5
5
|
Source code: https://github.com/lyaguxafrog/jam
|
|
6
6
|
Documentation: https://jam.makridenko.ru
|
|
@@ -12,5 +12,5 @@ from jam.encoders import JsonEncoder
|
|
|
12
12
|
from jam.instance import Jam
|
|
13
13
|
|
|
14
14
|
|
|
15
|
-
__version__ = "3.0.0
|
|
15
|
+
__version__ = "3.0.0"
|
|
16
16
|
__all__ = ["Jam", "JsonEncoder", "BaseJam", "BaseEncoder"]
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
|
|
3
|
+
from importlib.metadata import version
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
try:
|
|
7
|
+
import click
|
|
8
|
+
except ImportError:
|
|
9
|
+
from jam.exceptions import JamError
|
|
10
|
+
|
|
11
|
+
raise JamError(
|
|
12
|
+
message="To use the Jam CLI, run 'pip install jamlib[cli]'.",
|
|
13
|
+
error_code="jam.cli",
|
|
14
|
+
)
|
|
15
|
+
|
|
16
|
+
from jam.cli.commands import keys, password
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
@click.group()
|
|
20
|
+
@click.version_option(version=version("jamlib"))
|
|
21
|
+
def cli() -> None:
|
|
22
|
+
"""Jam CLI - Key generation and password utilities."""
|
|
23
|
+
pass
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
cli.add_command(keys.keys)
|
|
27
|
+
cli.add_command(password.password)
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
|
|
3
|
+
import click
|
|
4
|
+
|
|
5
|
+
from jam.utils import (
|
|
6
|
+
generate_aes_key,
|
|
7
|
+
generate_ecdsa_p384_keypair,
|
|
8
|
+
generate_ed25519_keypair,
|
|
9
|
+
generate_rsa_key_pair,
|
|
10
|
+
generate_symmetric_key,
|
|
11
|
+
)
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
@click.group()
|
|
15
|
+
def keys() -> None:
|
|
16
|
+
"""Generate cryptographic keys."""
|
|
17
|
+
pass
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
@keys.command()
|
|
21
|
+
@click.option(
|
|
22
|
+
"--public-out", "-p", default="public.pem", help="Public key output file"
|
|
23
|
+
)
|
|
24
|
+
@click.option(
|
|
25
|
+
"--private-out", "-o", default="private.pem", help="Private key output file"
|
|
26
|
+
)
|
|
27
|
+
def rsa(public_out: str, private_out: str) -> None:
|
|
28
|
+
"""Generate RSA key pair."""
|
|
29
|
+
key_pair = generate_rsa_key_pair()
|
|
30
|
+
|
|
31
|
+
with open(private_out, "w") as f:
|
|
32
|
+
f.write(key_pair["private"])
|
|
33
|
+
with open(public_out, "w") as f:
|
|
34
|
+
f.write(key_pair["public"])
|
|
35
|
+
|
|
36
|
+
click.echo(f"RSA key pair generated: {private_out}, {public_out}")
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
@keys.command()
|
|
40
|
+
@click.option(
|
|
41
|
+
"--public-out", "-p", default="public.pem", help="Public key output file"
|
|
42
|
+
)
|
|
43
|
+
@click.option(
|
|
44
|
+
"--private-out", "-o", default="private.pem", help="Private key output file"
|
|
45
|
+
)
|
|
46
|
+
def ed25519(public_out: str, private_out: str) -> None:
|
|
47
|
+
"""Generate Ed25519 key pair."""
|
|
48
|
+
key_pair = generate_ed25519_keypair()
|
|
49
|
+
|
|
50
|
+
with open(private_out, "w") as f:
|
|
51
|
+
f.write(key_pair["private"])
|
|
52
|
+
with open(public_out, "w") as f:
|
|
53
|
+
f.write(key_pair["public"])
|
|
54
|
+
|
|
55
|
+
click.echo(f"Ed25519 key pair generated: {private_out}, {public_out}")
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
@keys.command()
|
|
59
|
+
@click.option(
|
|
60
|
+
"--public-out", "-p", default="public.pem", help="Public key output file"
|
|
61
|
+
)
|
|
62
|
+
@click.option(
|
|
63
|
+
"--private-out", "-o", default="private.pem", help="Private key output file"
|
|
64
|
+
)
|
|
65
|
+
def ecdsa(public_out: str, private_out: str) -> None:
|
|
66
|
+
"""Generate ECDSA P-384 key pair."""
|
|
67
|
+
key_pair = generate_ecdsa_p384_keypair()
|
|
68
|
+
|
|
69
|
+
with open(private_out, "w") as f:
|
|
70
|
+
f.write(key_pair["private"])
|
|
71
|
+
with open(public_out, "w") as f:
|
|
72
|
+
f.write(key_pair["public"])
|
|
73
|
+
|
|
74
|
+
click.echo(f"ECDSA P-384 key pair generated: {private_out}, {public_out}")
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
@keys.command()
|
|
78
|
+
@click.option("--out", "-o", default="aes.key", help="AES key output file")
|
|
79
|
+
def aes(out: str) -> None:
|
|
80
|
+
"""Generate AES key."""
|
|
81
|
+
key = generate_aes_key()
|
|
82
|
+
|
|
83
|
+
with open(out, "wb") as f:
|
|
84
|
+
f.write(key)
|
|
85
|
+
|
|
86
|
+
click.echo(f"AES key generated: {out}")
|
|
87
|
+
|
|
88
|
+
|
|
89
|
+
@keys.command()
|
|
90
|
+
@click.option(
|
|
91
|
+
"--out", "-o", default="symmetric.key", help="Symmetric key output file"
|
|
92
|
+
)
|
|
93
|
+
@click.option(
|
|
94
|
+
"--bytes", "-b", default=32, help="Key size in bytes (default: 32)"
|
|
95
|
+
)
|
|
96
|
+
def symmetric(out: str, bytes: int) -> None:
|
|
97
|
+
"""Generate symmetric key."""
|
|
98
|
+
key = generate_symmetric_key(bytes)
|
|
99
|
+
|
|
100
|
+
with open(out, "w") as f:
|
|
101
|
+
f.write(key)
|
|
102
|
+
|
|
103
|
+
click.echo(f"Symmetric key generated: {out} ({bytes} bytes)")
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
|
|
3
|
+
import click
|
|
4
|
+
|
|
5
|
+
from jam.utils import (
|
|
6
|
+
check_password,
|
|
7
|
+
deserialize_hash,
|
|
8
|
+
hash_password,
|
|
9
|
+
serialize_hash,
|
|
10
|
+
)
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
@click.group()
|
|
14
|
+
def password() -> None:
|
|
15
|
+
"""Password hashing and verification utilities."""
|
|
16
|
+
pass
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
@password.command()
|
|
20
|
+
@click.argument("password")
|
|
21
|
+
@click.option("--out", "-o", default=None, help="Output file (default: stdout)")
|
|
22
|
+
def hash(password: str, out: str | None) -> None:
|
|
23
|
+
"""Hash a password."""
|
|
24
|
+
salt, hash_hex = hash_password(password)
|
|
25
|
+
serialized = serialize_hash(salt, hash_hex)
|
|
26
|
+
|
|
27
|
+
if out:
|
|
28
|
+
with open(out, "w") as f:
|
|
29
|
+
f.write(serialized)
|
|
30
|
+
click.echo(f"Password hash written to: {out}")
|
|
31
|
+
else:
|
|
32
|
+
click.echo(serialized)
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
@password.command()
|
|
36
|
+
@click.option(
|
|
37
|
+
"--hash",
|
|
38
|
+
"-h",
|
|
39
|
+
required=True,
|
|
40
|
+
help="Hash to verify against (format: salt$hash)",
|
|
41
|
+
)
|
|
42
|
+
def verify(hash: str) -> None:
|
|
43
|
+
"""Verify a password against a hash."""
|
|
44
|
+
salt_hex, hash_hex = deserialize_hash(hash)
|
|
45
|
+
|
|
46
|
+
password = click.prompt("Password", hide_input=True)
|
|
47
|
+
|
|
48
|
+
result = check_password(password, salt_hex, hash_hex)
|
|
49
|
+
if result:
|
|
50
|
+
click.echo("✓ Password matches")
|
|
51
|
+
else:
|
|
52
|
+
click.echo("✗ Password does not match")
|
|
53
|
+
raise click.Abort()
|
|
@@ -21,11 +21,15 @@ class BaseMiddleware(AbstractAuthenticationMiddleware):
|
|
|
21
21
|
AUTH_MODULE: Callable
|
|
22
22
|
HEADER_NAME: str | None
|
|
23
23
|
COOKIE_NAME: str | None
|
|
24
|
+
BEARER: bool = False
|
|
24
25
|
USER: type[BaseUser]
|
|
25
26
|
|
|
26
27
|
def _get_auth_token(self, connection: ASGIConnection) -> str | None:
|
|
27
28
|
if self.HEADER_NAME:
|
|
28
29
|
token = connection.headers.get(self.HEADER_NAME, None)
|
|
30
|
+
if self.BEARER and token:
|
|
31
|
+
token = token.split(" ")[1]
|
|
32
|
+
return token
|
|
29
33
|
elif self.COOKIE_NAME:
|
|
30
34
|
token = connection.cookies.get(self.COOKIE_NAME, None)
|
|
31
35
|
else:
|
|
@@ -39,6 +39,7 @@ class BasePlugin(InitPlugin):
|
|
|
39
39
|
pointer: str = GENERIC_POINTER,
|
|
40
40
|
cookie_name: str | None = None,
|
|
41
41
|
header_name: str | None = None,
|
|
42
|
+
bearer: bool = False,
|
|
42
43
|
middleware: bool = True,
|
|
43
44
|
user: type[BaseUser] | None = None,
|
|
44
45
|
**kwargs,
|
|
@@ -50,6 +51,7 @@ class BasePlugin(InitPlugin):
|
|
|
50
51
|
pointer (str): Config pointer
|
|
51
52
|
cookie_name (str | None): Cookie name to read token
|
|
52
53
|
header_name (str | None): Header name to read token
|
|
54
|
+
bearer (bool): Use bearer prefix for token (e.g. "Bearer ")
|
|
53
55
|
middleware (bool): Use middleware?
|
|
54
56
|
user (type[BaseUser]): User for request state. See: DOCUMENTATION
|
|
55
57
|
**kwargs: Config arguments if config=None
|
|
@@ -84,6 +86,7 @@ class BasePlugin(InitPlugin):
|
|
|
84
86
|
_middleware.HEADER_NAME = header_name
|
|
85
87
|
_middleware.AUTH_MODULE = self._auth
|
|
86
88
|
_middleware.USER = user # type: ignore
|
|
89
|
+
_middleware.BEARER = bearer
|
|
87
90
|
self._middleware = _middleware
|
|
88
91
|
|
|
89
92
|
def on_app_init(self, app_config: AppConfig) -> AppConfig: # noqa
|
|
@@ -111,6 +114,7 @@ class JWTPlugin(BasePlugin):
|
|
|
111
114
|
cookie_name: str | None = None,
|
|
112
115
|
header_name: str | None = None,
|
|
113
116
|
middleware: bool = True,
|
|
117
|
+
bearer: bool = False,
|
|
114
118
|
use_list: bool = False,
|
|
115
119
|
user: type[BaseUser] | None = None,
|
|
116
120
|
**kwargs,
|
|
@@ -123,6 +127,7 @@ class JWTPlugin(BasePlugin):
|
|
|
123
127
|
cookie_name (str | None): Cookie name to read token
|
|
124
128
|
header_name (str | None): Header name to read token
|
|
125
129
|
middleware (bool): Use middleware?
|
|
130
|
+
bearer (bool): Use bearer prefix for token (e.g. "Bearer ")
|
|
126
131
|
use_list (bool): Use token list for authentication?
|
|
127
132
|
user (type[BaseUser]): User for request state. See: DOCUMENTATION
|
|
128
133
|
**kwargs: Config arguments if config=None
|
|
@@ -133,6 +138,7 @@ class JWTPlugin(BasePlugin):
|
|
|
133
138
|
cookie_name=cookie_name,
|
|
134
139
|
header_name=header_name,
|
|
135
140
|
middleware=middleware,
|
|
141
|
+
bearer=bearer,
|
|
136
142
|
user=user,
|
|
137
143
|
**kwargs,
|
|
138
144
|
)
|
|
@@ -31,6 +31,7 @@ class BaseBackend(AuthenticationBackend):
|
|
|
31
31
|
pointer: str = GENERIC_POINTER,
|
|
32
32
|
cookie_name: str | None = None,
|
|
33
33
|
header_name: str | None = None,
|
|
34
|
+
bearer: bool = False,
|
|
34
35
|
user: type[BaseUser] = SimpleUser,
|
|
35
36
|
**kwargs,
|
|
36
37
|
) -> None:
|
|
@@ -44,6 +45,7 @@ class BaseBackend(AuthenticationBackend):
|
|
|
44
45
|
)
|
|
45
46
|
self._cookie_name = cookie_name
|
|
46
47
|
self._header_name = header_name
|
|
48
|
+
self._bearer = bearer
|
|
47
49
|
self._user = user
|
|
48
50
|
self._config_setup(config, pointer, kwargs)
|
|
49
51
|
|
|
@@ -53,7 +55,11 @@ class BaseBackend(AuthenticationBackend):
|
|
|
53
55
|
elif self._header_name:
|
|
54
56
|
token_bear = connection.headers.get(self._header_name, None)
|
|
55
57
|
if token_bear:
|
|
56
|
-
token =
|
|
58
|
+
token = (
|
|
59
|
+
token_bear.split("Bearer ")[1]
|
|
60
|
+
if self._bearer
|
|
61
|
+
else token_bear
|
|
62
|
+
) # noqa: E701
|
|
57
63
|
else:
|
|
58
64
|
token = None # noqa: E701
|
|
59
65
|
else:
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# -*- coding: utf-8 -*-
|
|
2
2
|
|
|
3
3
|
from abc import ABC, abstractmethod
|
|
4
|
-
from typing import
|
|
4
|
+
from typing import Literal
|
|
5
5
|
|
|
6
6
|
|
|
7
7
|
class BaseJWTList(ABC):
|
|
@@ -12,16 +12,16 @@ class BaseJWTList(ABC):
|
|
|
12
12
|
self.__list_type__ = list_type
|
|
13
13
|
|
|
14
14
|
@abstractmethod
|
|
15
|
-
def add(self, token: str) ->
|
|
15
|
+
def add(self, token: str) -> None:
|
|
16
16
|
"""Method for adding token to list."""
|
|
17
17
|
raise NotImplementedError
|
|
18
18
|
|
|
19
19
|
@abstractmethod
|
|
20
|
-
def check(self, token: str) ->
|
|
20
|
+
def check(self, token: str) -> bool:
|
|
21
21
|
"""Method for checking if a token is present in the list."""
|
|
22
22
|
raise NotImplementedError
|
|
23
23
|
|
|
24
24
|
@abstractmethod
|
|
25
|
-
def delete(self, token: str) ->
|
|
25
|
+
def delete(self, token: str) -> None:
|
|
26
26
|
"""Method for removing a token from a list."""
|
|
27
27
|
raise NotImplementedError
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: jamlib
|
|
3
|
-
Version: 3.0
|
|
3
|
+
Version: 3.1.0
|
|
4
4
|
Summary: Simple and universal library for authorization.
|
|
5
5
|
Author-email: Makridenko Adrian <adrianmakridenko@duck.com>, Ksenia Travnikova <kseniatravnikova@duck.com>
|
|
6
6
|
License: Apache-2.0
|
|
@@ -16,7 +16,6 @@ Classifier: Intended Audience :: Developers
|
|
|
16
16
|
Classifier: Intended Audience :: Information Technology
|
|
17
17
|
Classifier: Programming Language :: Python
|
|
18
18
|
Classifier: Programming Language :: Python :: 3
|
|
19
|
-
Classifier: Programming Language :: Python :: 3.9
|
|
20
19
|
Classifier: Programming Language :: Python :: 3.10
|
|
21
20
|
Classifier: Programming Language :: Python :: 3.11
|
|
22
21
|
Classifier: Programming Language :: Python :: 3.12
|
|
@@ -32,20 +31,22 @@ Requires-Python: >=3.10
|
|
|
32
31
|
Description-Content-Type: text/markdown
|
|
33
32
|
License-File: LICENSE.md
|
|
34
33
|
Requires-Dist: cryptography>=46.0.5
|
|
34
|
+
Provides-Extra: cli
|
|
35
|
+
Requires-Dist: click>=8.3.1; extra == "cli"
|
|
35
36
|
Provides-Extra: redis
|
|
36
|
-
Requires-Dist: redis>=
|
|
37
|
+
Requires-Dist: redis>=7.3.0; extra == "redis"
|
|
37
38
|
Provides-Extra: json
|
|
38
39
|
Requires-Dist: tinydb>=4.8.2; extra == "json"
|
|
39
40
|
Provides-Extra: yaml
|
|
40
|
-
Requires-Dist: pyyaml>=6.0.
|
|
41
|
+
Requires-Dist: pyyaml>=6.0.3; extra == "yaml"
|
|
41
42
|
Provides-Extra: toml
|
|
42
43
|
Requires-Dist: toml>=0.10.2; extra == "toml"
|
|
43
44
|
Provides-Extra: litestar
|
|
44
|
-
Requires-Dist: litestar>=2.
|
|
45
|
+
Requires-Dist: litestar>=2.21.1; extra == "litestar"
|
|
45
46
|
Provides-Extra: starlette
|
|
46
|
-
Requires-Dist: starlette>=0.
|
|
47
|
+
Requires-Dist: starlette>=0.52.1; extra == "starlette"
|
|
47
48
|
Provides-Extra: fastapi
|
|
48
|
-
Requires-Dist: fastapi>=0.
|
|
49
|
+
Requires-Dist: fastapi>=0.135.1; extra == "fastapi"
|
|
49
50
|
Provides-Extra: flask
|
|
50
51
|
Requires-Dist: flask>=3.1.2; extra == "flask"
|
|
51
52
|
Dynamic: license-file
|
|
@@ -25,6 +25,11 @@ src/jam/aio/sessions/__base__.py
|
|
|
25
25
|
src/jam/aio/sessions/__init__.py
|
|
26
26
|
src/jam/aio/sessions/json.py
|
|
27
27
|
src/jam/aio/sessions/redis.py
|
|
28
|
+
src/jam/cli/__init__.py
|
|
29
|
+
src/jam/cli/cli.py
|
|
30
|
+
src/jam/cli/commands/__init__.py
|
|
31
|
+
src/jam/cli/commands/keys.py
|
|
32
|
+
src/jam/cli/commands/password.py
|
|
28
33
|
src/jam/exceptions/__init__.py
|
|
29
34
|
src/jam/exceptions/base.py
|
|
30
35
|
src/jam/exceptions/jwt.py
|
|
@@ -95,5 +100,6 @@ src/jam/utils/xor.py
|
|
|
95
100
|
src/jamlib.egg-info/PKG-INFO
|
|
96
101
|
src/jamlib.egg-info/SOURCES.txt
|
|
97
102
|
src/jamlib.egg-info/dependency_links.txt
|
|
103
|
+
src/jamlib.egg-info/entry_points.txt
|
|
98
104
|
src/jamlib.egg-info/requires.txt
|
|
99
105
|
src/jamlib.egg-info/top_level.txt
|
|
@@ -1,7 +1,10 @@
|
|
|
1
1
|
cryptography>=46.0.5
|
|
2
2
|
|
|
3
|
+
[cli]
|
|
4
|
+
click>=8.3.1
|
|
5
|
+
|
|
3
6
|
[fastapi]
|
|
4
|
-
fastapi>=0.
|
|
7
|
+
fastapi>=0.135.1
|
|
5
8
|
|
|
6
9
|
[flask]
|
|
7
10
|
flask>=3.1.2
|
|
@@ -10,16 +13,16 @@ flask>=3.1.2
|
|
|
10
13
|
tinydb>=4.8.2
|
|
11
14
|
|
|
12
15
|
[litestar]
|
|
13
|
-
litestar>=2.
|
|
16
|
+
litestar>=2.21.1
|
|
14
17
|
|
|
15
18
|
[redis]
|
|
16
|
-
redis>=
|
|
19
|
+
redis>=7.3.0
|
|
17
20
|
|
|
18
21
|
[starlette]
|
|
19
|
-
starlette>=0.
|
|
22
|
+
starlette>=0.52.1
|
|
20
23
|
|
|
21
24
|
[toml]
|
|
22
25
|
toml>=0.10.2
|
|
23
26
|
|
|
24
27
|
[yaml]
|
|
25
|
-
pyyaml>=6.0.
|
|
28
|
+
pyyaml>=6.0.3
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|