First Push
This commit is contained in:
@@ -0,0 +1,55 @@
|
||||
"""Ed25519 key pair generation and JWT signing for QWeather API."""
|
||||
from cryptography.hazmat.primitives.asymmetric import ed25519
|
||||
from cryptography.hazmat.primitives import serialization
|
||||
import jwt
|
||||
import time
|
||||
|
||||
|
||||
def generate_key_pair() -> tuple:
|
||||
"""Generate an Ed25519 key pair.
|
||||
|
||||
Returns:
|
||||
(private_key_pem: str, public_key_pem: str)
|
||||
"""
|
||||
private_key = ed25519.Ed25519PrivateKey.generate()
|
||||
public_key = private_key.public_key()
|
||||
|
||||
private_pem = private_key.private_bytes(
|
||||
encoding=serialization.Encoding.PEM,
|
||||
format=serialization.PrivateFormat.PKCS8,
|
||||
encryption_algorithm=serialization.NoEncryption(),
|
||||
).decode("utf-8")
|
||||
|
||||
public_pem = public_key.public_bytes(
|
||||
encoding=serialization.Encoding.PEM,
|
||||
format=serialization.PublicFormat.SubjectPublicKeyInfo,
|
||||
).decode("utf-8")
|
||||
|
||||
return private_pem, public_pem
|
||||
|
||||
|
||||
def sign_jwt(private_key_pem: str, credential_id: str, project_id: str,
|
||||
expiry_seconds: int = 3600) -> str:
|
||||
"""Sign a JWT for QWeather API authentication.
|
||||
|
||||
Args:
|
||||
private_key_pem: Ed25519 private key in PEM format.
|
||||
credential_id: QWeather credential ID (kid).
|
||||
project_id: QWeather project ID (sub).
|
||||
expiry_seconds: Token validity in seconds (max 86400 per QWeather).
|
||||
|
||||
Returns:
|
||||
Signed JWT string.
|
||||
"""
|
||||
now = int(time.time())
|
||||
payload = {
|
||||
"sub": project_id,
|
||||
"iat": now,
|
||||
"exp": now + min(expiry_seconds, 86400),
|
||||
}
|
||||
headers = {
|
||||
"alg": "EdDSA",
|
||||
"kid": credential_id,
|
||||
}
|
||||
token = jwt.encode(payload, private_key_pem, algorithm="EdDSA", headers=headers)
|
||||
return token
|
||||
Reference in New Issue
Block a user