mirror of
https://github.com/jxxghp/MoviePilot.git
synced 2026-08-31 13:07:56 +08:00
refactor: 统一插件迁移与 Passkey 模块命名
This commit is contained in:
@@ -14,7 +14,7 @@ from app.application.security.auth import (
|
||||
AuthService,
|
||||
AuthUserRepository,
|
||||
)
|
||||
from app.application.security.passkeys import PasskeyRepository, PasskeyService
|
||||
from app.application.security.passkey import PasskeyRepository, PasskeyService
|
||||
from app.application.security.user import (
|
||||
AsyncUnitOfWork,
|
||||
UserRepository,
|
||||
|
||||
@@ -22,12 +22,10 @@ from app.application.security.otp import OtpUtils
|
||||
from app.application.security.passkey import (
|
||||
PasskeyChallengeStore,
|
||||
PassKeyHelper,
|
||||
PasskeyService,
|
||||
PassKeyRegistrationOriginMismatchError,
|
||||
PassKeyRegistrationVerificationError,
|
||||
)
|
||||
from app.application.security.passkeys import (
|
||||
PasskeyService,
|
||||
)
|
||||
from app.application.security.token import verify_password
|
||||
from app.application.security.user import (
|
||||
UserService,
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
"""存量插件来源身份的一次性启动迁移。"""
|
||||
"""存量插件来源身份的幂等启动迁移。"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
@@ -7,7 +7,7 @@ import json
|
||||
import secrets
|
||||
import threading
|
||||
from dataclasses import dataclass
|
||||
from typing import Any, Dict, List, Literal, Optional, Tuple
|
||||
from typing import Any, Dict, List, Literal, Optional, Protocol, Tuple
|
||||
from urllib.parse import urlparse
|
||||
|
||||
from webauthn import (
|
||||
@@ -451,3 +451,73 @@ class PassKeyHelper:
|
||||
except Exception as e:
|
||||
logger.error(f"验证认证响应失败: {e}")
|
||||
return False, credential_current_sign_count
|
||||
|
||||
|
||||
class PasskeyRepository(Protocol):
|
||||
"""PassKey 用例需要的最小同步数据端口。"""
|
||||
|
||||
def list(self) -> list[Any]:
|
||||
"""列出全部启用凭证。"""
|
||||
|
||||
def list_by_user_id(self, user_id: int) -> list[Any]:
|
||||
"""列出指定用户凭证。"""
|
||||
|
||||
def get_by_credential_id(self, credential_id: str) -> Optional[Any]:
|
||||
"""按凭证 ID 查找凭证。"""
|
||||
|
||||
def create(self, payload: dict[str, Any]) -> Any:
|
||||
"""创建凭证。"""
|
||||
|
||||
def update_last_used(self, passkey: Any, sign_count: int) -> bool:
|
||||
"""更新凭证使用计数。"""
|
||||
|
||||
def delete_by_id(self, passkey_id: int, user_id: int) -> bool:
|
||||
"""删除用户凭证。"""
|
||||
|
||||
|
||||
class PasskeyService:
|
||||
"""编排 PassKey 凭证生命周期。"""
|
||||
|
||||
def __init__(self, repository: PasskeyRepository) -> None:
|
||||
"""注入 PassKey 数据端口。"""
|
||||
self._repository = repository
|
||||
|
||||
def list(self) -> list[Any]:
|
||||
"""列出全部启用凭证。"""
|
||||
return self._repository.list()
|
||||
|
||||
def list_by_user_id(self, user_id: int) -> list[Any]:
|
||||
"""列出指定用户凭证。"""
|
||||
return self._repository.list_by_user_id(user_id)
|
||||
|
||||
def get_by_credential_id(self, credential_id: str) -> Optional[Any]:
|
||||
"""按凭证 ID 查找凭证。"""
|
||||
return self._repository.get_by_credential_id(credential_id)
|
||||
|
||||
def create(self, payload: dict[str, Any]) -> Any:
|
||||
"""创建凭证。"""
|
||||
return self._repository.create(payload)
|
||||
|
||||
def update_last_used(self, passkey: Any, sign_count: int) -> bool:
|
||||
"""更新凭证使用计数。"""
|
||||
return self._repository.update_last_used(passkey, sign_count)
|
||||
|
||||
def delete_by_id(self, passkey_id: int, user_id: int) -> bool:
|
||||
"""删除用户凭证。"""
|
||||
return self._repository.delete_by_id(passkey_id, user_id)
|
||||
|
||||
|
||||
_configured_passkey_service: Optional[PasskeyService] = None
|
||||
|
||||
|
||||
def configure_passkey_service(service: PasskeyService) -> None:
|
||||
"""由启动组合根登记 PassKey 应用服务。"""
|
||||
global _configured_passkey_service
|
||||
_configured_passkey_service = service
|
||||
|
||||
|
||||
def get_configured_passkey_service() -> PasskeyService:
|
||||
"""返回启动阶段登记的 PassKey 应用服务。"""
|
||||
if _configured_passkey_service is None:
|
||||
raise RuntimeError("PassKey 服务尚未配置")
|
||||
return _configured_passkey_service
|
||||
|
||||
@@ -1,75 +0,0 @@
|
||||
"""PassKey 认证凭证应用服务。"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import Any, Optional, Protocol
|
||||
|
||||
|
||||
class PasskeyRepository(Protocol):
|
||||
"""PassKey 用例需要的最小同步数据端口。"""
|
||||
|
||||
def list(self) -> list[Any]:
|
||||
"""列出全部启用凭证。"""
|
||||
|
||||
def list_by_user_id(self, user_id: int) -> list[Any]:
|
||||
"""列出指定用户凭证。"""
|
||||
|
||||
def get_by_credential_id(self, credential_id: str) -> Optional[Any]:
|
||||
"""按凭证 ID 查找凭证。"""
|
||||
|
||||
def create(self, payload: dict[str, Any]) -> Any:
|
||||
"""创建凭证。"""
|
||||
|
||||
def update_last_used(self, passkey: Any, sign_count: int) -> bool:
|
||||
"""更新凭证使用计数。"""
|
||||
|
||||
def delete_by_id(self, passkey_id: int, user_id: int) -> bool:
|
||||
"""删除用户凭证。"""
|
||||
|
||||
|
||||
class PasskeyService:
|
||||
"""编排 PassKey 凭证生命周期。"""
|
||||
|
||||
def __init__(self, repository: PasskeyRepository) -> None:
|
||||
"""注入 PassKey 数据端口。"""
|
||||
self._repository = repository
|
||||
|
||||
def list(self) -> list[Any]:
|
||||
"""列出全部启用凭证。"""
|
||||
return self._repository.list()
|
||||
|
||||
def list_by_user_id(self, user_id: int) -> list[Any]:
|
||||
"""列出指定用户凭证。"""
|
||||
return self._repository.list_by_user_id(user_id)
|
||||
|
||||
def get_by_credential_id(self, credential_id: str) -> Optional[Any]:
|
||||
"""按凭证 ID 查找凭证。"""
|
||||
return self._repository.get_by_credential_id(credential_id)
|
||||
|
||||
def create(self, payload: dict[str, Any]) -> Any:
|
||||
"""创建凭证。"""
|
||||
return self._repository.create(payload)
|
||||
|
||||
def update_last_used(self, passkey: Any, sign_count: int) -> bool:
|
||||
"""更新凭证使用计数。"""
|
||||
return self._repository.update_last_used(passkey, sign_count)
|
||||
|
||||
def delete_by_id(self, passkey_id: int, user_id: int) -> bool:
|
||||
"""删除用户凭证。"""
|
||||
return self._repository.delete_by_id(passkey_id, user_id)
|
||||
|
||||
|
||||
_configured_passkey_service: PasskeyService | None = None
|
||||
|
||||
|
||||
def configure_passkey_service(service: PasskeyService) -> None:
|
||||
"""由启动组合根登记 PassKey 应用服务。"""
|
||||
global _configured_passkey_service
|
||||
_configured_passkey_service = service
|
||||
|
||||
|
||||
def get_configured_passkey_service() -> PasskeyService:
|
||||
"""返回启动阶段登记的 PassKey 应用服务。"""
|
||||
if _configured_passkey_service is None:
|
||||
raise RuntimeError("PassKey 服务尚未配置")
|
||||
return _configured_passkey_service
|
||||
@@ -89,7 +89,7 @@ from app.application.outbox import (
|
||||
)
|
||||
from app.application.plugin.runtime import configure_plugin_runtime
|
||||
from app.application.security.auth import AuthService, build_superuser_token_payload, configure_auth_service
|
||||
from app.application.security.passkeys import PasskeyService, configure_passkey_service
|
||||
from app.application.security.passkey import PasskeyService, configure_passkey_service
|
||||
from app.application.security.url import close_image_proxy_block_log_coalescer
|
||||
from app.application.security.user import configure_user_lookups
|
||||
from app.application.security.userconfig import (
|
||||
|
||||
@@ -30,7 +30,7 @@ from app.application.plugin.identity import (
|
||||
TrustedPluginSourceType,
|
||||
normalize_physical_plugin_id,
|
||||
)
|
||||
from app.application.plugin.identity_migration import (
|
||||
from app.application.plugin.migration import (
|
||||
PluginIdentityMigrationService,
|
||||
configure_plugin_identity_migration,
|
||||
get_plugin_identity_migration,
|
||||
|
||||
@@ -69,7 +69,7 @@ MoviePilot V3 已经形成较清晰的模块化单体:`foundation`、`domain`
|
||||
|
||||
| 指标 | 当前值 | 解释 |
|
||||
|---|---:|---|
|
||||
| 宿主 Python 模块 / 内部依赖边 | 843 / 6,883 | `dependency-baseline.json` 当前快照 |
|
||||
| 宿主 Python 模块 / 内部依赖边 | 842 / 6,882 | `dependency-baseline.json` 当前快照 |
|
||||
| 非平凡 SCC | 2 | 新增 Chain 包根环;另一个是隔离的 29 模块 TMDB 移植包环 |
|
||||
| 跨层 DB 边界债务 | 0 | Application、Chain、API、Agent、Runtime、Workflow 到 DB 的受控债务均为零 |
|
||||
| Model/Oper 事务债务 | 0 | 自建 Session、自动事务装饰器、直接 commit/rollback 等基线均为零 |
|
||||
|
||||
@@ -704,8 +704,8 @@ flowchart LR
|
||||
|
||||
| 指标 | 当前值 |
|
||||
|---|---:|
|
||||
| Python 模块 | 843 |
|
||||
| 内部导入边 | 6,883 |
|
||||
| Python 模块 | 842 |
|
||||
| 内部导入边 | 6,882 |
|
||||
| 非平凡 SCC | 2(`ARCH-107` 临时 Chain 包根环;精确 containment 的 TMDB 移植包环) |
|
||||
| Direct egress | 66(12 条待迁移债务,54 条精确 containment) |
|
||||
| Module Contract V2 spec | 217(其中 215 个进入 `run_module` 观察面) |
|
||||
|
||||
@@ -69,7 +69,7 @@ to make the directory tree look symmetrical.
|
||||
| `app/application/agentdata.py` | Named Agent data ports; canonical Agent consumers use `get_agent_*_port()` and do not alias legacy proxies to Oper classes |
|
||||
| `app/application/outbox.py` | Durable intent and Outbox repository/dispatcher contracts for post-commit side effects |
|
||||
| `app/application/transfer_execution.py` | Durable transfer execution contracts: stable operation identity, step/checkpoint state, retry/manual-review commands and terminal-settlement DTOs; contains no SQLAlchemy or external I/O |
|
||||
| `app/application/plugin/` | Plugin market catalog, installation command, installed-plugin identity contract, runtime port, folder operations and dynamic-route use cases; filenames remain single words (`catalog.py`, `identity.py`, `install.py`, `runtime.py`, `folders.py`, `routes.py`) |
|
||||
| `app/application/plugin/` | Plugin market catalog, installation command, installed-plugin identity contract and startup migration, runtime port, folder operations and dynamic-route use cases; filenames remain single words (`catalog.py`, `identity.py`, `migration.py`, `install.py`, `runtime.py`, `folders.py`, `routes.py`) |
|
||||
| `app/application/server/` | MoviePilot Server reporting and sharing use cases; local data readers and transport callbacks are injected by startup |
|
||||
| `app/application/site/` | Configured site catalog, authentication level and index-resource capability; the generated extension and its data bundle stay together here |
|
||||
| `app/application/messaging/` | Message rendering/routing, interactions and the Agent-to-message bridge: `ingress.py` owns the single channel-to-host loopback boundary; `interaction.py` shared interaction contracts and view helpers; `router.py` unified interaction priority and callback dispatch; `site.py`/`subscribe.py`/`skill.py` per-command sessions, input parsing and views; `media.py` media interaction state while the business workflow stays in `MediaInteractionChain`; `plugin.py` plugin input capture and plugin button callbacks; `agent.py` agent choice state, callback protocol and WebAgent bridge; `message.py` notification rendering, templates and queue. Not a public SDK recommended for direct plugin use |
|
||||
|
||||
+13
-15
@@ -1441,8 +1441,8 @@
|
||||
"runtime_only": true
|
||||
}
|
||||
},
|
||||
"edge_count": 6883,
|
||||
"edge_sha256": "f44ae63f222eda2fc1b8ce805ab5138550a560bef6c266e3f2fae6338a243cd2",
|
||||
"edge_count": 6882,
|
||||
"edge_sha256": "602a73df30503fec4f4f01e28020222497cdadcad731dfedca40a3e4b1133c0d",
|
||||
"edges": [
|
||||
"app -> app.runtime",
|
||||
"app -> app.runtime.compat",
|
||||
@@ -3003,7 +3003,7 @@
|
||||
"app.api.dependencies.auth -> app.application",
|
||||
"app.api.dependencies.auth -> app.application.security",
|
||||
"app.api.dependencies.auth -> app.application.security.auth",
|
||||
"app.api.dependencies.auth -> app.application.security.passkeys",
|
||||
"app.api.dependencies.auth -> app.application.security.passkey",
|
||||
"app.api.dependencies.auth -> app.application.security.user",
|
||||
"app.api.dependencies.auth -> app.schemas",
|
||||
"app.api.dependencies.auth -> app.schemas.token",
|
||||
@@ -3468,7 +3468,6 @@
|
||||
"app.api.endpoints.mfa -> app.application.security.auth",
|
||||
"app.api.endpoints.mfa -> app.application.security.otp",
|
||||
"app.api.endpoints.mfa -> app.application.security.passkey",
|
||||
"app.api.endpoints.mfa -> app.application.security.passkeys",
|
||||
"app.api.endpoints.mfa -> app.application.security.token",
|
||||
"app.api.endpoints.mfa -> app.application.security.user",
|
||||
"app.api.endpoints.mfa -> app.runtime",
|
||||
@@ -4215,12 +4214,6 @@
|
||||
"app.application.plugin.identity -> app.application",
|
||||
"app.application.plugin.identity -> app.application.plugin",
|
||||
"app.application.plugin.identity -> app.application.plugin.declaration",
|
||||
"app.application.plugin.identity_migration -> app.application",
|
||||
"app.application.plugin.identity_migration -> app.application.plugin",
|
||||
"app.application.plugin.identity_migration -> app.application.plugin.identity",
|
||||
"app.application.plugin.identity_migration -> app.application.plugin.source",
|
||||
"app.application.plugin.identity_migration -> app.runtime",
|
||||
"app.application.plugin.identity_migration -> app.runtime.log",
|
||||
"app.application.plugin.install -> app.application",
|
||||
"app.application.plugin.install -> app.application.plugin",
|
||||
"app.application.plugin.install -> app.application.plugin.admission",
|
||||
@@ -4239,6 +4232,12 @@
|
||||
"app.application.plugin.inventory -> app.application.plugin.source",
|
||||
"app.application.plugin.inventory -> app.foundation",
|
||||
"app.application.plugin.inventory -> app.foundation.environment",
|
||||
"app.application.plugin.migration -> app.application",
|
||||
"app.application.plugin.migration -> app.application.plugin",
|
||||
"app.application.plugin.migration -> app.application.plugin.identity",
|
||||
"app.application.plugin.migration -> app.application.plugin.source",
|
||||
"app.application.plugin.migration -> app.runtime",
|
||||
"app.application.plugin.migration -> app.runtime.log",
|
||||
"app.application.plugin.recovery -> app.application",
|
||||
"app.application.plugin.recovery -> app.application.plugin",
|
||||
"app.application.plugin.recovery -> app.application.plugin.install",
|
||||
@@ -7935,7 +7934,7 @@
|
||||
"app.startup.initializers.modules -> app.application.plugin.transaction",
|
||||
"app.startup.initializers.modules -> app.application.security",
|
||||
"app.startup.initializers.modules -> app.application.security.auth",
|
||||
"app.startup.initializers.modules -> app.application.security.passkeys",
|
||||
"app.startup.initializers.modules -> app.application.security.passkey",
|
||||
"app.startup.initializers.modules -> app.application.security.url",
|
||||
"app.startup.initializers.modules -> app.application.security.user",
|
||||
"app.startup.initializers.modules -> app.application.security.userconfig",
|
||||
@@ -8046,10 +8045,10 @@
|
||||
"app.startup.initializers.plugins -> app.application.plugin.data",
|
||||
"app.startup.initializers.plugins -> app.application.plugin.gateway",
|
||||
"app.startup.initializers.plugins -> app.application.plugin.identity",
|
||||
"app.startup.initializers.plugins -> app.application.plugin.identity_migration",
|
||||
"app.startup.initializers.plugins -> app.application.plugin.install",
|
||||
"app.startup.initializers.plugins -> app.application.plugin.inventory",
|
||||
"app.startup.initializers.plugins -> app.application.plugin.lifecycle",
|
||||
"app.startup.initializers.plugins -> app.application.plugin.migration",
|
||||
"app.startup.initializers.plugins -> app.application.plugin.recovery",
|
||||
"app.startup.initializers.plugins -> app.application.plugin.routes",
|
||||
"app.startup.initializers.plugins -> app.application.plugin.runtime",
|
||||
@@ -8328,7 +8327,7 @@
|
||||
"app.workflow.actions.transfer_file -> app.workflow",
|
||||
"app.workflow.actions.transfer_file -> app.workflow.actions"
|
||||
],
|
||||
"module_count": 843,
|
||||
"module_count": 842,
|
||||
"modules": [
|
||||
"app",
|
||||
"app.adapters",
|
||||
@@ -8627,10 +8626,10 @@
|
||||
"app.application.plugin.folders",
|
||||
"app.application.plugin.gateway",
|
||||
"app.application.plugin.identity",
|
||||
"app.application.plugin.identity_migration",
|
||||
"app.application.plugin.install",
|
||||
"app.application.plugin.inventory",
|
||||
"app.application.plugin.lifecycle",
|
||||
"app.application.plugin.migration",
|
||||
"app.application.plugin.recovery",
|
||||
"app.application.plugin.routes",
|
||||
"app.application.plugin.runtime",
|
||||
@@ -8647,7 +8646,6 @@
|
||||
"app.application.security.cookie",
|
||||
"app.application.security.otp",
|
||||
"app.application.security.passkey",
|
||||
"app.application.security.passkeys",
|
||||
"app.application.security.token",
|
||||
"app.application.security.twofactor",
|
||||
"app.application.security.url",
|
||||
|
||||
@@ -18,7 +18,7 @@ from app.application.plugin.identity import (
|
||||
PluginPayloadSourceType,
|
||||
TrustedPluginSourceType,
|
||||
)
|
||||
from app.application.plugin.identity_migration import PluginIdentityMigrationService
|
||||
from app.application.plugin.migration import PluginIdentityMigrationService
|
||||
from app.application.plugin.source import (
|
||||
CandidateInventory,
|
||||
LocalCandidateRead,
|
||||
|
||||
Reference in New Issue
Block a user