From f1f196274ac4608f596f0b502f17bd4b162d2e5d Mon Sep 17 00:00:00 2001 From: meoacgx Date: Sat, 20 Dec 2025 08:10:12 +0800 Subject: [PATCH] Add 2FA password reset request --- .../Telegram/AccountTelegramToolsService.cs | 44 +++++++++++++ .../ChangeTwoFactorPasswordDialog.razor | 66 +++++++++++++++++-- 2 files changed, 106 insertions(+), 4 deletions(-) diff --git a/src/TelegramPanel.Core/Services/Telegram/AccountTelegramToolsService.cs b/src/TelegramPanel.Core/Services/Telegram/AccountTelegramToolsService.cs index 9471eb7..da0eb46 100644 --- a/src/TelegramPanel.Core/Services/Telegram/AccountTelegramToolsService.cs +++ b/src/TelegramPanel.Core/Services/Telegram/AccountTelegramToolsService.cs @@ -330,6 +330,50 @@ public class AccountTelegramToolsService } } + /// + /// 忘记二级密码:向 Telegram 发起“重置两步验证密码”申请(通常需要等待 7 天)。 + /// + public async Task<(bool Success, string? Error, DateTimeOffset? WaitUntilUtc)> RequestTwoFactorPasswordResetAsync( + int accountId, + CancellationToken cancellationToken = default) + { + try + { + var client = await GetOrCreateConnectedClientAsync(accountId, cancellationToken); + cancellationToken.ThrowIfCancellationRequested(); + + var result = await client.Account_ResetPassword(); + cancellationToken.ThrowIfCancellationRequested(); + + switch (result) + { + case TL.Account_ResetPasswordOk: + return (true, "二级密码已重置成功(现在可以直接重新设置二级密码)", null); + + case TL.Account_ResetPasswordRequestedWait wait: + { + var untilUtc = DateTimeOffset.FromUnixTimeSeconds(wait.until_date); + return (true, $"已提交重置申请,请等待至 {untilUtc:yyyy-MM-dd HH:mm:ss} UTC 后再完成重置/重新设置二级密码", untilUtc); + } + + case TL.Account_ResetPasswordFailedWait failed: + { + var retryUtc = DateTimeOffset.FromUnixTimeSeconds(failed.retry_date); + return (false, $"近期有被取消的重置申请,需等待至 {retryUtc:yyyy-MM-dd HH:mm:ss} UTC 后才能再次申请", retryUtc); + } + + default: + return (false, $"未知返回类型:{result.GetType().Name}", null); + } + } + catch (Exception ex) + { + var (summary, details) = MapTelegramException(ex); + var msg = string.IsNullOrWhiteSpace(details) ? summary : $"{summary}:{details}"; + return (false, msg, null); + } + } + /// /// 获取两步验证找回邮箱状态(是否已绑定、是否存在待确认的邮箱)。 /// diff --git a/src/TelegramPanel.Web/Components/Dialogs/ChangeTwoFactorPasswordDialog.razor b/src/TelegramPanel.Web/Components/Dialogs/ChangeTwoFactorPasswordDialog.razor index 987be1c..577cbe8 100644 --- a/src/TelegramPanel.Web/Components/Dialogs/ChangeTwoFactorPasswordDialog.razor +++ b/src/TelegramPanel.Web/Components/Dialogs/ChangeTwoFactorPasswordDialog.razor @@ -17,6 +17,10 @@ + + 忘记原二级密码时,可发起“重置二级密码”申请(通常需要等待 7 天)。等待结束后,再回来设置新的二级密码即可。 + + @@ -44,7 +48,7 @@ 账号 结果 - 原因 + 原因/提示 @context.Phone @@ -53,7 +57,7 @@ @(context.Success ? "成功" : "失败") - @((context.Error ?? "").Trim()) + @((context.Message ?? "").Trim()) } @@ -61,6 +65,9 @@ 关闭 + + 忘记密码(申请重置) + @if (running) { @@ -154,7 +161,7 @@ processed++; if (ok) success++; else failed++; - results.Add(new ResultRow(a.Phone, ok, err)); + results.Add(new ResultRow(a.Phone, ok, ok ? null : err)); StateHasChanged(); } @@ -170,7 +177,58 @@ } } + private async Task StartReset() + { + if (running) + return; + + if (accounts.Count == 0) + { + Snackbar.Add("未选择账号", Severity.Warning); + return; + } + + bool? confirm = await DialogService.ShowMessageBox( + "确认申请重置", + $"将对 {accounts.Count} 个账号向 Telegram 发起“重置二级密码”申请(通常需要等待 7 天)。是否继续?", + yesText: "继续", cancelText: "取消"); + + if (confirm != true) + return; + + running = true; + processed = 0; + success = 0; + failed = 0; + results.Clear(); + + try + { + foreach (var a in accounts) + { + var (ok, msg, _) = await AccountTelegramTools.RequestTwoFactorPasswordResetAsync( + accountId: a.Id, + cancellationToken: CancellationToken.None); + + processed++; + if (ok) success++; else failed++; + results.Add(new ResultRow(a.Phone, ok, msg)); + StateHasChanged(); + } + + Snackbar.Add($"重置申请已处理:成功 {success}/{accounts.Count},失败 {failed}/{accounts.Count}", failed == 0 ? Severity.Success : Severity.Warning); + } + catch (Exception ex) + { + Snackbar.Add($"执行失败:{ex.Message}", Severity.Error); + } + finally + { + running = false; + } + } + private void Cancel() => MudDialog.Close(); - private sealed record ResultRow(string Phone, bool Success, string? Error); + private sealed record ResultRow(string Phone, bool Success, string? Message); }