Add 2FA password reset request

This commit is contained in:
meoacgx committed 2025-12-20 08:10:12 +08:00
1 parent 0acfc0ffdb
commit f1f196274a
2 files changed
+106 -4

No files matched your search

@@ -330,6 +330,50 @@ public class AccountTelegramToolsService
}
}
/// <summary>
/// 忘记二级密码:向 Telegram 发起“重置两步验证密码”申请(通常需要等待 7 天)。
/// </summary>
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);
}
}
/// <summary>
/// 获取两步验证找回邮箱状态(是否已绑定、是否存在待确认的邮箱)。
/// </summary>
@@ -17,6 +17,10 @@
<MudTextField @bind-Value="currentPassword" Label="原二级密码" Variant="Variant.Outlined" InputType="InputType.Password"
HelperText="如果账号未开启两步验证,可留空" />
<MudAlert Severity="Severity.Info" Variant="Variant.Outlined" Dense="true">
忘记原二级密码时,可发起“重置二级密码”申请(通常需要等待 7 天)。等待结束后,再回来设置新的二级密码即可。
</MudAlert>
<MudTextField @bind-Value="newPassword" Label="新二级密码" Variant="Variant.Outlined" InputType="InputType.Password"
Required="true" />
@@ -44,7 +48,7 @@
<HeaderContent>
<MudTh>账号</MudTh>
<MudTh>结果</MudTh>
<MudTh>原因</MudTh>
<MudTh>原因/提示</MudTh>
</HeaderContent>
<RowTemplate>
<MudTd DataLabel="账号">@context.Phone</MudTd>
@@ -53,7 +57,7 @@
@(context.Success ? "成功" : "失败")
</MudChip>
</MudTd>
<MudTd DataLabel="原因">@((context.Error ?? "").Trim())</MudTd>
<MudTd DataLabel="原因/提示">@((context.Message ?? "").Trim())</MudTd>
</RowTemplate>
</MudTable>
}
@@ -61,6 +65,9 @@
</DialogContent>
<DialogActions>
<MudButton Variant="Variant.Text" Color="Color.Default" OnClick="Cancel" Disabled="@running">关闭</MudButton>
<MudButton Variant="Variant.Outlined" Color="Color.Warning" OnClick="StartReset" Disabled="@running">
忘记密码(申请重置)
</MudButton>
<MudButton Variant="Variant.Filled" Color="Color.Primary" OnClick="Start" Disabled="@running">
@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);
}