"""Client VPN Profile model for user/technician VPN connections.""" 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 ClientVPNProfileStatus(str, PyEnum): """Client VPN Profile status.""" PENDING = "pending" # Certificate being generated ACTIVE = "active" # Ready to use EXPIRED = "expired" # Certificate expired REVOKED = "revoked" # Certificate revoked class ClientVPNProfile(Base): """VPN Profile for a user/technician to connect to the VPN server.""" __tablename__ = "client_vpn_profiles" id = Column(Integer, primary_key=True, index=True) user_id = Column(Integer, ForeignKey("users.id"), nullable=False) vpn_server_id = Column(Integer, ForeignKey("vpn_servers.id"), nullable=False) ca_id = Column(Integer, ForeignKey("certificate_authorities.id"), nullable=False) # Certificate data cert_cn = Column(String(255), nullable=False, unique=True) # Common Name client_cert = Column(Text, nullable=True) # Client certificate PEM client_key = Column(Text, nullable=True) # Client private key PEM # Status status = Column(Enum(ClientVPNProfileStatus), default=ClientVPNProfileStatus.PENDING) is_active = Column(Boolean, default=True) # Validity valid_from = Column(DateTime, nullable=True) valid_until = Column(DateTime, nullable=True) # VPN IP assigned (updated when connected) vpn_ip = Column(String(15), nullable=True) # Tracking last_connection = Column(DateTime, nullable=True) created_at = Column(DateTime, default=datetime.utcnow, nullable=False) updated_at = Column(DateTime, default=datetime.utcnow, onupdate=datetime.utcnow) # Relationships user = relationship("User", back_populates="client_vpn_profile") vpn_server = relationship("VPNServer", back_populates="client_vpn_profiles") certificate_authority = relationship("CertificateAuthority", back_populates="client_vpn_profiles") def __repr__(self): return f"" @property def is_ready(self) -> bool: """Check if profile is ready for use.""" return ( self.status == ClientVPNProfileStatus.ACTIVE 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