edadometro / dev_certs.py
chechoguz's picture
Publicar demo Edadómetro en Hugging Face Spaces
c1fed6e
Raw History Blame Contribute Delete
2.52 kB
"""Certificado HTTPS de desarrollo (autofirmado) para cámara en red local."""
from __future__ import annotations
import datetime
import ipaddress
import socket
from pathlib import Path
from cryptography import x509
from cryptography.hazmat.primitives import hashes, serialization
from cryptography.hazmat.primitives.asymmetric import rsa
from cryptography.x509.oid import NameOID
def local_ip() -> str | None:
try:
with socket.socket(socket.AF_INET, socket.SOCK_DGRAM) as s:
s.connect(("8.8.8.8", 80))
return s.getsockname()[0]
except OSError:
return None
def ensure_dev_certs(cert_dir: Path) -> tuple[Path, Path]:
cert_dir.mkdir(parents=True, exist_ok=True)
cert_path = cert_dir / "dev.pem"
key_path = cert_dir / "dev-key.pem"
marker = cert_dir / ".ip"
ip = local_ip()
cert_version = "2"
cached = marker.read_text(encoding="utf-8").strip() if marker.exists() else ""
fingerprint = f"{ip or ''}|{cert_version}"
if cert_path.exists() and key_path.exists() and cached == fingerprint:
return cert_path, key_path
key = rsa.generate_private_key(public_exponent=65537, key_size=2048)
subject = issuer = x509.Name(
[
x509.NameAttribute(NameOID.ORGANIZATION_NAME, "Edadometro Dev"),
x509.NameAttribute(NameOID.COMMON_NAME, "localhost"),
]
)
san: list[x509.GeneralName] = [
x509.DNSName("localhost"),
x509.IPAddress(ipaddress.IPv4Address("127.0.0.1")),
x509.IPAddress(ipaddress.IPv6Address("::1")),
]
if ip:
san.append(x509.IPAddress(ipaddress.IPv4Address(ip)))
now = datetime.datetime.now(datetime.timezone.utc)
cert = (
x509.CertificateBuilder()
.subject_name(subject)
.issuer_name(issuer)
.public_key(key.public_key())
.serial_number(x509.random_serial_number())
.not_valid_before(now)
.not_valid_after(now + datetime.timedelta(days=365))
.add_extension(x509.SubjectAlternativeName(san), critical=False)
.sign(key, hashes.SHA256())
)
key_path.write_bytes(
key.private_bytes(
encoding=serialization.Encoding.PEM,
format=serialization.PrivateFormat.TraditionalOpenSSL,
encryption_algorithm=serialization.NoEncryption(),
)
)
cert_path.write_bytes(cert.public_bytes(serialization.Encoding.PEM))
marker.write_text(fingerprint, encoding="utf-8")
return cert_path, key_path