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());
        }
Exemple #2
0
        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}");
                }
            }
        }
Exemple #3
0
        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()
            {
            }
                       ));
        }
Exemple #4
0
        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));
        }
Exemple #8
0
        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)));
        }