openvpn-endpoint-server/server/app/models/client_vpn_profile.py

72 lines
2.7 KiB
Python

"""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"<ClientVPNProfile(id={self.id}, user_id={self.user_id}, cert_cn='{self.cert_cn}')>"
@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