Esempio n. 1
0
        public async Task <APIResponse> Confirm([FromBody] ConfirmModel model)
        {
            // validate
            if (BaseValidableModel.IsInvalid(model, out var errFields))
            {
                return(APIResponse.BadRequest(errFields));
            }

            var user       = (DAL.Models.Identity.User)null;
            var agent      = GetUserAgentInfo();
            var userLocale = GetUserLocale();

            // check token
            if (!await JWT.IsValid(
                    appConfig: AppConfig,
                    jwtToken: model.Token,
                    expectedAudience: JwtAudience.Cabinet,
                    expectedArea: Common.JwtArea.Registration,
                    validStamp: async(jwt, id) => {
                user = await UserManager.FindByNameAsync(id);
                return("");
            }
                    ) || user == null)
            {
                return(APIResponse.BadRequest(nameof(model.Token), "Invalid token"));
            }

            if (!user.EmailConfirmed)
            {
                user.EmailConfirmed = true;
                await DbContext.SaveChangesAsync();
            }
            return(APIResponse.Success());
        }
Esempio n. 2
0
        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());
        }
Esempio n. 3
0
        public async Task <APIResponse> Estimate([FromBody] EstimateModel model)
        {
            if (BaseValidableModel.IsInvalid(model, out var errFields))
            {
                return(APIResponse.BadRequest(errFields));
            }

            var exchangeCurrency         = FiatCurrency.Usd;
            TradableCurrency?cryptoToken = null;

            // try parse fiat currency
            if (Enum.TryParse(model.Currency, true, out FiatCurrency fc))
            {
                exchangeCurrency = fc;
            }
            // or crypto currency
            else if (Enum.TryParse(model.Currency, true, out TradableCurrency cc))
            {
                cryptoToken = cc;
            }
            else
            {
                return(APIResponse.BadRequest(nameof(model.Currency), "Invalid format"));
            }

            // try parse amount
            if (!BigInteger.TryParse(model.Amount, out var inputAmount) || inputAmount < 1 || (cryptoToken == null && !model.Reversed && inputAmount > long.MaxValue))
            {
                return(APIResponse.BadRequest(nameof(model.Amount), "Invalid amount"));
            }

            // ---

            var userOrNull = await GetUserFromDb();

            var rcfg = RuntimeConfigHolder.Clone();

            // get user limits
            var limits = cryptoToken != null
                                ? DepositLimits(rcfg, cryptoToken.Value)
                                : await DepositLimits(rcfg, DbContext, userOrNull?.Id, exchangeCurrency)
            ;

            // estimate
            var estimation = await Estimation(rcfg, inputAmount, cryptoToken, exchangeCurrency, model.Reversed, 0, limits.Min, limits.Max);

            if (!estimation.TradingAllowed)
            {
                return(APIResponse.BadRequest(APIErrorCode.TradingNotAllowed));
            }
            if (estimation.IsLimitExceeded)
            {
                return(APIResponse.BadRequest(APIErrorCode.TradingExchangeLimit, estimation.View.Limits));
            }

            return(APIResponse.Success(estimation.View));
        }
Esempio n. 4
0
        private APIResponse OnSignInResultCheck(IServiceProvider services, Microsoft.AspNetCore.Identity.SignInResult result, DAL.Models.Identity.User user, JwtAudience audience, bool tfaRequired)
        {
            if (result != null)
            {
                if (result.Succeeded || result.RequiresTwoFactor)
                {
                    // tfa token
                    if (tfaRequired || result.RequiresTwoFactor)
                    {
                        return(APIResponse.Success(
                                   new AuthenticateView()
                        {
                            Token = JWT.CreateAuthToken(
                                appConfig: AppConfig,
                                user: user,
                                audience: audience,
                                area: JwtArea.Tfa
                                ),
                            TfaRequired = true,
                        }
                                   ));
                    }

                    // new jwt salt
                    UserAccount.GenerateJwtSalt(user, audience);
                    DbContext.SaveChanges();

                    // auth token
                    return(APIResponse.Success(
                               new AuthenticateView()
                    {
                        Token = JWT.CreateAuthToken(
                            appConfig: AppConfig,
                            user: user,
                            audience: audience,
                            area: JwtArea.Authorized
                            ),
                        TfaRequired = false,
                    }
                               ));
                }

                if (result.IsLockedOut)
                {
                    return(APIResponse.BadRequest(APIErrorCode.AccountLocked, "Too many unsuccessful attempts to sign in. Account is locked, try to sign in later"));
                }

                if (result.IsNotAllowed)
                {
                    return(APIResponse.BadRequest(APIErrorCode.AccountEmailNotConfirmed, "Email is not confirmed yet"));
                }
            }

            // not found
            return(null);
        }
Esempio n. 5
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()
            {
            }
                       ));
        }
Esempio n. 6
0
        public IActionResult PostEmployee(
            [FromBody] EmployeeModel employee
            )
        {
            try
            {
                Employee lastEmployee = _employeeService.GetEmployees().OrderByDescending(prop => prop.EmployeeNumber).First();

                int newEmployeeId = lastEmployee.EmployeeNumber + 1;

                employee.EmployeeNumber = newEmployeeId;

                Employee employeeToInsert = new Employee
                {
                    EmployeeNumber = newEmployeeId,
                    FirstName      = employee.FirstName,
                    LastName       = employee.LastName,
                    Gender         = employee.EmployeeGender,
                    BirthDate      = employee.BirthDate,
                    HireDate       = employee.HireDate
                };

                _employeeService.InsertEmployee(employeeToInsert);

                return(Created($"/api/employees/{newEmployeeId}", employee));
            }
            catch (GenericServiceException genericServiceException)
            {
                if (genericServiceException.GenericExceptionResponse.Equals(GenericExceptionResponse.ConflictException))
                {
                    return(StatusCode(genericServiceException.StatusCode, APIResponse.ApiConflict(genericServiceException.Message)));
                }
                else if (genericServiceException.GenericExceptionResponse.Equals(GenericExceptionResponse.BadConstraintsException))
                {
                    return(StatusCode(genericServiceException.StatusCode, APIResponse.BadRequest()));
                }
                else if (genericServiceException.GenericExceptionResponse.Equals(GenericExceptionResponse.InternalErrorException))
                {
                    return(StatusCode(500, APIResponse.DefaultErrorMessage(genericServiceException.Message, 500)));
                }

                return(StatusCode(500, APIResponse.DefaultErrorMessage(genericServiceException.Message, 500)));
            }
            catch (Exception ex)
            {
                return(StatusCode(500, APIResponse.DefaultErrorMessage(ex.Message, 500)));
            }
        }
Esempio n. 7
0
        public async Task <APIResponse> Activity([FromBody] ActivityModel model)
        {
            var sortExpression = new Dictionary <string, System.Linq.Expressions.Expression <Func <DAL.Models.UserActivity, object> > >()
            {
                { "date", _ => _.TimeCreated },
            };

            // validate
            if (BasePagerModel.IsInvalid(model, sortExpression.Keys, out var errFields))
            {
                return(APIResponse.BadRequest(errFields));
            }

            var user = await GetUserFromDb();

            var query = (
                from a in DbContext.UserActivity
                where a.UserId == user.Id
                select a
                );

            var page = await DalExtensions.PagerAsync(query, model.Offset, model.Limit,
                                                      sortExpression.GetValueOrDefault(model.Sort), model.Ascending
                                                      );

            var list =
                from i in page.Selected
                select new ActivityViewItem()
            {
                Type    = i.Type.ToLower(),
                Comment = i.Comment,
                Ip      = i.Ip,
                Agent   = i.Agent,
                Date    = ((DateTimeOffset)i.TimeCreated).ToUnixTimeSeconds(),
            }
            ;

            return(APIResponse.Success(
                       new ActivityView()
            {
                Items = list.ToArray(),
                Limit = model.Limit,
                Offset = model.Offset,
                Total = page.TotalCount,
            }
                       ));
        }
Esempio n. 8
0
        public async Task <APIResponse> Tfa([FromBody] TfaModel model)
        {
            // validate
            if (BaseValidableModel.IsInvalid(model, out var errFields))
            {
                return(APIResponse.BadRequest(errFields));
            }

            var audience = GetCurrentAudience();

            if (audience == null)
            {
                return(APIResponse.BadRequest(APIErrorCode.Unauthorized));
            }

            var user = await GetUserFromDb();

            if (user != null && user.TwoFactorEnabled)
            {
                // locked out
                if (await UserManager.IsLockedOutAsync(user))
                {
                    return(APIResponse.BadRequest(APIErrorCode.AccountLocked, "Too many unsuccessful attempts. Account is locked, try to sign in later"));
                }

                // by code
                if (GoogleAuthenticator.Validate(model.Code, user.TfaSecret))
                {
                    return(OnSignInResultCheck(
                               services: HttpContext.RequestServices,
                               result: Microsoft.AspNetCore.Identity.SignInResult.Success,
                               user: user,
                               audience: audience.Value,
                               tfaRequired: false
                               ));
                }

                // +1 failed login
                DbContext.Attach <DAL.Models.Identity.User>(user);
                await UserManager.AccessFailedAsync(user);
            }

            return(APIResponse.BadRequest(nameof(model.Code), "Invalid code"));
        }
Esempio n. 9
0
        public async Task <APIResponse> Confirm([FromBody] ConfirmModel model)
        {
            if (BaseValidableModel.IsInvalid(model, out var errFields))
            {
                return(APIResponse.BadRequest(errFields));
            }

            var user = await GetUserFromDb();

            var userLocale = GetUserLocale();
            var agent      = GetUserAgentInfo();

            // ---

            var request = await
                          (
                from r in DbContext.BuyGoldEth
                where
                r.Status == BuySellGoldRequestStatus.Unconfirmed &&
                r.Id == model.RequestId &&
                r.UserId == user.Id &&
                (DateTime.UtcNow - r.TimeCreated).TotalHours < 1.0
                select r
                          )
                          .AsTracking()
                          .FirstOrDefaultAsync()
            ;

            // request not exists
            if (request == null)
            {
                return(APIResponse.BadRequest(nameof(model.RequestId), "Invalid id"));
            }

            request.Status = BuySellGoldRequestStatus.Confirmed;
            await DbContext.SaveChangesAsync();

            return(APIResponse.Success(
                       new ConfirmView()
            {
            }
                       ));
        }
Esempio n. 10
0
        public async Task <APIResponse> VerificationEdit([FromBody] VerificationEditModel model)
        {
            // validate
            if (BaseValidableModel.IsInvalid(model, out var errFields))
            {
                return(APIResponse.BadRequest(errFields));
            }

            var user = await GetUserFromDb();

            var userTier = CoreLogic.User.GetTier(user);

            if (userTier == UserTier.Tier1 && !CoreLogic.User.HasKycVerification(user.UserVerification))
            {
                // format phone number
                var phoneFormatted = Common.TextFormatter.NormalizePhoneNumber(model.PhoneNumber);

                // parse dob
                var dob = DateTime.ParseExact(model.Dob, "dd.MM.yyyy", CultureInfo.InvariantCulture, DateTimeStyles.AssumeUniversal | DateTimeStyles.AdjustToUniversal);

                {
                    user.UserVerification.FirstName  = model.FirstName.Limit(64);
                    user.UserVerification.MiddleName = model.MiddleName?.Limit(64);
                    user.UserVerification.LastName   = model.LastName.Limit(64);
                    user.UserVerification.DoB        = dob;

                    user.UserVerification.PhoneNumber = phoneFormatted.Limit(32);
                    user.UserVerification.Country     = Common.Countries.GetNameByAlpha2(model.Country);
                    user.UserVerification.CountryCode = model.Country.ToUpper();
                    user.UserVerification.State       = model.State.Limit(256);
                    user.UserVerification.City        = model.City.Limit(256);
                    user.UserVerification.PostalCode  = model.PostalCode.Limit(16);
                    user.UserVerification.Street      = model.Street.Limit(256);
                    user.UserVerification.Apartment   = model.Apartment?.Limit(128);

                    user.UserVerification.TimeUserChanged = DateTime.UtcNow;
                }

                await DbContext.SaveChangesAsync();
            }

            return(APIResponse.Success(MakeVerificationView(user)));
        }
Esempio n. 11
0
        public IActionResult PostTitle(
            [FromBody] TitleModel titleModel
            )
        {
            try
            {
                Title titleToInsert = new Title
                {
                    EmployeeNumber = titleModel.EmployeeNumber,
                    Title          = titleModel.EmployeeTitle,
                    FromDate       = titleModel.FromDate,
                    ToDate         = titleModel.ToDate
                };

                _titleService.InsertTitle(titleToInsert);

                return(Created($" /api/employees/{titleModel.EmployeeNumber}/titles/{titleModel.EmployeeTitle}/startDate/{titleModel.FromDate}", titleModel));
            }
            catch (GenericServiceException genericServiceException)
            {
                if (genericServiceException.GenericExceptionResponse.Equals(GenericExceptionResponse.ConflictException))
                {
                    return(StatusCode(genericServiceException.StatusCode, APIResponse.ApiConflict(genericServiceException.Message)));
                }
                else if (genericServiceException.GenericExceptionResponse.Equals(GenericExceptionResponse.BadConstraintsException))
                {
                    return(StatusCode(genericServiceException.StatusCode, APIResponse.BadRequest()));
                }
                else if (genericServiceException.GenericExceptionResponse.Equals(GenericExceptionResponse.InternalErrorException))
                {
                    return(StatusCode(500, APIResponse.DefaultErrorMessage(genericServiceException.Message, 500)));
                }

                return(StatusCode(500, APIResponse.DefaultErrorMessage(genericServiceException.Message, 500)));
            }
            catch (Exception ex)
            {
                return(StatusCode(500, APIResponse.DefaultErrorMessage(ex.Message, 500)));
            }
        }
Esempio n. 12
0
        public IActionResult PostSalary(
            [FromBody] SalaryModel salaryModel
            )
        {
            try
            {
                Salary salaryToInsert = new Salary
                {
                    EmployeeNumber = salaryModel.EmployeeNumber,
                    EmployeeSalary = salaryModel.EmployeeSalary,
                    FromDate       = salaryModel.FromDate,
                    ToDate         = salaryModel.ToDate
                };

                _salaryService.InsertSalary(salaryToInsert);

                return(Created($"/api/employees/{salaryModel.EmployeeNumber}/salaries/startDate/{salaryModel.FromDate}", salaryModel));
            }
            catch (GenericServiceException genericServiceException)
            {
                if (genericServiceException.GenericExceptionResponse.Equals(GenericExceptionResponse.ConflictException))
                {
                    return(StatusCode(genericServiceException.StatusCode, APIResponse.ApiConflict(genericServiceException.Message)));
                }
                else if (genericServiceException.GenericExceptionResponse.Equals(GenericExceptionResponse.BadConstraintsException))
                {
                    return(StatusCode(genericServiceException.StatusCode, APIResponse.BadRequest()));
                }
                else if (genericServiceException.GenericExceptionResponse.Equals(GenericExceptionResponse.InternalErrorException))
                {
                    return(StatusCode(500, APIResponse.DefaultErrorMessage(genericServiceException.Message, 500)));
                }

                return(StatusCode(500, APIResponse.DefaultErrorMessage(genericServiceException.Message, 500)));
            }
            catch (Exception ex)
            {
                return(StatusCode(500, APIResponse.DefaultErrorMessage(ex.Message, 500)));
            }
        }
        public IActionResult PostDepartment(
            [FromBody] DepartmentModel department
            )
        {
            try
            {
                Department lastDepartment = _departmentService.GetDepartments().OrderByDescending(prop => prop.DepartmentNumber).First();

                string departmentNumber = UtilityKit.ConstructDepartmentNumber(lastDepartment.DepartmentNumber.Substring(1));

                department.DepartmentNumber = departmentNumber;

                _departmentService.InsertDepartment(new Department {
                    DepartmentNumber = department.DepartmentNumber, DepartmentName = department.DepartmentName
                });

                return(Created($"/api/departments/{department.DepartmentNumber}", department));
            }
            catch (GenericServiceException genericServiceException)
            {
                if (genericServiceException.GenericExceptionResponse.Equals(GenericExceptionResponse.ConflictException))
                {
                    return(StatusCode(genericServiceException.StatusCode, APIResponse.ApiConflict(genericServiceException.Message)));
                }
                else if (genericServiceException.GenericExceptionResponse.Equals(GenericExceptionResponse.BadConstraintsException))
                {
                    return(StatusCode(genericServiceException.StatusCode, APIResponse.BadRequest()));
                }
                else if (genericServiceException.GenericExceptionResponse.Equals(GenericExceptionResponse.InternalErrorException))
                {
                    return(StatusCode(500, APIResponse.DefaultErrorMessage(genericServiceException.Message, 500)));
                }

                return(StatusCode(500, APIResponse.DefaultErrorMessage(genericServiceException.Message, 500)));
            }
            catch (Exception ex)
            {
                return(StatusCode(500, APIResponse.DefaultErrorMessage(ex.Message, 500)));
            }
        }
        public IActionResult PostDepartmentManager(
            [FromBody] DepartmentManagerModel departmentManager
            )
        {
            try
            {
                _departmentManagerService.InsertDepartmentManager(
                    new DepartmentManager
                {
                    EmployeeNumber   = departmentManager.EmployeeNumber,
                    DepartmentNumber = departmentManager.DepartmentNumber,
                    FromDate         = departmentManager.FromDate,
                    ToDate           = departmentManager.ToDate
                });

                return(Created($"/api/departments/{departmentManager.DepartmentNumber}/managers/{departmentManager.EmployeeNumber}", departmentManager));
            }
            catch (GenericServiceException genericServiceException)
            {
                if (genericServiceException.GenericExceptionResponse.Equals(GenericExceptionResponse.ConflictException))
                {
                    return(StatusCode(genericServiceException.StatusCode, APIResponse.ApiConflict(genericServiceException.Message)));
                }
                else if (genericServiceException.GenericExceptionResponse.Equals(GenericExceptionResponse.BadConstraintsException))
                {
                    return(StatusCode(genericServiceException.StatusCode, APIResponse.BadRequest()));
                }
                else if (genericServiceException.GenericExceptionResponse.Equals(GenericExceptionResponse.InternalErrorException))
                {
                    return(StatusCode(500, APIResponse.DefaultErrorMessage(genericServiceException.Message, 500)));
                }

                return(StatusCode(500, APIResponse.DefaultErrorMessage(genericServiceException.Message, 500)));
            }
            catch (Exception ex)
            {
                return(StatusCode(500, APIResponse.DefaultErrorMessage(ex.Message, 500)));
            }
        }
Esempio n. 15
0
        public async Task <APIResponse> Refresh()
        {
            var user = await GetUserFromDb();

            var audience = GetCurrentAudience();

            if (audience == null)
            {
                return(APIResponse.BadRequest(APIErrorCode.Unauthorized));
            }

            return(APIResponse.Success(
                       new RefreshView()
            {
                Token = JWT.CreateAuthToken(
                    appConfig: AppConfig,
                    user: user,
                    audience: audience.Value,
                    area: JwtArea.Authorized
                    ),
            }
                       ));
        }
Esempio n. 16
0
        public async Task <APIResponse> AssetEth([FromBody] AssetEthModel model)
        {
            // validate
            if (BaseValidableModel.IsInvalid(model, out var errFields))
            {
                return(APIResponse.BadRequest(errFields));
            }

            // try parse amount
            if (!BigInteger.TryParse(model.Amount, out var inputAmount) || inputAmount < 1)
            {
                return(APIResponse.BadRequest(nameof(model.Amount), "Invalid amount"));
            }

            // try parse fiat currency
            var exchangeCurrency = FiatCurrency.Usd;

            if (Enum.TryParse(model.Currency, true, out FiatCurrency fc))
            {
                exchangeCurrency = fc;
            }

            // ---

            var rcfg = RuntimeConfigHolder.Clone();
            var user = await GetUserFromDb();

            // ---

            if (!rcfg.Gold.AllowTradingEth)
            {
                return(APIResponse.BadRequest(APIErrorCode.TradingNotAllowed));
            }

            var limits = DepositLimits(rcfg, TradableCurrency.Eth);

            // estimation
            var estimation = await Estimation(rcfg, inputAmount, TradableCurrency.Eth, exchangeCurrency, model.Reversed, 0d, limits.Min, limits.Max);

            if (!estimation.TradingAllowed || estimation.ResultCurrencyAmount < 1)
            {
                return(APIResponse.BadRequest(APIErrorCode.TradingNotAllowed));
            }
            if (estimation.IsLimitExceeded)
            {
                return(APIResponse.BadRequest(APIErrorCode.TradingExchangeLimit, estimation.View.Limits));
            }

            var timeNow = DateTime.UtcNow;

            // request
            var request = new DAL.Models.BuyGoldEth()
            {
                Status           = BuySellGoldRequestStatus.Unconfirmed,
                ExchangeCurrency = exchangeCurrency,
                GoldRateCents    = estimation.CentsPerGoldRate,
                EthRateCents     = estimation.CentsPerAssetRate,
                TimeCreated      = timeNow,
                UserId           = user.Id,
            };

            DbContext.BuyGoldEth.Add(request);
            await DbContext.SaveChangesAsync();

            // get a token from eth2gold service
            var contractToken = "";
            {
                try {
                    var reply = await Bus.Request(
                        Eth2Gold.Subject.Request.OrderCreate,
                        new Eth2Gold.Request.OrderCreate()
                    {
                        ExternalID = (ulong)request.Id,
                    },
                        Eth2Gold.Request.OrderCreateReply.Parser
                        );

                    if (reply.ResultCase == Eth2Gold.Request.OrderCreateReply.ResultOneofCase.Token)
                    {
                        if (reply.Token.ToByteArray().Length != 32)
                        {
                            throw new Exception($"token is length of {reply.Token.ToByteArray().Length}");
                        }
                        contractToken = BitConverter.ToString(reply.Token.ToByteArray()).Replace("-", string.Empty);
                    }
                    else
                    {
                        throw new Exception(reply.Error);
                    }
                } catch (Exception e) {
                    Logger.Error(e, "Failed to get token from eth2gold service");
                    return(APIResponse.Failure(APIErrorCode.InternalServerError));
                }
            }

            var assetPerGold = CoreLogic.Finance.Estimation.AssetPerGold(TradableCurrency.Eth, estimation.CentsPerAssetRate, estimation.CentsPerGoldRate);

            return(APIResponse.Success(
                       new AssetEthView()
            {
                RequestId = request.Id,
                EthRate = estimation.CentsPerAssetRate / 100d,
                GoldRate = estimation.CentsPerGoldRate / 100d,
                EthPerGoldRate = assetPerGold.ToString(),
                Currency = exchangeCurrency.ToString().ToUpper(),
                Expires = ((DateTimeOffset)timeNow.AddHours(1)).ToUnixTimeSeconds(),
                Estimation = estimation.View,
                ContractToken = contractToken,
            }
                       ));
        }
Esempio n. 17
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");
        }
Esempio n. 18
0
        public async Task <APIResponse> FiatHistory([FromBody] FiatHistoryModel model)
        {
            var sortExpression = new Dictionary <string, System.Linq.Expressions.Expression <Func <DAL.Models.UserFinHistory, object> > >()
            {
                { "date", _ => _.TimeCreated },
                { "type", _ => _.Type },
                { "status", _ => _.Status }
            };

            // validate
            if (BasePagerModel.IsInvalid(model, sortExpression.Keys, out var errFields))
            {
                return(APIResponse.BadRequest(errFields));
            }

            var user = await GetUserFromDb();

            var query = (
                from h in DbContext.UserFinHistory
                where
                h.UserId == user.Id &&
                (
                    h.Status == UserFinHistoryStatus.Manual ||
                    h.Status == UserFinHistoryStatus.Processing ||
                    h.Status == UserFinHistoryStatus.Completed ||
                    h.Status == UserFinHistoryStatus.Failed
                )
                select h
                );

            var page = await query.PagerAsync(
                model.Offset, model.Limit,
                sortExpression.GetValueOrDefault(model.Sort), model.Ascending
                );

            var nowTime = DateTime.UtcNow;

            var list =
                from i in page.Selected
                select new FiatHistoryViewItem()
            {
                Type   = i.Type.ToString().ToLower(),
                Status = (
                    i.Status == UserFinHistoryStatus.Completed
                                                ? 2         // success
                                                : i.Status == UserFinHistoryStatus.Failed
                                                        ? 3 // cancelled/failed
                                                        : 1 // pending
                    ),
                Comment   = i.Comment,
                Src       = i.Source,
                SrcAmount = i.SourceAmount,
                Dst       = i.Destination,
                DstAmount = i.DestinationAmount,
                Date      = ((DateTimeOffset)i.TimeCreated).ToUnixTimeSeconds(),
            }
            ;

            return(APIResponse.Success(
                       new FiatHistoryView()
            {
                Items = list.ToArray(),
                Limit = model.Limit,
                Offset = model.Offset,
                Total = page.TotalCount,
            }
                       ));
        }
Esempio n. 19
0
        public async Task <APIResponse> VerificationKycStart([FromBody] VerificationKycStartModel model)
        {
            // validate
            if (BaseValidableModel.IsInvalid(model, out var errFields))
            {
                return(APIResponse.BadRequest(errFields));
            }

            var user = await GetUserFromDb();

            var userTier = CoreLogic.User.GetTier(user);

            // tos not signed, didn't fill personal data, has kyc already
            if (
                !CoreLogic.User.HasTosSigned(user.UserVerification) ||
                !CoreLogic.User.HasFilledPersonalData(user.UserVerification) ||
                CoreLogic.User.HasKycVerification(user.UserVerification)
                )
            {
                return(APIResponse.BadRequest(APIErrorCode.AccountNotVerified));
            }

            // check previous verification attempt
            var status = MakeVerificationView(user);

            if (status.IsKycPending)
            {
                return(APIResponse.BadRequest(APIErrorCode.RateLimit));
            }

            // ---

            // new kyc ticket
            var ticket = new KycTicket()
            {
                UserId      = user.Id,
                ReferenceId = Guid.NewGuid().ToString("N"),
                Method      = "general",

                FirstName   = user.UserVerification.FirstName,
                LastName    = user.UserVerification.LastName,
                DoB         = user.UserVerification.DoB.Value,
                CountryCode = user.UserVerification.CountryCode,
                PhoneNumber = user.UserVerification.PhoneNumber,
                TimeCreated = DateTime.UtcNow,
            };

            DbContext.KycShuftiProTicket.Add(ticket);
            await DbContext.SaveChangesAsync();

            // set last ticket
            user.UserVerification.LastKycTicket = ticket;
            await DbContext.SaveChangesAsync();

            // new redirect
            var kycUser = new CoreLogic.Services.KYC.UserData()
            {
                FirstName    = ticket.FirstName,
                LastName     = ticket.LastName,
                CountryCode  = ticket.CountryCode,
                LanguageCode = GetUserLocale().ToString().ToUpper(),
                DoB          = ticket.DoB,
                PhoneNumber  = ticket.PhoneNumber,
                Email        = user.Email,
            };

            var callbackUrl         = Url.Link("CallbackShuftiPro", new { /*secret = AppConfig.Services.ShuftiPro.CallbackSecret*/ });
            var userTempRedirectUrl = Url.Link("CallbackRedirect", new { to = System.Web.HttpUtility.UrlEncode(model.Redirect) });
            var kycRedirect         = await KycExternalProvider.GetRedirect(
                kycUser,
                ticket.ReferenceId,
                userTempRedirectUrl,
                callbackUrl
                );

            Logger.Verbose($"{user.UserName} got kyc redirect to {kycRedirect} with callback to {callbackUrl} and middle redirect to {userTempRedirectUrl}");

            return(APIResponse.Success(new VerificationKycStartView()
            {
                TicketId = ticket.Id.ToString(),
                Redirect = kycRedirect,
            }));
        }
Esempio n. 20
0
        public void Configure(IApplicationBuilder app, IApplicationLifetime applicationLifetime, IRuntimeConfigLoader runtimeConfigLoader)
        {
            applicationLifetime.ApplicationStopping.Register(OnServerStopRequested);
            applicationLifetime.ApplicationStopped.Register(OnServerStopped);

            // globlization
            app.UseRequestLocalization(new RequestLocalizationOptions {
                DefaultRequestCulture = new Microsoft.AspNetCore.Localization.RequestCulture(System.Globalization.CultureInfo.InvariantCulture),
                SupportedCultures     = new List <System.Globalization.CultureInfo> {
                    System.Globalization.CultureInfo.InvariantCulture
                },
                SupportedUICultures = new List <System.Globalization.CultureInfo> {
                    System.Globalization.CultureInfo.InvariantCulture
                },
            });

            // config loader
            _runtimeConfigHolder.SetLoader(runtimeConfigLoader);

            // setup ms logger
            // app.ApplicationServices.GetRequiredService<Microsoft.Extensions.Logging.ILoggerFactory>().AddNLog();

            // nginx proxy
            {
                var forwardingOptions = new ForwardedHeadersOptions()
                {
                    ForwardedHeaders      = ForwardedHeaders.XForwardedFor | ForwardedHeaders.XForwardedProto,
                    RequireHeaderSymmetry = false,
                    ForwardLimit          = null,
                };
                forwardingOptions.KnownNetworks.Clear();
                forwardingOptions.KnownProxies.Clear();
                app.UseForwardedHeaders(forwardingOptions);
            }

            // 503: response on exception
            app.UseExceptionHandler(builder => {
                builder.Run(async context => {
                    var error = context.Features.Get <IExceptionHandlerFeature>();
                    context.RequestServices?.GetService <ILogger>()?.ForContext(this.GetType())?.Error(error?.Error ?? new Exception("No extra data"), "Service failure");
                    var resp = APIResponse.GeneralInternalFailure(error?.Error, !_environment.IsProduction());
                    await resp.WriteResponse(context).ConfigureAwait(false);
                });
            });

            // 403: always write body if unathorized
            app.Use(async(context, next) => {
                await next();
                if (context.Response.StatusCode == 403)
                {
                    var resp = APIResponse.BadRequest(APIErrorCode.Unauthorized);
                    await resp.WriteResponse(context).ConfigureAwait(false);
                }
            });

            // check content type
            app.Use(async(context, next) => {
                var flatPath = context.Request.Path.ToString();

                if (context.Request.Method == "POST" && flatPath.StartsWith("/api/") && !flatPath.Contains("/callback/"))
                {
                    if (!(context.Request.ContentType?.StartsWith("application/json") ?? false))
                    {
                        var resp = APIResponse.BadRequest(APIErrorCode.InvalidContentType, "Json format is only allowed");
                        await resp.WriteResponse(context).ConfigureAwait(false);
                        return;
                    }
                }
                await next();
            });

            // swagger
            if (!_environment.IsProduction())
            {
                app.UseSwagger(opts => {
                });
                app.UseSwaggerUI(opts => {
                    opts.SwaggerEndpoint("/" + ((_appConfig.Apps.RelativeApiPath).Trim('/') + "/swagger/api/swagger.json").Trim('/'), "API");
                });
            }

            // 404: redirect to index: not found, not a file, not api request
            app.Use(async(context, next) => {
                await next();
                if (context.Response.StatusCode == 404)
                {
                    var resp = APIResponse.BadRequest(APIErrorCode.MethodNotFound);
                    await resp.WriteResponse(context).ConfigureAwait(false);
                }
            });

            app.UseAuthentication();

            app.UseCors(opts => {
                opts.WithMethods("GET", "POST", "OPTIONS");
                opts.AllowAnyHeader();
                opts.AllowAnyOrigin();
            }
                        );

            app.UseMvc();

            RunServices();
        }
Esempio n. 21
0
        public async Task <APIResponse> LiteWallet([FromBody] LiteWalletModel model)
        {
            // validate
            if (BaseValidableModel.IsInvalid(model, out var errFields))
            {
                return(APIResponse.BadRequest(errFields));
            }

            var user = await GetUserFromDb();

            var userTier   = CoreLogic.User.GetTier(user);
            var userLocale = GetUserLocale();
            var agent      = GetUserAgentInfo();

            if (userTier < UserTier.Tier2)
            {
                return(APIResponse.BadRequest(APIErrorCode.AccountNotVerified));
            }

            if (model.Amount <= 0.001m || user.UserSumusWallet.BalanceGold < model.Amount)
            {
                return(APIResponse.BadRequest(APIErrorCode.TradingNotAllowed));
            }

            // ---

            var timeNow = DateTime.UtcNow;

            // charge
            using (var scope = HttpContext.RequestServices.CreateScope()) {
                if (await CoreLogic.Finance.SumusWallet.Charge(scope.ServiceProvider, user.Id, model.Amount, SumusToken.Gold))
                {
                    try {
                        var finHistory = new UserFinHistory()
                        {
                            Status            = UserFinHistoryStatus.Processing,
                            Type              = UserFinHistoryType.GoldWithdraw,
                            Source            = "GOLD",
                            SourceAmount      = TextFormatter.FormatTokenAmountFixed(model.Amount),
                            Destination       = "",
                            DestinationAmount = "",
                            Comment           = "",
                            TimeCreated       = timeNow,
                            UserId            = user.Id,
                        };
                        DbContext.UserFinHistory.Add(finHistory);
                        await DbContext.SaveChangesAsync();

                        var request = new WithdrawGold()
                        {
                            Status          = EmissionRequestStatus.Requested,
                            SumAddress      = model.SumusAddress,
                            Amount          = model.Amount,
                            TimeCreated     = timeNow,
                            UserId          = user.Id,
                            RelFinHistoryId = finHistory.Id,
                        };
                        DbContext.WithdrawGold.Add(request);
                        await DbContext.SaveChangesAsync();

                        // mint-sender service
                        {
                            var reply = await Bus.Request(
                                MintSender.Subject.Sender.Request.Send,
                                new MintSender.Sender.Request.Send()
                            {
                                Id        = request.Id.ToString(),
                                Amount    = model.Amount.ToString("F18"),
                                PublicKey = model.SumusAddress,
                                Service   = "core_gold_withdrawer",
                                Token     = "GOLD",
                            },
                                MintSender.Sender.Request.SendReply.Parser,
                                3000
                                );

                            if (!reply.Success)
                            {
                                throw new Exception(reply.Error);
                            }
                        }

                        return(APIResponse.Success(
                                   new LiteWalletView()
                        {
                        }
                                   ));
                    } catch (Exception e) {
                        try {
                            await CoreLogic.Finance.SumusWallet.Refill(scope.ServiceProvider, user.Id, model.Amount, SumusToken.Gold);
                        } catch { }
                        Logger.Error(e, $"Failed to withdraw user {model.Amount} GOLD");
                        return(APIResponse.GeneralInternalFailure(e));
                    }
                }
                else
                {
                    return(APIResponse.BadRequest(APIErrorCode.TradingNotAllowed));
                }
            }
        }
Esempio n. 22
0
        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));
        }
Esempio n. 23
0
        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());
        }
Esempio n. 24
0
        public async Task <APIResponse> Confirm([FromBody] ConfirmModel model)
        {
            // validate
            if (BaseValidableModel.IsInvalid(model, out var errFields))
            {
                return(APIResponse.BadRequest(errFields));
            }

            var user = await GetUserFromDb();

            var userTier   = CoreLogic.User.GetTier(user);
            var userLocale = GetUserLocale();
            var agent      = GetUserAgentInfo();

            if (userTier < UserTier.Tier2)
            {
                return(APIResponse.BadRequest(APIErrorCode.AccountNotVerified));
            }

            // ---

            var request = await
                          (
                from r in DbContext.SellGoldEth
                where
                r.Status == BuySellGoldRequestStatus.Unconfirmed &&
                r.Id == model.RequestId &&
                r.UserId == user.Id &&
                (DateTime.UtcNow - r.TimeCreated).TotalHours < 1.0
                select r
                          )
                          .Include(_ => _.RelFinHistory)
                          .AsTracking()
                          .FirstOrDefaultAsync()
            ;

            // request not exists
            if (request == null)
            {
                return(APIResponse.BadRequest(nameof(model.RequestId), "Invalid id"));
            }

            // charge
            using (var scope = HttpContext.RequestServices.CreateScope()) {
                if (!await CoreLogic.Finance.SumusWallet.Charge(scope.ServiceProvider, request.UserId, request.GoldAmount, SumusToken.Gold))
                {
                    // mark request failed
                    request.Status = BuySellGoldRequestStatus.Failed;
                    if (request.RelFinHistory != null)
                    {
                        request.RelFinHistory.Status  = UserFinHistoryStatus.Failed;
                        request.RelFinHistory.Comment = "Not enough GOLD";
                    }
                    await DbContext.SaveChangesAsync();

                    return(APIResponse.BadRequest(APIErrorCode.TradingNotAllowed));
                }
                else
                {
                    // mark request for processing
                    request.Status = BuySellGoldRequestStatus.Confirmed;
                    if (request.RelFinHistory != null)
                    {
                        request.RelFinHistory.Status = UserFinHistoryStatus.Processing;
                    }
                    await DbContext.SaveChangesAsync();

                    return(APIResponse.Success(
                               new ConfirmView()
                    {
                    }
                               ));
                }
            }
        }
Esempio n. 25
0
        public async Task <APIResponse> Transparency([FromBody] TransparencyModel model)
        {
            var sortExpression = new Dictionary <string, System.Linq.Expressions.Expression <Func <DAL.Models.Transparency, object> > >()
            {
                { "date", _ => _.TimeCreated }
            };

            // validate
            if (Models.API.BasePagerModel.IsInvalid(model, sortExpression.Keys, out var errFields))
            {
                return(APIResponse.BadRequest(errFields));
            }

            var query = (
                from a in DbContext.Transparency
                select a
                );

            var page = await DalExtensions.PagerAsync(query, model.Offset, model.Limit,
                                                      sortExpression.GetValueOrDefault(model.Sort), model.Ascending
                                                      );

            var list =
                from i in page.Selected
                select new TransparencyViewItem()
            {
                Comment = i.Comment,
                Amount  = i.Amount,
                Link    = string.Format("https://ipfs.io/ipfs/{0}", i.Hash),
                Date    = ((DateTimeOffset)i.TimeCreated).ToUnixTimeSeconds(),
            }
            ;

            var stat = await DbContext.TransparencyStat.AsNoTracking().LastOrDefaultAsync();

            var statAssets    = Common.Json.Parse <TransparencyViewStatItem[]>(stat?.AssetsArray ?? "[]");
            var statBonds     = Common.Json.Parse <TransparencyViewStatItem[]>(stat?.BondsArray ?? "[]");
            var statFiat      = Common.Json.Parse <TransparencyViewStatItem[]>(stat?.FiatArray ?? "[]");
            var statGold      = Common.Json.Parse <TransparencyViewStatItem[]>(stat?.GoldArray ?? "[]");
            var statTotalOz   = stat?.TotalOz ?? "";
            var statTotalUsd  = stat?.TotalUsd ?? "";
            var statDataTime  = stat?.DataTimestamp != null? ((DateTimeOffset)stat.DataTimestamp).ToUnixTimeSeconds(): (long?)null;
            var statAuditTime = stat?.AuditTimestamp != null? ((DateTimeOffset)stat.AuditTimestamp).ToUnixTimeSeconds(): (long?)null;

            return(APIResponse.Success(
                       new TransparencyView()
            {
                Stat = new TransparencyViewStat()
                {
                    Assets = statAssets,
                    Bonds = statBonds,
                    Fiat = statFiat,
                    Gold = statGold,
                    TotalOz = statTotalOz,
                    TotalUsd = statTotalUsd,
                    DataTimestamp = statDataTime,
                    AuditTimestamp = statAuditTime,
                },
                Items = list.ToArray(),
                Limit = model.Limit,
                Offset = model.Offset,
                Total = page.TotalCount,
            }
                       ));
        }
Esempio n. 26
0
        public async Task <APIResponse> AssetEth([FromBody] AssetEthModel model)
        {
            // validate
            if (BaseValidableModel.IsInvalid(model, out var errFields))
            {
                return(APIResponse.BadRequest(errFields));
            }

            // try parse amount
            if (!BigInteger.TryParse(model.Amount, out var inputAmount) || inputAmount < 1)
            {
                return(APIResponse.BadRequest(nameof(model.Amount), "Invalid amount"));
            }

            // try parse fiat currency
            var exchangeCurrency = FiatCurrency.Usd;

            if (Enum.TryParse(model.Currency, true, out FiatCurrency fc))
            {
                exchangeCurrency = fc;
            }

            // ---

            var rcfg = RuntimeConfigHolder.Clone();

            var user = await GetUserFromDb();

            var userTier = CoreLogic.User.GetTier(user);
            var agent    = GetUserAgentInfo();

            if (userTier < UserTier.Tier2)
            {
                return(APIResponse.BadRequest(APIErrorCode.AccountNotVerified));
            }

            // ---

            if (!rcfg.Gold.AllowTradingEth)
            {
                return(APIResponse.BadRequest(APIErrorCode.TradingNotAllowed));
            }

            var limits = WithdrawalLimits(rcfg, TradableCurrency.Eth);

            var estimation = await Estimation(rcfg, inputAmount, TradableCurrency.Eth, exchangeCurrency, model.EthAddress, model.Reversed, limits.Min, limits.Max);

            if (!estimation.TradingAllowed || estimation.ResultCurrencyAmount < 1)
            {
                return(APIResponse.BadRequest(APIErrorCode.TradingNotAllowed));
            }
            if (estimation.IsLimitExceeded)
            {
                return(APIResponse.BadRequest(APIErrorCode.TradingExchangeLimit, estimation.View.Limits));
            }

            // limit gold amount to max available
            if (estimation.ResultGoldAmount.FromSumus() > user.UserSumusWallet.BalanceGold)
            {
                estimation = await Estimation(rcfg, user.UserSumusWallet.BalanceGold.ToSumus(), TradableCurrency.Eth, exchangeCurrency, model.EthAddress, false, limits.Min, limits.Max);

                if (!estimation.TradingAllowed || estimation.ResultCurrencyAmount < 1)
                {
                    return(APIResponse.BadRequest(APIErrorCode.TradingNotAllowed));
                }
                if (estimation.IsLimitExceeded)
                {
                    return(APIResponse.BadRequest(APIErrorCode.TradingExchangeLimit, estimation.View.Limits));
                }
            }

            var timeNow = DateTime.UtcNow;

            // history
            var finHistory = new DAL.Models.UserFinHistory()
            {
                Status            = UserFinHistoryStatus.Unconfirmed,
                Type              = UserFinHistoryType.GoldSell,
                Source            = "GOLD",
                SourceAmount      = TextFormatter.FormatTokenAmountFixed(estimation.ResultGoldAmount, TokensPrecision.Sumus),
                Destination       = "ETH",
                DestinationAmount = TextFormatter.FormatTokenAmountFixed(estimation.ResultCurrencyAmount, TokensPrecision.Ethereum),
                Comment           = "",
                TimeCreated       = timeNow,
                UserId            = user.Id,
            };

            DbContext.UserFinHistory.Add(finHistory);
            await DbContext.SaveChangesAsync();

            // request
            var request = new DAL.Models.SellGoldEth()
            {
                Status           = BuySellGoldRequestStatus.Unconfirmed,
                GoldAmount       = estimation.ResultGoldAmount.FromSumus(),
                Destination      = model.EthAddress,
                EthAmount        = estimation.ResultCurrencyAmount.FromSumus(),
                ExchangeCurrency = exchangeCurrency,
                GoldRateCents    = estimation.CentsPerGoldRate,
                EthRateCents     = estimation.CentsPerAssetRate,
                TimeCreated      = timeNow,
                RelFinHistoryId  = finHistory.Id,
                UserId           = user.Id,
            };

            // add and save
            DbContext.SellGoldEth.Add(request);
            await DbContext.SaveChangesAsync();

            var assetPerGold = CoreLogic.Finance.Estimation.AssetPerGold(TradableCurrency.Eth, estimation.CentsPerAssetRate, estimation.CentsPerGoldRate);

            return(APIResponse.Success(
                       new AssetEthView()
            {
                RequestId = request.Id,
                EthRate = estimation.CentsPerAssetRate / 100d,
                GoldRate = estimation.CentsPerGoldRate / 100d,
                Currency = exchangeCurrency.ToString().ToUpper(),
                EthPerGoldRate = assetPerGold.ToString(),
                Estimation = estimation.View,
            }
                       ));
        }
Esempio n. 27
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)));
        }