From 82dd2996e6716e482ae5c4dde312c35eb07df7ee Mon Sep 17 00:00:00 2001 From: A Date: Mon, 8 Jun 2026 21:42:55 +0800 Subject: [PATCH] docs: update account and Android compatibility notes (cherry picked from commit 3e6321d99607160d0d77bc63977619d5e1d28516) --- docs/compatibility-matrix.md | 33 ++++++++++++++++++++++----------- docs/persistence-layer.md | 4 ++-- 2 files changed, 24 insertions(+), 13 deletions(-) diff --git a/docs/compatibility-matrix.md b/docs/compatibility-matrix.md index 3cc99ef3..03000518 100644 --- a/docs/compatibility-matrix.md +++ b/docs/compatibility-matrix.md @@ -94,31 +94,41 @@ status 取值:done(真实实现) / stub(兼容响应) / todo(已发现未实 | method | status | behavior | note | |---|---|---|---| | auth.bindTempAuthKey | done | real-validated | 校验 encrypted bind_auth_key_inner(nonce/temp key/perm key/session/expires_at)后记录 temp_auth_key_bindings;后续 temp auth_key RPC 会解析为 perm auth_key 身份,并刷新 active session 的业务 auth_key_id / user_id 缓存 | -| auth.exportLoginToken | stub | tdesktop-qr-placeholder | TDesktop QR 登录页轮询;第一阶段只支持手机号登录,返回短期 auth.loginToken 避免未实现噪声 | -| auth.sendCode | done | dev-code | 开发固定验证码,phone_code_hash 存 Redis CodeStore;手机号统一规范为纯数字 | -| auth.signIn | done | real | 校验码;兼容 TDesktop sendCode 后 signIn 使用 DigitsOnly(phone);登录成功绑定在线 session 的 user_id,写入并延迟推送 777000 官方登录消息 updateNewMessage,同时向其它在线 session 推送新登录 updateServiceNotification | +| auth.exportLoginToken / auth.importLoginToken | stub | tdesktop-qr-placeholder | TDesktop QR 登录页轮询;当前单 DC 主路径只支持手机号登录,返回短期 auth.loginToken 避免未实现噪声;`auth.acceptLoginToken` 显式返回 `AUTH_TOKEN_INVALID`,不伪造跨设备 QR 授权 | +| auth.exportAuthorization / auth.importAuthorization / auth.dropTempAuthKeys | stub | single-dc-bounded | 单 DC 当前不做跨 DC authorization handoff;export/import 返回 `DC_ID_INVALID`,dropTempAuthKeys 返回成功避免旧 temp key 清理路径噪声 | +| auth.sendCode / auth.resendCode / auth.cancelCode | done | dev-code | 开发固定验证码,phone_code_hash 存 Redis CodeStore;手机号统一规范为纯数字;resend 会校验并失效旧 hash 后生成新 hash,cancel 会删除 pending code | +| auth.signIn | done | real+2fa-gate | 校验码;兼容 TDesktop sendCode 后 signIn 使用 DigitsOnly(phone);无 2FA 时登录成功绑定在线 session 的 user_id,写入并延迟推送 777000 官方登录消息 updateNewMessage,同时向其它在线 session 推送新登录 updateServiceNotification;账号已启用 2FA 时返回 `SESSION_PASSWORD_NEEDED` 并等待 `auth.checkPassword` | | auth.signUp | done | real | 建 user + 绑定 authorization;登录成功绑定在线 session 的 user_id,写入并延迟推送 777000 官方登录消息 updateNewMessage | | auth.logOut | done | real | 解绑当前 auth_key 的授权,并清理同业务 auth_key 的活跃连接 user_id 缓存与 auth_key+user update state;账号级 user_update_events 不随设备退出删除,退出后同设备换号不会继承旧账号差分 | +| auth.resetAuthorizations | done | real | 删除当前账号除当前 auth_key 外的其它授权,清理对应 session/auth cache 与设备 update state | +| auth.checkPassword / auth.requestPasswordRecovery / auth.checkRecoveryPassword / auth.recoverPassword | done | real-srp-dev-email | 按 Telegram SRP KDF 校验 `inputCheckPasswordSRP`;恢复邮箱只保存/返回 pattern,开发环境使用固定恢复码 `12345`,未接真实邮件网关;recover 可清除或重设 2FA | | account.checkUsername | done | real | username 规则为 ASCII 字母开头、后续字母/数字/下划线、5-32 字符;大小写不敏感检查占用,已被本人占用视为可用 | | account.updateUsername | done | real | 设置或清除当前账号主 username;大小写不敏感唯一约束由 PG partial unique index 兜底,并向其它在线 session 推送 updateUserName | | account.updateProfile | done | real | 更新当前账号 first_name/last_name/about;first_name 必填且姓名 64 字符内,about 70 字符内;资料变化后向其它在线 session 推送 updateUserName,`users.getFullUser` 返回 about | -| account.getPassword | done | real | PG-backed account_passwords;第一阶段默认无 2FA | +| account.getPassword / account.getPasswordSettings / account.updatePasswordSettings | done | real-srp | PG-backed `account_passwords`;返回 Layer225 `passwordKdfAlgoSHA256SHA256PBKDF2HMACSHA512iter100000SHA256ModPow` 参数;支持设置/修改/清除 2FA、hint、恢复邮箱、SRP challenge 轮换与错误映射 | +| account.confirmPasswordEmail / account.resendPasswordEmail / account.cancelPasswordEmail | done | dev-email-code | 开发环境恢复邮箱码固定为 `12345`;confirm/resend/cancel 走持久 recovery code 状态,未接真实邮件网关 | +| account.resetPassword / account.declinePasswordReset | done | real-wait-state | 无恢复邮箱的 2FA 账号可进入 7 天 reset wait,等待期到期再次调用清除 2FA;decline 清除 pending reset;有恢复邮箱时返回 `PASSWORD_RECOVERY_NA` 让客户端走邮箱恢复 | | account.getAccountTTL | stub | default-365d | TDesktop Settings/self-destruct 预取;当前不做账号自动销毁持久配置,返回正数默认 TTL 避免后台 NOT_IMPLEMENTED | +| account.setAccountTTL | stub | ack | 当前不持久化账号自动销毁 TTL,接受写入并返回成功 | | account.getNotifySettings | stub | default | TDesktop 主界面读取通知设置;显式返回 show_previews=true、silent=false、mute_until=0 与 default sound,避免空 settings 被客户端按静默展示 | -| account.updateNotifySettings | stub | ok | 第一阶段不持久化通知偏好,但接受 TDesktop 设置写入,避免本地通知状态 RPC 报错 | +| account.updateNotifySettings / account.resetNotifySettings / account.getNotifyExceptions | stub | ok-empty | 当前不持久化通知偏好/例外,但接受 TDesktop 设置写入并返回空 updates,避免本地通知状态 RPC 报错 | | account.getPrivacy | done | real-privacy | 按 owner+key 读取 `account_privacy_rules`;无记录时默认 PhoneNumber=DisallowAll、Birthday=AllowContacts、其它=AllowAll;支持 Layer225 全部 privacy key/rule kind,users/chats 按规则回填 | | account.setPrivacy | done | real-privacy/online-update | 校验 `InputPrivacyKey/InputPrivacyRule` 与 input user access_hash 后持久化;返回 `account.privacyRules` 并向当前账号在线 session 推 `updatePrivacy`;Stars/Premium/Bot 等高级产品只保存规则,不扩展商业模型。离线 `updates.getDifference` 恢复 `updatePrivacy` 仍需扩展 `user_update_events` privacy payload | -| account.getAuthorizations | stub | empty | Settings 设备列表预取;第一阶段不展示授权设备管理,返回空 authorizations | -| account.getDefaultEmojiStatuses | stub | notModified | 第一阶段不提供默认 emoji status 列表 | +| account.getAuthorizations / account.resetAuthorization | done | real-devices | 从 `authorizations` 返回当前账号设备列表,带 current/hash/device/app/ip/date;resetAuthorization 按 hash 删除同账号授权并清理 session/auth cache | +| account.getWebAuthorizations / account.resetWebAuthorization / account.resetWebAuthorizations | stub | empty/ack | 当前无 Telegram Login Widget/Web 授权模型,返回空列表并接受清理请求 | +| account.registerDevice / account.unregisterDevice | stub | ack | 当前未接真实 APNS/FCM 推送网关,接受 TDesktop 设备 token 注册/注销避免后台噪声 | +| account.getDefaultEmojiStatuses / account.getRecentEmojiStatuses / account.clearRecentEmojiStatuses / account.updateEmojiStatus | stub | empty/notModified | 当前不提供云 emoji status;读取返回空或 notModified,写入/清理返回成功 | | account.getCollectibleEmojiStatuses | stub | empty | TDesktop 启动/emoji status 面板会刷新 collectible gift emoji statuses;当前无 gift/status 模型,返回空 `account.emojiStatuses` | -| account.getDefaultGroupPhotoEmojis | stub | empty | TDesktop 头像/群头像编辑页默认 emoji 图片入口;当前无 custom-emoji photo 候选,返回空 `emojiList` | +| account.getDefaultProfilePhotoEmojis / account.getDefaultGroupPhotoEmojis / account.getDefaultBackgroundEmojis / account.getChannelDefaultEmojiStatuses / account.getChannelRestrictedStatusEmojis | stub | empty | TDesktop 头像/背景/频道状态编辑页默认 emoji 入口;当前无 custom-emoji 候选,返回空 `emojiList` 或空 statuses | | account.getConnectedBots | stub | empty | TDesktop business chatbot 资料预取;当前无 business bot 模型,返回空 `account.connectedBots`,避免客户端 API error | | account.getReactionsNotifySettings / account.setReactionsNotifySettings | done | real-account-settings | 持久化账号 reaction 通知范围(none/contacts/all)与 show_previews,返回默认提示音;无记录时默认 contacts + previews | -| account.getContactSignUpNotification | stub | false | 第一阶段不推送联系人注册提醒 | +| account.getContactSignUpNotification / account.setContactSignUpNotification | stub | false/ack | 当前不推送联系人注册提醒,读取 false、写入接受 | | account.getThemes | stub | notModified | Settings/theme 预取,第一阶段不提供云主题 | -| account.getContentSettings | stub | default | Settings 内容敏感项预取,第一阶段不启用 NSFW 内容配置 | -| account.getGlobalPrivacySettings | stub | default | Settings 全局隐私项预取,返回空默认设置 | +| account.getContentSettings / account.setContentSettings | stub | default/ack | Settings 内容敏感项预取,当前不启用 NSFW 内容配置,写入接受 | +| account.getGlobalPrivacySettings / account.setGlobalPrivacySettings | stub | default/echo | Settings 全局隐私项预取,返回空默认设置;写入回显,不扩展全局 privacy 模型 | | account.getPasskeys | stub | empty | Settings 安全项预取,第一阶段不提供 passkeys | +| account.getAutoDownloadSettings / account.saveAutoDownloadSettings | stub | defaults/ack | TDesktop 自动下载设置预取;返回保守默认下载阈值,写入接受但不持久化 | +| account.setAuthorizationTTL / account.changeAuthorizationSettings | stub | ack | Settings 设备管理长尾写入入口;当前只维护 active authorization 删除,不持久化授权 TTL/设备名设置 | | account.getSavedMusicIds | stub | empty | TDesktop saved/profile music 预取;当前没有 profile music media store,返回空 id vector | | account.updateStatus | done | persisted-presence | 记录 `auth_key/session/user` 维度运行时在线状态并持久化 `users.last_seen_at`;`offline=false` 与重连后 session 身份恢复都会写入 last_seen 并推送 `updateUserStatus(userStatusOnline expires=now+5m)`,`offline=true` 写入精确 `userStatusOffline.was_online`;最后一个 MTProto session 断开/destroy_session 也会写 last_seen 并推送 offline。状态推送给当前用户其它在线 session、在线联系人、以及已有私聊 dialog 的在线对端;session 恢复时还会向当前 session 补发在线联系人/私聊对端状态。users/dialog/history projection 已按 StatusTimestamp privacy 裁剪返回值;presence fanout 的精细 privacy 过滤仍为后续项 | @@ -392,6 +402,7 @@ outbox 多 worker 并发 + 发送事务乱序提交 → **主动推送可能乱 | langpack.getLangPack | done | real | PG-backed;启动 seed `tdesktop_en/zh-hans_v12000000.strings` | | langpack.getDifference | done | real | 按 version 返回语言包差异;当前 seed 同版本全量 | | langpack.getStrings | done | real | 按 key 查询 PG 中的语言包字符串 | +| langpack.getLanguages | done | compat-static | Layer 225 `#42c6978f` 已注册;DrKLO Android 仍会发 legacy `#800fd57d` 无参版本,RPC edge 显式 adapter 后返回语言列表 | ## Files / Media / Photos diff --git a/docs/persistence-layer.md b/docs/persistence-layer.md index de866809..5cb9cf8c 100644 --- a/docs/persistence-layer.md +++ b/docs/persistence-layer.md @@ -52,8 +52,8 @@ DDL 见 [`deploy/migrations/0001_init.up.sql`](../deploy/migrations/0001_init.up - **`auth_keys`** —— 密钥交换产物。`auth_key_id`(BIGINT,SHA1 低 64 位小端 int64) + `body`(256B BYTEA) + `server_salt`。 - **`users`** —— 登录链路必须字段:`id` / `access_hash` / `phone`(UNIQUE) / `first_name` / `last_name` / `username` / `about` / `country_code` / `verified` / `support`。`access_hash` 为任何 `InputUser` 校验所必须,不可省;普通注册用户 ID 从 `1780243200`(2026-06-01 00:00:00 Asia/Shanghai 的 Unix 秒级时间戳)起递增,内置 777000 官方系统账号显式保留在低位区间。注册页只写手机号与姓名,后续 Settings/Profile 通过 `account.updateProfile` 更新姓名与 bio。 -- **`authorizations`** —— `auth_key ↔ user` 绑定 + 设备信息(`layer` / `device_model` / `app_version` / `api_id` …)。PK 为 `auth_key_id`(一个 auth_key 一条授权),外键挂 `auth_keys` 与 `users`。 -- **`account_passwords`** —— 账号 2FA/SRP 配置。第一阶段默认 `has_password=false`,但 `account.getPassword` 已走持久化查询。 +- **`authorizations`** —— `auth_key ↔ user` 绑定 + 设备信息(`layer` / `device_model` / `app_version` / `api_id` …)。PK 为 `auth_key_id`(一个 auth_key 一条授权),外键挂 `auth_keys` 与 `users`;`hash` 是 `account.getAuthorizations/resetAuthorization` 对外稳定设备句柄,按 `(user_id, hash)` 唯一,reset 时只允许删除当前账号自己的授权。 +- **`account_passwords`** —— 账号 2FA/SRP 配置。保存 Layer225 Telegram SRP 所需的 `current_algo_salt1/current_algo_salt2/current_algo_g/current_algo_p`、`srp_id`、`srp_verifier`、当前 challenge 的 `srp_b_secret/srp_b`、hint、恢复邮箱与开发恢复码状态;`account.getPassword` 会轮换 challenge,`account.updatePasswordSettings/auth.checkPassword/auth.recoverPassword` 都按 SRP 校验。`pending_reset_date` 表示无恢复邮箱密码重置等待期,`account.declinePasswordReset` 会清除它。 - **`temp_auth_key_bindings`** —— `auth.bindTempAuthKey` 的 temp→perm 绑定记录。写入前校验 encrypted `bind_auth_key_inner`,持久化 `temp_session_id`,后续 temp auth_key RPC 在 router 入口解析为 perm auth_key 身份,并缓存在 active session 上。 - **`app_configs`** —— `help.getAppConfig` 的 data-backed JSON config,包含 TDesktop read mark、quote reply 与 native anti-spam 管理入口所需参数。 - **`countries` / `country_codes`** —— `help.getCountriesList` 的登录页国家区号目录。