public async Task <APIResponse> NewPassword([FromBody] NewPasswordModel model) { // validate if (BaseValidableModel.IsInvalid(model, out var errFields)) { return(APIResponse.BadRequest(errFields)); } var user = (DAL.Models.Identity.User)null; var audience = GetCurrentAudience(); var agent = GetUserAgentInfo(); var userLocale = GetUserLocale(); // check token if (!await Core.Tokens.JWT.IsValid( appConfig: AppConfig, jwtToken: model.Token, expectedAudience: JwtAudience.Cabinet, expectedArea: JwtArea.RestorePassword, validStamp: async(jwt, id) => { user = await UserManager.FindByNameAsync(id); return(""); } ) || user == null) { return(APIResponse.BadRequest(nameof(model.Token), "Invalid token")); } await UserManager.RemovePasswordAsync(user); await UserManager.AddPasswordAsync(user, model.Password); if (audience != null) { UserAccount.GenerateJwtSalt(user, audience.Value); await DbContext.SaveChangesAsync(); } // notification await EmailComposer.FromTemplate(await TemplateProvider.GetEmailTemplate(EmailTemplate.PasswordChanged, userLocale)) .Initiator(agent.Ip, agent.Agent, DateTime.UtcNow) .Send(user.Email, user.UserName, EmailQueue) ; // activity var userActivity = CoreLogic.User.CreateUserActivity( user: user, type: Common.UserActivityType.Password, comment: "Password changed", ip: agent.Ip, agent: agent.Agent, locale: userLocale ); DbContext.UserActivity.Add(userActivity); await DbContext.SaveChangesAsync(); return(APIResponse.Success()); }
protected override async Task OnUpdate() { _dbContext.DetachEverything(); var rows = await (from r in _dbContext.EthSending where r.Status == EthereumOperationStatus.Initial select r) .Include(_ => _.User) .Include(_ => _.RelFinHistory) .AsTracking() .Take(_rowsPerRound) .ToArrayAsync(CancellationToken) ; if (IsCancelled() || rows.Length == 0) { return; } var ethAmount = await _ethReader.GetEtherBalance(await _ethWriter.GetEthSender()); foreach (var r in rows) { if (IsCancelled() || ethAmount < r.Amount.ToEther()) { return; } try { r.Status = EthereumOperationStatus.BlockchainInit; _dbContext.SaveChanges(); var tx = await _ethWriter.SendEth(r.Address, r.Amount.ToEther()); r.Status = EthereumOperationStatus.BlockchainConfirm; r.Transaction = tx; r.TimeNextCheck = DateTime.UtcNow.AddSeconds(60); ethAmount -= r.Amount.ToEther(); try { // notification await EmailComposer.FromTemplate(await _templateProvider.GetEmailTemplate(EmailTemplate.ExchangeEthTransferred, Locale.En)) .ReplaceBodyTag("REQUEST_ID", r.Id.ToString()) .ReplaceBodyTag("ETHERSCAN_LINK", _appConfig.Services.Ethereum.EtherscanTxView + tx) .ReplaceBodyTag("DETAILS_SOURCE", r.RelFinHistory?.SourceAmount ?? "?" + " GOLD") .ReplaceBodyTag("DETAILS_ESTIMATED", r.RelFinHistory?.DestinationAmount ?? "?" + " ETH") .ReplaceBodyTag("DETAILS_ADDRESS", TextFormatter.MaskBlockchainAddress(r.Address)) .Send(r.User.Email, r.User.UserName, _notificationQueue) ; } catch { } } catch (Exception e) { Logger.Error(e, $"Failed to process #{r.Id}"); } } }
public async Task <APIResponse> ChangePassword([FromBody] ChangePasswordModel model) { // validate if (BaseValidableModel.IsInvalid(model, out var errFields)) { return(APIResponse.BadRequest(errFields)); } var user = await GetUserFromDb(); var agent = GetUserAgentInfo(); var userLocale = GetUserLocale(); // first check tfa if (user.TwoFactorEnabled && !Core.Tokens.GoogleAuthenticator.Validate(model.TfaCode, user.TfaSecret)) { return(APIResponse.BadRequest(nameof(model.TfaCode), "Invalid 2fa code")); } // check current password if (await UserManager.HasPasswordAsync(user) && (model.Current == null || !await UserManager.CheckPasswordAsync(user, model.Current))) { return(APIResponse.BadRequest(nameof(model.Current), "Invalid current password")); } // set new password await UserManager.RemovePasswordAsync(user); await UserManager.AddPasswordAsync(user, model.New); // notification await EmailComposer.FromTemplate(await TemplateProvider.GetEmailTemplate(EmailTemplate.PasswordChanged, userLocale)) .Initiator(agent.Ip, agent.Agent, DateTime.UtcNow) .Send(user.Email, user.UserName, EmailQueue) ; // activity var userActivity = CoreLogic.User.CreateUserActivity( user: user, type: Common.UserActivityType.Password, comment: "Password changed", ip: agent.Ip, agent: agent.Agent, locale: userLocale ); DbContext.UserActivity.Add(userActivity); await DbContext.SaveChangesAsync(); return(APIResponse.Success( new ChangePasswordView() { } )); }
public async Task <APIResponse> Register([FromBody] RegisterModel model) { // validate if (BaseValidableModel.IsInvalid(model, out var errFields)) { return(APIResponse.BadRequest(errFields)); } var agent = GetUserAgentInfo(); var userLocale = GetUserLocale(); // captcha if (!HostingEnvironment.IsDevelopment()) { if (!await Core.Recaptcha.Verify(AppConfig.Services.Recaptcha.SecretKey, model.Captcha, agent.Ip)) { return(APIResponse.BadRequest(nameof(model.Captcha), "Failed to validate captcha")); } } var result = await Core.UserAccount.CreateUserAccount(HttpContext.RequestServices, model.Email, model.Password); if (result.User != null) { // confirmation token var token = Core.Tokens.JWT.CreateSecurityToken( appConfig: AppConfig, entityId: result.User.UserName, audience: JwtAudience.Cabinet, securityStamp: "", area: Common.JwtArea.Registration, validFor: TimeSpan.FromDays(2) ); var callbackUrl = this.MakeAppLink(JwtAudience.Cabinet, fragment: AppConfig.Apps.Cabinet.RouteSignUpConfirmation.Replace(":token", token)); // email confirmation await EmailComposer.FromTemplate(await TemplateProvider.GetEmailTemplate(EmailTemplate.EmailConfirmation, userLocale)) .Link(callbackUrl) .Send(model.Email, "", EmailQueue) ; // auth token return(APIResponse.Success( new Models.API.v1.User.UserModels.AuthenticateView() { Token = JWT.CreateAuthToken( appConfig: AppConfig, user: result.User, audience: JwtAudience.Cabinet, area: JwtArea.Authorized ), TfaRequired = false, } )); } else { if (result.IsUsernameExists || result.IsEmailExists) { return(APIResponse.BadRequest(APIErrorCode.AccountEmailTaken, "Email is already taken")); } } throw new Exception("Registration failed"); }
public async Task <APIResponse> Password([FromBody] RestoreModel model) { // validate if (BaseValidableModel.IsInvalid(model, out var errFields)) { return(APIResponse.BadRequest(errFields)); } var agent = GetUserAgentInfo(); var userLocale = GetUserLocale(); // captcha if (!HostingEnvironment.IsDevelopment()) { if (!await Core.Recaptcha.Verify(AppConfig.Services.Recaptcha.SecretKey, model.Captcha, agent.Ip)) { return(APIResponse.BadRequest(nameof(model.Captcha), "Failed to validate captcha")); } } // try find user var user = await UserManager.FindByEmailAsync(model.Email); if (user == null || !(await UserManager.IsEmailConfirmedAsync(user))) { return(APIResponse.Success()); } // confirmation token var token = Core.Tokens.JWT.CreateSecurityToken( appConfig: AppConfig, entityId: user.UserName, audience: JwtAudience.Cabinet, area: Common.JwtArea.RestorePassword, securityStamp: "", validFor: TimeSpan.FromHours(24) ); var callbackUrl = this.MakeAppLink(JwtAudience.Cabinet, fragment: AppConfig.Apps.Cabinet.RoutePasswordRestoration.Replace(":token", token)); // restoration email await EmailComposer.FromTemplate(await TemplateProvider.GetEmailTemplate(EmailTemplate.PasswordRestoration, userLocale)) .Link(callbackUrl) .Initiator(agent.Ip, agent.Agent, DateTime.UtcNow) .Send(model.Email, user.UserName, EmailQueue) ; // activity var userActivity = CoreLogic.User.CreateUserActivity( user: user, type: Common.UserActivityType.Password, comment: "Password restoration requested", ip: agent.Ip, agent: agent.Agent, locale: userLocale ); DbContext.UserActivity.Add(userActivity); await DbContext.SaveChangesAsync(); return(APIResponse.Success()); }
public async Task <RedirectResult> ProcessOAuthCallback(LoginProvider provider, UserInfo userInfo) { Logger.Information($"User {userInfo.Id} - login attempt"); var audience = JwtAudience.Cabinet; var userLocale = GetUserLocale(); // find user with this ext login var user = await UserManager.FindByLoginAsync(provider.ToString(), userInfo.Id); // exists if (user != null) { Logger.Information($"User {userInfo.Id} - account {user.Id} found"); // try to sign in var signResult = await SignInManager.CanSignInAsync(user); // can sign in if (signResult) { Logger.Information($"User {userInfo.Id} - can sign in"); var agent = GetUserAgentInfo(); // notification await EmailComposer.FromTemplate(await TemplateProvider.GetEmailTemplate(EmailTemplate.SignedIn, userLocale)) .ReplaceBodyTag("IP", agent.Ip) .Initiator(agent.Ip, agent.Agent, DateTime.UtcNow) .Send(user.Email, user.UserName, EmailQueue) ; // activity var userActivity = CoreLogic.User.CreateUserActivity( user: user, type: Common.UserActivityType.Auth, comment: "Signed in with social network", ip: agent.Ip, agent: agent.Agent, locale: userLocale ); DbContext.UserActivity.Add(userActivity); await DbContext.SaveChangesAsync(); // tfa required if (user.TwoFactorEnabled) { Logger.Information($"User {userInfo.Id} - 2FA required"); var tokenForTfa = JWT.CreateAuthToken( appConfig: AppConfig, user: user, audience: audience, area: JwtArea.Tfa ); return(Redirect( this.MakeAppLink(audience, fragment: AppConfig.Apps.Cabinet.RouteOAuthTfaPage.Replace(":token", tokenForTfa)) )); } // new jwt salt UserAccount.GenerateJwtSalt(user, audience); DbContext.SaveChanges(); Logger.Information($"User {userInfo.Id} - signed in"); // ok var token = JWT.CreateAuthToken( appConfig: AppConfig, user: user, audience: audience, area: JwtArea.Authorized ); return(Redirect( this.MakeAppLink(audience, fragment: AppConfig.Apps.Cabinet.RouteOAuthAuthorized.Replace(":token", token)) )); } Logger.Information($"User {userInfo.Id} - failure 1"); // never should get here return(Redirect(MakeAppLink(Common.JwtAudience.Cabinet))); } // doesnt exist yet else { Logger.Information($"User {userInfo.Id} - account creation"); // try create and sign in var cuaResult = await Core.UserAccount.CreateUserAccount(HttpContext.RequestServices, userInfo.Email, null, true); if (cuaResult.User != null) { Logger.Information($"User {userInfo.Id} - account {cuaResult.User.Id} created"); // user created and external login attached if (await CreateExternalLogin(cuaResult.User, provider, userInfo)) { Logger.Information($"User {userInfo.Id} - external login created"); // ok var token = JWT.CreateAuthToken( appConfig: AppConfig, user: cuaResult.User, audience: audience, area: JwtArea.Authorized ); return(Redirect( this.MakeAppLink(audience, fragment: AppConfig.Apps.Cabinet.RouteOAuthAuthorized.Replace(":token", token)) )); } Logger.Information($"User {userInfo.Id} - failure 2"); // failed return(Redirect(MakeAppLink(Common.JwtAudience.Cabinet))); } Logger.Information($"User {userInfo.Id} - failure 3"); // redirect to error OR email input return(Redirect( this.MakeAppLink(audience, fragment: AppConfig.Apps.Cabinet.RouteEmailTaken) )); } }
public async Task <APIResponse> Authenticate([FromBody] AuthenticateModel model) { var notFoundDesc = "Account not found"; // validate if (BaseValidableModel.IsInvalid(model, out var errFields)) { return(APIResponse.BadRequest(APIErrorCode.AccountNotFound, notFoundDesc)); } var agent = GetUserAgentInfo(); var userLocale = GetUserLocale(); var user = await UserManager.FindByNameAsync(model.Username) ?? await UserManager.FindByEmailAsync(model.Username); if (user != null) { bool isLockedOut = false; // locked out if (user.LockoutEnd != null && user.LockoutEnd.Value.UtcDateTime > DateTime.UtcNow) { // unlock before this check isLockedOut = true; user.LockoutEnd = null; } // get audience JwtAudience audience = JwtAudience.Cabinet; if (!string.IsNullOrWhiteSpace(model.Audience)) { if (Enum.TryParse(model.Audience, true, out JwtAudience aud)) { audience = aud; } } // load options await DbContext.Entry(user).Reference(_ => _.UserOptions).LoadAsync(); var sres = OnSignInResultCheck( services: HttpContext.RequestServices, result: await SignInManager.CheckPasswordSignInAsync(user, model.Password, lockoutOnFailure: true), audience: audience, user: user, tfaRequired: user.TwoFactorEnabled ); if (sres != null) { // successful result if (sres.GetHttpStatusCode() == System.Net.HttpStatusCode.OK && sres.GetErrorCode() == null) { // notification await EmailComposer.FromTemplate(await TemplateProvider.GetEmailTemplate(EmailTemplate.SignedIn, userLocale)) .ReplaceBodyTag("IP", agent.Ip) .Initiator(agent.Ip, agent.Agent, DateTime.UtcNow) .Send(user.Email, user.UserName, EmailQueue) ; // activity var userActivity = CoreLogic.User.CreateUserActivity( user: user, type: Common.UserActivityType.Auth, comment: "Signed in with password", ip: agent.Ip, agent: agent.Agent, locale: userLocale ); DbContext.UserActivity.Add(userActivity); await DbContext.SaveChangesAsync(); } return(sres); } // was locked before if (isLockedOut) { await UserManager.SetLockoutEndDateAsync(user, (DateTimeOffset)DateTime.UtcNow.AddMinutes(60)); return(APIResponse.BadRequest(APIErrorCode.AccountLocked, "Too many unsuccessful attempts. Account is locked, try to sign in later")); } } return(APIResponse.BadRequest(APIErrorCode.AccountNotFound, notFoundDesc)); }
public async Task <APIResponse> TFAEdit([FromBody] TfaEditModel model) { // validate if (BaseValidableModel.IsInvalid(model, out var errFields)) { return(APIResponse.BadRequest(nameof(model.Code), "Invalid 2fa code")); } var user = await GetUserFromDb(); var agent = GetUserAgentInfo(); var userLocale = GetUserLocale(); var makeChange = user.TwoFactorEnabled != model.Enable; if (makeChange) { if (!Core.Tokens.GoogleAuthenticator.Validate(model.Code, user.TfaSecret)) { return(APIResponse.BadRequest(nameof(model.Code), "Invalid 2fa code")); } user.TwoFactorEnabled = model.Enable; } user.UserOptions.InitialTfaQuest = true; await DbContext.SaveChangesAsync(); // notify if (makeChange) { if (model.Enable) { // notification await EmailComposer.FromTemplate(await TemplateProvider.GetEmailTemplate(EmailTemplate.TfaEnabled, userLocale)) .Initiator(agent.Ip, agent.Agent, DateTime.UtcNow) .Send(user.Email, user.UserName, EmailQueue) ; // activity var userActivity = CoreLogic.User.CreateUserActivity( user: user, type: Common.UserActivityType.Settings, comment: "Two factor authentication enabled", ip: agent.Ip, agent: agent.Agent, locale: userLocale ); DbContext.UserActivity.Add(userActivity); await DbContext.SaveChangesAsync(); } else { // notification await EmailComposer.FromTemplate(await TemplateProvider.GetEmailTemplate(EmailTemplate.TfaDisabled, userLocale)) .Initiator(agent.Ip, agent.Agent, DateTime.UtcNow) .Send(user.Email, user.UserName, EmailQueue) ; // activity var userActivity = CoreLogic.User.CreateUserActivity( user: user, type: Common.UserActivityType.Settings, comment: "Two factor authentication disabled", ip: agent.Ip, agent: agent.Agent, locale: userLocale ); DbContext.UserActivity.Add(userActivity); await DbContext.SaveChangesAsync(); } } return(APIResponse.Success(MakeTFASetupView(user))); }