pensenova-verify 1.0.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.
- pensenova_verify-1.0.0/NOTICE +6 -0
- pensenova_verify-1.0.0/PKG-INFO +40 -0
- pensenova_verify-1.0.0/README.md +18 -0
- pensenova_verify-1.0.0/pensenova_verify/__init__.py +46 -0
- pensenova_verify-1.0.0/pensenova_verify/__main__.py +2 -0
- pensenova_verify-1.0.0/pensenova_verify/cli.py +13 -0
- pensenova_verify-1.0.0/pensenova_verify.egg-info/PKG-INFO +40 -0
- pensenova_verify-1.0.0/pensenova_verify.egg-info/SOURCES.txt +12 -0
- pensenova_verify-1.0.0/pensenova_verify.egg-info/dependency_links.txt +1 -0
- pensenova_verify-1.0.0/pensenova_verify.egg-info/entry_points.txt +2 -0
- pensenova_verify-1.0.0/pensenova_verify.egg-info/requires.txt +1 -0
- pensenova_verify-1.0.0/pensenova_verify.egg-info/top_level.txt +1 -0
- pensenova_verify-1.0.0/pyproject.toml +38 -0
- pensenova_verify-1.0.0/setup.cfg +4 -0
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: pensenova-verify
|
|
3
|
+
Version: 1.0.0
|
|
4
|
+
Summary: Independent, local verification of Pensenova conformity seals (Ed25519).
|
|
5
|
+
Author-email: Pensenova <partners@pensenova.com>
|
|
6
|
+
Project-URL: Homepage, https://safety.pensenova.com
|
|
7
|
+
Keywords: robotics,safety,compliance,certification,ed25519,verification
|
|
8
|
+
Classifier: Development Status :: 5 - Production/Stable
|
|
9
|
+
Classifier: Intended Audience :: Developers
|
|
10
|
+
Classifier: License :: OSI Approved :: Apache Software License
|
|
11
|
+
Classifier: Programming Language :: Python :: 3
|
|
12
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
13
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
15
|
+
Classifier: Operating System :: OS Independent
|
|
16
|
+
Classifier: Topic :: Security :: Cryptography
|
|
17
|
+
Requires-Python: >=3.10
|
|
18
|
+
Description-Content-Type: text/markdown
|
|
19
|
+
License-File: NOTICE
|
|
20
|
+
Requires-Dist: cryptography>=42.0
|
|
21
|
+
Dynamic: license-file
|
|
22
|
+
|
|
23
|
+
# pensenova-verify
|
|
24
|
+
|
|
25
|
+
Verificação local e independente de selos de conformidade Pensenova.
|
|
26
|
+
Confere a assinatura Ed25519 usando apenas a chave pública publicada — sem
|
|
27
|
+
depender de nenhum servidor da Pensenova.
|
|
28
|
+
|
|
29
|
+
## Instalação
|
|
30
|
+
pip install pensenova-verify
|
|
31
|
+
|
|
32
|
+
## Uso (Python)
|
|
33
|
+
from pensenova_verify import verify_seal, fetch_jwks
|
|
34
|
+
ok, motivo = verify_seal(seal, fetch_jwks())
|
|
35
|
+
|
|
36
|
+
## Uso (linha de comando)
|
|
37
|
+
pensenova-verify selo.json
|
|
38
|
+
|
|
39
|
+
Verificar != certificar: qualquer um verifica; só a Pensenova emite selos
|
|
40
|
+
válidos. Licença Apache-2.0. Contato: partners@pensenova.com
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
# pensenova-verify
|
|
2
|
+
|
|
3
|
+
Verificação local e independente de selos de conformidade Pensenova.
|
|
4
|
+
Confere a assinatura Ed25519 usando apenas a chave pública publicada — sem
|
|
5
|
+
depender de nenhum servidor da Pensenova.
|
|
6
|
+
|
|
7
|
+
## Instalação
|
|
8
|
+
pip install pensenova-verify
|
|
9
|
+
|
|
10
|
+
## Uso (Python)
|
|
11
|
+
from pensenova_verify import verify_seal, fetch_jwks
|
|
12
|
+
ok, motivo = verify_seal(seal, fetch_jwks())
|
|
13
|
+
|
|
14
|
+
## Uso (linha de comando)
|
|
15
|
+
pensenova-verify selo.json
|
|
16
|
+
|
|
17
|
+
Verificar != certificar: qualquer um verifica; só a Pensenova emite selos
|
|
18
|
+
válidos. Licença Apache-2.0. Contato: partners@pensenova.com
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
"""pensenova-verify — verificação local e independente de selos Pensenova."""
|
|
2
|
+
from __future__ import annotations
|
|
3
|
+
import base64, json
|
|
4
|
+
from urllib.request import urlopen
|
|
5
|
+
from cryptography.hazmat.primitives.asymmetric.ed25519 import Ed25519PublicKey
|
|
6
|
+
from cryptography.exceptions import InvalidSignature
|
|
7
|
+
|
|
8
|
+
__version__ = "1.0.0"
|
|
9
|
+
__all__ = ["verify_seal", "canonical", "fetch_jwks", "DEFAULT_JWKS_URL", "SEAL_VERSION"]
|
|
10
|
+
SEAL_VERSION = "pensenova-seal/1"
|
|
11
|
+
DEFAULT_JWKS_URL = "https://safety.pensenova.com/.well-known/pensenova-jwks.json"
|
|
12
|
+
|
|
13
|
+
def canonical(obj) -> str:
|
|
14
|
+
if obj is None or not isinstance(obj, (dict, list)):
|
|
15
|
+
return json.dumps(obj, ensure_ascii=False)
|
|
16
|
+
if isinstance(obj, list):
|
|
17
|
+
return "[" + ",".join(canonical(v) for v in obj) + "]"
|
|
18
|
+
keys = sorted(obj.keys())
|
|
19
|
+
return "{" + ",".join(json.dumps(k, ensure_ascii=False) + ":" + canonical(obj[k]) for k in keys) + "}"
|
|
20
|
+
|
|
21
|
+
def _b64url_to_bytes(s): return base64.urlsafe_b64decode(s + "=" * (-len(s) % 4))
|
|
22
|
+
def _b64_to_bytes(s): return base64.b64decode(s)
|
|
23
|
+
|
|
24
|
+
def fetch_jwks(url: str = DEFAULT_JWKS_URL, *, timeout: float = 15) -> dict:
|
|
25
|
+
with urlopen(url, timeout=timeout) as r:
|
|
26
|
+
return json.loads(r.read().decode("utf-8"))
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
def verify_seal(seal, jwks=None):
|
|
30
|
+
if jwks is None: jwks = fetch_jwks()
|
|
31
|
+
if seal.get("seal_version") != SEAL_VERSION:
|
|
32
|
+
return False, f"seal_version desconhecido: {seal.get('seal_version')!r}"
|
|
33
|
+
fp = seal.get("authority_fingerprint"); sig_b64 = seal.get("signature"); payload = seal.get("payload")
|
|
34
|
+
if not fp or not sig_b64 or payload is None:
|
|
35
|
+
return False, "selo incompleto (falta fingerprint, signature ou payload)"
|
|
36
|
+
jwk = next((k for k in jwks.get("keys", []) if k.get("kid") == fp), None)
|
|
37
|
+
if jwk is None:
|
|
38
|
+
return False, f"nenhuma chave publica com kid={fp!r} no JWKS"
|
|
39
|
+
try:
|
|
40
|
+
pub = Ed25519PublicKey.from_public_bytes(_b64url_to_bytes(jwk["x"]))
|
|
41
|
+
pub.verify(_b64_to_bytes(sig_b64), canonical(payload).encode("utf-8"))
|
|
42
|
+
except InvalidSignature:
|
|
43
|
+
return False, "assinatura invalida (selo adulterado ou chave errada)"
|
|
44
|
+
except Exception as e:
|
|
45
|
+
return False, f"erro ao verificar: {e}"
|
|
46
|
+
return True, "valido"
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import argparse, json, sys
|
|
2
|
+
from . import verify_seal, fetch_jwks, DEFAULT_JWKS_URL, __version__
|
|
3
|
+
def main() -> None:
|
|
4
|
+
ap = argparse.ArgumentParser(prog="pensenova-verify",
|
|
5
|
+
description="Verifica um selo de conformidade Pensenova (Ed25519), localmente.")
|
|
6
|
+
ap.add_argument("seal", nargs="?", default="-", help="arquivo JSON do selo (ou '-' para stdin)")
|
|
7
|
+
ap.add_argument("--jwks", default=DEFAULT_JWKS_URL, help="URL do JWKS")
|
|
8
|
+
ap.add_argument("--version", action="version", version=f"pensenova-verify {__version__}")
|
|
9
|
+
a = ap.parse_args()
|
|
10
|
+
data = sys.stdin.read() if a.seal == "-" else open(a.seal, encoding="utf-8").read()
|
|
11
|
+
ok, why = verify_seal(json.loads(data), fetch_jwks(a.jwks))
|
|
12
|
+
print(("VÁLIDO" if ok else "INVÁLIDO") + f" — {why}")
|
|
13
|
+
sys.exit(0 if ok else 1)
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: pensenova-verify
|
|
3
|
+
Version: 1.0.0
|
|
4
|
+
Summary: Independent, local verification of Pensenova conformity seals (Ed25519).
|
|
5
|
+
Author-email: Pensenova <partners@pensenova.com>
|
|
6
|
+
Project-URL: Homepage, https://safety.pensenova.com
|
|
7
|
+
Keywords: robotics,safety,compliance,certification,ed25519,verification
|
|
8
|
+
Classifier: Development Status :: 5 - Production/Stable
|
|
9
|
+
Classifier: Intended Audience :: Developers
|
|
10
|
+
Classifier: License :: OSI Approved :: Apache Software License
|
|
11
|
+
Classifier: Programming Language :: Python :: 3
|
|
12
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
13
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
15
|
+
Classifier: Operating System :: OS Independent
|
|
16
|
+
Classifier: Topic :: Security :: Cryptography
|
|
17
|
+
Requires-Python: >=3.10
|
|
18
|
+
Description-Content-Type: text/markdown
|
|
19
|
+
License-File: NOTICE
|
|
20
|
+
Requires-Dist: cryptography>=42.0
|
|
21
|
+
Dynamic: license-file
|
|
22
|
+
|
|
23
|
+
# pensenova-verify
|
|
24
|
+
|
|
25
|
+
Verificação local e independente de selos de conformidade Pensenova.
|
|
26
|
+
Confere a assinatura Ed25519 usando apenas a chave pública publicada — sem
|
|
27
|
+
depender de nenhum servidor da Pensenova.
|
|
28
|
+
|
|
29
|
+
## Instalação
|
|
30
|
+
pip install pensenova-verify
|
|
31
|
+
|
|
32
|
+
## Uso (Python)
|
|
33
|
+
from pensenova_verify import verify_seal, fetch_jwks
|
|
34
|
+
ok, motivo = verify_seal(seal, fetch_jwks())
|
|
35
|
+
|
|
36
|
+
## Uso (linha de comando)
|
|
37
|
+
pensenova-verify selo.json
|
|
38
|
+
|
|
39
|
+
Verificar != certificar: qualquer um verifica; só a Pensenova emite selos
|
|
40
|
+
válidos. Licença Apache-2.0. Contato: partners@pensenova.com
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
NOTICE
|
|
2
|
+
README.md
|
|
3
|
+
pyproject.toml
|
|
4
|
+
pensenova_verify/__init__.py
|
|
5
|
+
pensenova_verify/__main__.py
|
|
6
|
+
pensenova_verify/cli.py
|
|
7
|
+
pensenova_verify.egg-info/PKG-INFO
|
|
8
|
+
pensenova_verify.egg-info/SOURCES.txt
|
|
9
|
+
pensenova_verify.egg-info/dependency_links.txt
|
|
10
|
+
pensenova_verify.egg-info/entry_points.txt
|
|
11
|
+
pensenova_verify.egg-info/requires.txt
|
|
12
|
+
pensenova_verify.egg-info/top_level.txt
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
cryptography>=42.0
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
pensenova_verify
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["setuptools>=68", "wheel"]
|
|
3
|
+
build-backend = "setuptools.build_meta"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "pensenova-verify"
|
|
7
|
+
dynamic = ["version"]
|
|
8
|
+
description = "Independent, local verification of Pensenova conformity seals (Ed25519)."
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
requires-python = ">=3.10"
|
|
11
|
+
license = { file = "LICENSE" }
|
|
12
|
+
authors = [{ name = "Pensenova", email = "partners@pensenova.com" }]
|
|
13
|
+
keywords = ["robotics", "safety", "compliance", "certification", "ed25519", "verification"]
|
|
14
|
+
classifiers = [
|
|
15
|
+
"Development Status :: 5 - Production/Stable",
|
|
16
|
+
"Intended Audience :: Developers",
|
|
17
|
+
"License :: OSI Approved :: Apache Software License",
|
|
18
|
+
"Programming Language :: Python :: 3",
|
|
19
|
+
"Programming Language :: Python :: 3.10",
|
|
20
|
+
"Programming Language :: Python :: 3.11",
|
|
21
|
+
"Programming Language :: Python :: 3.12",
|
|
22
|
+
"Operating System :: OS Independent",
|
|
23
|
+
"Topic :: Security :: Cryptography",
|
|
24
|
+
]
|
|
25
|
+
dependencies = ["cryptography>=42.0"]
|
|
26
|
+
|
|
27
|
+
[project.scripts]
|
|
28
|
+
pensenova-verify = "pensenova_verify.cli:main"
|
|
29
|
+
|
|
30
|
+
[project.urls]
|
|
31
|
+
Homepage = "https://safety.pensenova.com"
|
|
32
|
+
|
|
33
|
+
[tool.setuptools.dynamic]
|
|
34
|
+
version = { attr = "pensenova_verify.__version__" }
|
|
35
|
+
|
|
36
|
+
[tool.setuptools.packages.find]
|
|
37
|
+
where = ["."]
|
|
38
|
+
include = ["pensenova_verify*"]
|