该提交新增了完整的 Nostr 去中心化社交网络适配器实现,包含以下核心功能: 1. 基础加密与密钥处理:支持 nsec/npub/hex 格式密钥转换,实现 NIP-04/NIP-17 加解密 2. Relay 管理与健康监控:支持多 Relay 连接、自动重连、健康评分与自动选优 3. 事件与消息处理:实现事件校验、去重、速率限制、消息缓存与状态持久化 4. 个人资料管理:支持发布/导入/合并 Nostr Kind 0 元数据事件 5. 配对机制:实现安全的双向配对通信流程 6. Zap 功能:支持 NIP-57 打赏请求与收据解析 7. NIP-05 验证:实现域名身份验证 8. 配置系统:完整的配置校验与多账户支持 9. 监控与指标:提供连接监控、事件统计与健康快照 10. HTTP API:提供个人资料管理的 RESTful 接口 11. 安装向导:命令行配置向导与初始化流程 所有模块均遵循 Nostr 协议规范,支持多账户、多 Relay 部署,内置安全防护与流量控制机制。
99 lines
3.7 KiB
Python
99 lines
3.7 KiB
Python
from __future__ import annotations
|
||
|
||
from typing import Any
|
||
|
||
from yuxi.channels.adapters.nostr.setup import NostrSetupAdapter
|
||
from yuxi.channels.adapters.nostr.crypto import NostrCrypto, NostrCryptoError
|
||
from yuxi.channels.adapters.nostr.config import NostrConfig
|
||
|
||
|
||
class NostrSetupPlugin:
|
||
channel_id: str = "nostr"
|
||
channel_label: str = "Nostr (Decentralized)"
|
||
channel_description: str = "Nostr 去中心化社交网络 DM 协议配置向导"
|
||
|
||
def __init__(self, config: dict[str, Any] | None = None):
|
||
self._config = config or {}
|
||
self._setup_adapter = NostrSetupAdapter()
|
||
|
||
@property
|
||
def config(self) -> dict[str, Any]:
|
||
return self._config
|
||
|
||
def get_setup_wizard(self) -> dict[str, Any]:
|
||
return {
|
||
"channel_id": self.channel_id,
|
||
"label": self.channel_label,
|
||
"description": self.channel_description,
|
||
"steps": self._setup_adapter.get_setup_steps(),
|
||
"help": "详细文档请参考: /docs/channels/nostr",
|
||
}
|
||
|
||
async def validate_credentials(self, private_key: str) -> dict[str, Any]:
|
||
result = await self._setup_adapter.verify_key(private_key)
|
||
if result.get("success"):
|
||
return {"valid": True, "npub": result.get("npub"), "hex": result.get("hex")}
|
||
return {"valid": False, "error": result.get("error", "unknown")}
|
||
|
||
async def probe_connectivity(self, relays: list[str], timeout_ms: int = 8000) -> dict[str, Any]:
|
||
result = await self._setup_adapter.probe_relays(relays)
|
||
return {
|
||
"connected": result.get("success", False),
|
||
"reachable": result.get("reachable", 0),
|
||
"total": result.get("total", 0),
|
||
"details": result.get("details", []),
|
||
}
|
||
|
||
def get_recommendations(self) -> dict[str, Any]:
|
||
return {
|
||
"relays": [
|
||
"wss://relay.damus.io",
|
||
"wss://relay.primal.net",
|
||
"wss://relay.nostr.info",
|
||
"wss://nos.lol",
|
||
],
|
||
"dm_policy": "pairing",
|
||
"nip17_enabled": True,
|
||
"streaming_mode": "block",
|
||
}
|
||
|
||
async def validate_full_config(self, full_config: dict[str, Any]) -> dict[str, Any]:
|
||
errors: list[str] = []
|
||
warnings: list[str] = []
|
||
|
||
try:
|
||
NostrConfig.from_dict(full_config)
|
||
except Exception as e:
|
||
errors.append(f"配置验证失败: {e}")
|
||
return {"valid": False, "errors": errors, "warnings": warnings}
|
||
|
||
private_key = full_config.get("private_key") or full_config.get("accounts", {}).get("default", {}).get(
|
||
"private_key", ""
|
||
)
|
||
if private_key:
|
||
try:
|
||
NostrCrypto(private_key)
|
||
except NostrCryptoError as e:
|
||
errors.append(f"私钥无效: {e}")
|
||
else:
|
||
warnings.append("未配置私钥,将自动生成临时密钥")
|
||
|
||
relays = full_config.get("relays") or full_config.get("accounts", {}).get("default", {}).get("relays")
|
||
if not relays:
|
||
warnings.append("未配置 Relay,将使用默认 Relay 列表")
|
||
else:
|
||
invalid_relays = [r for r in relays if not r.startswith(("ws://", "wss://"))]
|
||
if invalid_relays:
|
||
warnings.append(f"以下 Relay URL 格式可能无效: {invalid_relays}")
|
||
|
||
return {"valid": len(errors) == 0, "errors": errors, "warnings": warnings}
|
||
|
||
|
||
def get_setup_plugin(config: dict[str, Any] | None = None) -> NostrSetupPlugin:
|
||
return NostrSetupPlugin(config)
|
||
|
||
|
||
async def verify_channel_setup(config: dict[str, Any]) -> dict[str, Any]:
|
||
plugin = NostrSetupPlugin(config)
|
||
return await plugin.validate_full_config(config)
|