@using System.Timers @using BTCPayServer.Data @using BTCPayServer.Fido2 @using Microsoft.AspNetCore.Http @using Microsoft.AspNetCore.Identity @using Microsoft.AspNetCore.Mvc @using Microsoft.AspNetCore.Routing @using Microsoft.Extensions.Localization @inject AuthenticationStateProvider AuthenticationStateProvider @inject UserManager UserManager @inject UserLoginCodeService UserLoginCodeService @inject LinkGenerator LinkGenerator @inject IHttpContextAccessor HttpContextAccessor @inject IStringLocalizer StringLocalizer @implements IDisposable @if (!string.IsNullOrEmpty(_data)) {

@StringLocalizer["Valid for {0} seconds", _seconds]

} @code { [Parameter] public string UserId { get; set; } [Parameter] public string RedirectUrl { get; set; } [Parameter] public int Size { get; set; } = 256; [Parameter(CaptureUnmatchedValues = true)] public Dictionary Attrs { get; set; } private static readonly double Seconds = UserLoginCodeService.ExpirationTime.TotalSeconds; private double _seconds = Seconds; private string _data; private ApplicationUser _user; private Timer _timer; protected override async Task OnParametersSetAsync() { UserId ??= await GetUserId(); if (!string.IsNullOrEmpty(UserId)) _user = await UserManager.FindByIdAsync(UserId); if (_user == null) return; GenerateCodeAndStartTimer(); } public void Dispose() { _timer?.Dispose(); } private void GenerateCodeAndStartTimer() { var loginCode = UserLoginCodeService.GetOrGenerate(_user.Id); _data = GetData(loginCode); _seconds = Seconds; _timer?.Dispose(); _timer = new Timer(1000); _timer.Elapsed += CountDownTimer; _timer.Enabled = true; } private void CountDownTimer(object source, ElapsedEventArgs e) { if (_seconds > 0) _seconds -= 1; else GenerateCodeAndStartTimer(); InvokeAsync(StateHasChanged); } private async Task GetUserId() { var state = await AuthenticationStateProvider.GetAuthenticationStateAsync(); return state.User.Identity?.IsAuthenticated is true ? UserManager.GetUserId(state.User) : null; } private string GetData(string loginCode) { var req = HttpContextAccessor.HttpContext?.Request; if (req == null) return loginCode; return !string.IsNullOrEmpty(RedirectUrl) ? LinkGenerator.LoginCodeLink(loginCode, RedirectUrl, req.Scheme, req.Host, req.PathBase) : $"{loginCode};{LinkGenerator.IndexLink(req.Scheme, req.Host, req.PathBase)};{_user.Email}"; } private double Percent => Math.Round(_seconds / Seconds * 100); private string CssClass => $"user-login-code d-inline-flex flex-column {(Attrs?.ContainsKey("class") is true ? Attrs["class"] : "")}".Trim(); }