"""VPN Profile model for gateway VPN configurations.""" from datetime import datetime from enum import Enum as PyEnum from sqlalchemy import Column, Integer, String, Boolean, DateTime, ForeignKey, Enum, Text from sqlalchemy.orm import relationship from ..database import Base class VPNProfileStatus(str, PyEnum): """VPN Profile status.""" PENDING = "pending" # Certificate being generated ACTIVE = "active" # Ready to use PROVISIONED = "provisioned" # Downloaded/deployed to gateway EXPIRED = "expired" # Certificate expired REVOKED = "revoked" # Certificate revoked class VPNProfile(Base): """VPN Profile for a gateway - links gateway to VPN server.""" __tablename__ = "vpn_profiles" id = Column(Integer, primary_key=True, index=True) gateway_id = Column(Integer, ForeignKey("gateways.id"), nullable=False) vpn_server_id = Column(Integer, ForeignKey("vpn_servers.id"), nullable=False) ca_id = Column(Integer, ForeignKey("certificate_authorities.id"), nullable=False) # Profile info name = Column(String(255), nullable=False) # e.g., "Produktion", "Fallback" description = Column(Text, nullable=True) # Certificate data cert_cn = Column(String(255), nullable=False) # Common Name client_cert = Column(Text, nullable=True) # Client certificate PEM client_key = Column(Text, nullable=True) # Client private key PEM # Priority for failover (1 = highest priority) priority = Column(Integer, default=1) # Status status = Column(Enum(VPNProfileStatus), default=VPNProfileStatus.PENDING) is_active = Column(Boolean, default=True) # Validity valid_from = Column(DateTime, nullable=True) valid_until = Column(DateTime, nullable=True) # Provisioning tracking provisioned_at = Column(DateTime, nullable=True) last_connection = Column(DateTime, nullable=True) # VPN IP assigned to this profile (if static) vpn_ip = Column(String(15), nullable=True) # Audit created_at = Column(DateTime, default=datetime.utcnow, nullable=False) updated_at = Column(DateTime, default=datetime.utcnow, onupdate=datetime.utcnow) # Relationships gateway = relationship("Gateway", back_populates="vpn_profiles") vpn_server = relationship("VPNServer", back_populates="vpn_profiles") certificate_authority = relationship("CertificateAuthority", back_populates="vpn_profiles") def __repr__(self): return f"" @property def is_ready(self) -> bool: """Check if profile is ready for provisioning.""" return ( self.status in (VPNProfileStatus.ACTIVE, VPNProfileStatus.PROVISIONED) and self.client_cert is not None and self.client_key is not None ) @property def is_expired(self) -> bool: """Check if certificate is expired.""" if self.valid_until: return datetime.utcnow() > self.valid_until return False @property def days_until_expiry(self) -> int | None: """Days until certificate expires.""" if self.valid_until: delta = self.valid_until - datetime.utcnow() return max(0, delta.days) return None