"""天宰域器谱表:设备配对与逐项授契(PRD §8.3)。 设计依据: - 设备采用一次配对、设备密钥、可撤销证书; - 器谱属于镜域,人物逐项授契;撤回立即生效; - 失联时只允许安全自治与输入暂存,不允许本地人物副本。 """ from datetime import datetime from sqlalchemy import DateTime, String, Text from sqlalchemy.orm import Mapped, mapped_column from app.core.ids import new_id from app.core.time import utc_now from app.db.base import Base class Device(Base): """已配对设备(镜匣桌面端/移动端):一次配对,可撤销。""" __tablename__ = "devices" id: Mapped[str] = mapped_column(String(80), primary_key=True, default=lambda: new_id("dev")) owner_scope: Mapped[str] = mapped_column(String(80), nullable=False, index=True) # 设备形态:desktop_shell(镜匣)/ mobile / other kind: Mapped[str] = mapped_column(String(30), nullable=False, default="desktop_shell") name: Mapped[str] = mapped_column(String(120), nullable=False, default="") # 设备公钥指纹(配对时登记;凭证与通信验签用其派生) key_fingerprint: Mapped[str] = mapped_column(String(128), nullable=False, default="") # active / revoked / lost status: Mapped[str] = mapped_column(String(20), nullable=False, default="active", index=True) created_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), default=utc_now) last_seen_at: Mapped[datetime | None] = mapped_column(DateTime(timezone=True)) class DeviceGrant(Base): """器谱授契:设备级能力逐项授权(通知/文件对话框/语音输入/通感…);撤回立即生效。""" __tablename__ = "device_grants" id: Mapped[str] = mapped_column(String(80), primary_key=True, default=lambda: new_id("dgrant")) device_id: Mapped[str] = mapped_column( String(80), nullable=False, index=True ) owner_scope: Mapped[str] = mapped_column(String(80), nullable=False, index=True) # 能力键:notifications / file_dialog / voice_input / camera / screen / location / local_search capability: Mapped[str] = mapped_column(String(60), nullable=False, index=True) # 授权范围(时间窗/精度/单次触发等自由结构;敏感设备必须用户主动触发) scope_json: Mapped[str] = mapped_column(Text, nullable=False, default="{}") # active / revoked status: Mapped[str] = mapped_column(String(20), nullable=False, default="active", index=True) granted_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), default=utc_now) revoked_at: Mapped[datetime | None] = mapped_column(DateTime(timezone=True))