83 lines
3.5 KiB
Python
83 lines
3.5 KiB
Python
from datetime import datetime
|
|
from typing import Optional
|
|
|
|
from sqlalchemy import CheckConstraint, DateTime, ForeignKey, Integer, String, func
|
|
from sqlalchemy.orm import Mapped, mapped_column, relationship
|
|
|
|
from .base import Base
|
|
|
|
|
|
class SSHKey(Base):
|
|
"""Registry of SSH private key files stored on the server filesystem."""
|
|
|
|
__tablename__ = "ssh_keys"
|
|
|
|
id: Mapped[int] = mapped_column(Integer, primary_key=True)
|
|
name: Mapped[str] = mapped_column(String(100), nullable=False, unique=True)
|
|
path: Mapped[str] = mapped_column(String(500), nullable=False)
|
|
description: Mapped[Optional[str]] = mapped_column(String(1000), nullable=True)
|
|
created_at: Mapped[datetime] = mapped_column(
|
|
DateTime(timezone=True), server_default=func.now(), nullable=False
|
|
)
|
|
|
|
|
|
class ObjectSSHCredential(Base):
|
|
"""Ordered list of SSH credentials (password or key) for an object.
|
|
|
|
Tried in ascending priority order when connecting to hosts of this object.
|
|
type='password': username + password_enc required.
|
|
type='key': username + ssh_key_id required.
|
|
"""
|
|
|
|
__tablename__ = "object_ssh_credentials"
|
|
__table_args__ = (
|
|
CheckConstraint("type IN ('password', 'key')", name="ck_obj_ssh_cred_type"),
|
|
)
|
|
|
|
id: Mapped[int] = mapped_column(Integer, primary_key=True)
|
|
object_id: Mapped[int] = mapped_column(
|
|
Integer, ForeignKey("objects.id", ondelete="CASCADE"), nullable=False, index=True
|
|
)
|
|
type: Mapped[str] = mapped_column(String(10), nullable=False)
|
|
username: Mapped[str] = mapped_column(String(100), nullable=False)
|
|
password_enc: Mapped[Optional[str]] = mapped_column(String(500), nullable=True)
|
|
ssh_key_id: Mapped[Optional[int]] = mapped_column(
|
|
Integer, ForeignKey("ssh_keys.id", ondelete="SET NULL"), nullable=True
|
|
)
|
|
priority: Mapped[int] = mapped_column(Integer, nullable=False, default=0)
|
|
|
|
object: Mapped["Object"] = relationship("Object", back_populates="ssh_credentials")
|
|
ssh_key: Mapped[Optional["SSHKey"]] = relationship("SSHKey")
|
|
|
|
|
|
class ObjectCategoryCredential(Base):
|
|
"""Per-category credentials on an object.
|
|
|
|
protocol='ssh': SSH access to devices of this category.
|
|
protocol='http': HTTP/API access (cameras, MikroTik, Proxmox, etc.).
|
|
type='password': username + password_enc required.
|
|
type='key': username + ssh_key_id required (ssh only).
|
|
"""
|
|
|
|
__tablename__ = "object_category_credentials"
|
|
__table_args__ = (
|
|
CheckConstraint("protocol IN ('ssh', 'http')", name="ck_obj_cat_cred_protocol"),
|
|
CheckConstraint("type IN ('password', 'key')", name="ck_obj_cat_cred_type"),
|
|
)
|
|
|
|
id: Mapped[int] = mapped_column(Integer, primary_key=True)
|
|
object_id: Mapped[int] = mapped_column(
|
|
Integer, ForeignKey("objects.id", ondelete="CASCADE"), nullable=False, index=True
|
|
)
|
|
category: Mapped[str] = mapped_column(String(20), nullable=False)
|
|
protocol: Mapped[str] = mapped_column(String(10), nullable=False)
|
|
type: Mapped[str] = mapped_column(String(10), nullable=False, default="password")
|
|
username: Mapped[str] = mapped_column(String(100), nullable=False)
|
|
password_enc: Mapped[Optional[str]] = mapped_column(String(500), nullable=True)
|
|
ssh_key_id: Mapped[Optional[int]] = mapped_column(
|
|
Integer, ForeignKey("ssh_keys.id", ondelete="SET NULL"), nullable=True
|
|
)
|
|
priority: Mapped[int] = mapped_column(Integer, nullable=False, default=0)
|
|
|
|
object: Mapped["Object"] = relationship("Object", back_populates="category_credentials")
|
|
ssh_key: Mapped[Optional["SSHKey"]] = relationship("SSHKey")
|