Esempio n. 1
0
        public async Task <APIResponse> AddRequest([FromBody] AddTokenRequestViewModel viewModel)
        {
            var model = Mapper.Map <AddTokenRequest>(viewModel);

            model.IsEnabled   = true;
            model.TimeCreated = DateTime.Now;

            DbContext.AddTokenRequests.Add(model);

            await DbContext.SaveChangesAsync();

            try {
                var body = $@"
					Hello from fotron.io
					There is a new request:

					Company: {model.CompanyName}
					Email: {model.ContactEmail}
					Website: {model.WebsiteUrl}
					
					Token ticker: {model.TokenTicker}
					Token contract address: {model.TokenContractAddress}
					Start price: {model.StartPriceEth} ETH
					Total token supply: {model.TotalSupply}
				"                ;
                await EmailSender.Send(AppConfig.Apps.AdminEmails, "New request", body.Replace("\t", ""));
            }
            catch {
            }

            return(APIResponse.Success());
        }
Esempio n. 2
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. 3
0
        public async Task <APIResponse> DebugAuth(long id, string audi)
        {
            var user = await UserManager.FindByIdAsync(id.ToString());

            JwtAudience audience = JwtAudience.Cabinet;

            if (!string.IsNullOrWhiteSpace(audi))
            {
                if (Enum.TryParse(audi, true, out JwtAudience aud))
                {
                    audience = aud;
                }
            }

            // denied
            var accessRightsMask = Core.UserAccount.ResolveAccessRightsMask(HttpContext.RequestServices, audience, user);

            if (accessRightsMask == null)
            {
                return(null);
            }

            return(APIResponse.Success(
                       new AuthenticateView()
            {
                Token = JWT.CreateAuthToken(
                    appConfig: AppConfig,
                    user: user,
                    audience: audience,
                    area: JwtArea.Authorized,
                    rightsMask: accessRightsMask.Value
                    ),
                TfaRequired = false,
            }));
        }
Esempio n. 4
0
        public async Task <APIResponse> GetTokenList()
        {
            var query = DbContext.Tokens.Where(x => x.IsEnabled && !x.IsDeleted);

            var list = new List <TokenBaseInfoResponseViewModel>();

            (await query.AsNoTracking().ToListAsync()).ForEach(x => list.Add(Mapper.Map <TokenBaseInfoResponseViewModel>(x)));

            foreach (var token in list)
            {
                var last7DStatList = await DbContext.TokenStatistics.Where(x => x.TokenId == token.Id && x.Date >= DateTime.Now.AddDays(-7)).ToListAsync();

                token.PriceStatistics7D = last7DStatList.Select(x => x.PriceEth).ToList();

                if (last7DStatList.Count > 1)
                {
                    var prevDayPrice = last7DStatList[last7DStatList.Count - 2].PriceEth;
                    if (prevDayPrice > 0)
                    {
                        token.PriceChangeLastDayPercent = (((token.CurrentPriceEth - prevDayPrice) / prevDayPrice) * 100).RoundUp(2);
                    }
                    token.TradingVolume24HEth = (last7DStatList[last7DStatList.Count - 1].VolumeEth - last7DStatList[last7DStatList.Count - 2].VolumeEth).RoundUp(2);
                }
            }

            return(APIResponse.Success(list));
        }
Esempio n. 5
0
        public async Task <APIResponse> Profile()
        {
            var rcfg = RuntimeConfigHolder.Clone();
            var user = await GetUserFromDb();

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

            // user challenges
            var challenges = new List <string>();

            if (!user.UserOptions.InitialTfaQuest && !user.TwoFactorEnabled)
            {
                challenges.Add("2fa");
            }

            return(APIResponse.Success(
                       new ProfileView()
            {
                Id = user.UserName,
                Name = CoreLogic.User.HasFilledPersonalData(user.UserVerification) ? (user.UserVerification.FirstName + " " + user.UserVerification.LastName).Trim() : user.UserName,
                Email = user.Email ?? "",
                TfaEnabled = user.TwoFactorEnabled,
                VerifiedL0 = userTier >= UserTier.Tier1,
                VerifiedL1 = userTier >= UserTier.Tier2,
                Challenges = challenges.ToArray(),
            }
                       ));
        }
Esempio n. 6
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. 7
0
        public async Task <APIResponse> GetTokenFullInfo(RequestByIdViewModel viewModel)
        {
            var item = await DbContext.Tokens.FirstOrDefaultAsync(x => x.Id == viewModel.Id && x.IsEnabled && !x.IsDeleted);

            var res = Mapper.Map <TokenFullInfoResponseViewModel>(item);

            return(APIResponse.Success(res));
        }
Esempio n. 8
0
        public async Task <APIResponse> BannedCountries()
        {
            var list = await(
                from a in DbContext.BannedCountry
                select a.Code.ToUpper()
                ).AsNoTracking().ToArrayAsync();

            return(APIResponse.Success(list));
        }
Esempio n. 9
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. 10
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. 11
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. 12
0
        public async Task <APIResponse> BannedCountries()
        {
            var codes = await(
                from a in DbContext.BannedCountry
                select a.Code.ToUpper()
                ).AsNoTracking().ToArrayAsync();

            return(APIResponse.Success(new BannedCountriesView()
            {
                Codes = codes,
                CallerBanned = codes.Contains(GetUserCountry()),
            }));
        }
Esempio n. 13
0
        public async Task <APIResponse> TFAView()
        {
            var user = await GetUserFromDb();

            // randomize tfa secret
            if (!user.TwoFactorEnabled)
            {
                user.TfaSecret = Core.UserAccount.GenerateTfaSecret();
                await DbContext.SaveChangesAsync();
            }

            return(APIResponse.Success(MakeTFASetupView(user)));
        }
Esempio n. 14
0
        public async Task <APIResponse> Google()
        {
            var provider = HttpContext.RequestServices.GetRequiredService <GoogleProvider>();

            return(APIResponse.Success(
                       new RedirectView()
            {
                Redirect = await provider.GetRedirect(
                    Url.Link("OAuthGoogleCallback", new { }),
                    null
                    ),
            }
                       ));
        }
Esempio n. 15
0
        public async Task <APIResponse> GetTokenStatistics(TokenStatisticsRequestViewModel viewModel)
        {
            var query = DbContext.TokenStatistics.Where(x => x.TokenId == viewModel.Id && x.Date >= Utils.UnixTimestampToDateTime(viewModel.DateFrom));

            if (viewModel.DateTo > 0)
            {
                query = query.Where(x => x.Date <= Utils.UnixTimestampToDateTime(viewModel.DateTo));
            }

            var list = new List <TokenStatisticsResponseViewModel>();

            (await query.AsNoTracking().ToListAsync()).ForEach(x => list.Add(Mapper.Map <TokenStatisticsResponseViewModel>(x)));

            return(APIResponse.Success(list));
        }
Esempio n. 16
0
        public async Task <APIResponse> SignOut()
        {
            var user = await GetUserFromDb();

            var audience = GetCurrentAudience();

            // new jwt salt
            if (audience != null)
            {
                Core.UserAccount.GenerateJwtSalt(user, audience.Value);
                await DbContext.SaveChangesAsync();
            }

            return(APIResponse.Success());
        }
Esempio n. 17
0
        public async Task <APIResponse> Account()
        {
            var user = await GetUserFromDb();

            var gold = user.UserSumusWallet.BalanceGold.ToSumus();
            var mnt  = user.UserSumusWallet.BalanceMnt.ToSumus();

            return(APIResponse.Success(
                       new AccountView()
            {
                SumusGold = gold.ToString(),
                SumusMnt = mnt.ToString(),
                SumusWallet = user.UserSumusWallet.PublicKey,
            }
                       ));
        }
Esempio n. 18
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. 19
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. 20
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. 21
0
        public async Task <APIResponse> AgreedWithTos()
        {
            var user = await GetUserFromDb();

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

            if (userTier == UserTier.Tier0)
            {
                if (user.UserVerification == null)
                {
                    user.UserVerification = new UserVerification();
                }
                user.UserVerification.AgreedWithTos   = true;
                user.UserVerification.TimeUserChanged = DateTime.UtcNow;
                await DbContext.SaveChangesAsync();
            }

            return(APIResponse.Success());
        }
Esempio n. 22
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. 23
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. 24
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. 25
0
        public async Task <APIResponse> VerificationView()
        {
            var user = await GetUserFromDb();

            return(APIResponse.Success(MakeVerificationView(user)));
        }
Esempio n. 26
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. 27
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. 28
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. 29
0
        public async Task <APIResponse> Status()
        {
            var user = await GetUserFromDb();

            var rcfg = RuntimeConfigHolder.Clone();

            var ethDepositLimits  = v1.User.BuyGoldController.DepositLimits(rcfg, TradableCurrency.Eth);
            var ethWithdrawLimits = v1.User.SellGoldController.WithdrawalLimits(rcfg, TradableCurrency.Eth);
            var ccDepositLimits   = await v1.User.BuyGoldController.DepositLimits(rcfg, DbContext, user.Id, FiatCurrency.Usd);

            var ccWithdrawLimits = await v1.User.SellGoldController.WithdrawalLimits(rcfg, DbContext, user.Id, FiatCurrency.Usd);

            var ret = new StatusView()
            {
                Trading = new StatusViewTrading()
                {
                    EthAllowed = rcfg.Gold.AllowTradingOverall && rcfg.Gold.AllowTradingEth,
                    CreditCardBuyingAllowed  = rcfg.Gold.AllowTradingOverall && rcfg.Gold.AllowBuyingCreditCard,
                    CreditCardSellingAllowed = rcfg.Gold.AllowTradingOverall && rcfg.Gold.AllowSellingCreditCard,
                },
                Limits = new StatusViewLimits()
                {
                    Eth = new StatusViewLimits.Method()
                    {
                        Deposit = new StatusViewLimits.MinMax()
                        {
                            Min         = ethDepositLimits.Min.ToString(),
                            Max         = ethDepositLimits.Max.ToString(),
                            AccountMax  = "0",
                            AccountUsed = "0",
                        },
                        Withdraw = new StatusViewLimits.MinMax()
                        {
                            Min         = ethWithdrawLimits.Min.ToString(),
                            Max         = ethWithdrawLimits.Max.ToString(),
                            AccountMax  = "0",
                            AccountUsed = "0",
                        }
                    },
                    CreditCardUsd = new StatusViewLimits.Method()
                    {
                        Deposit = new StatusViewLimits.MinMax()
                        {
                            Min         = (long)ccDepositLimits.Min / 100d,
                            Max         = (long)ccDepositLimits.Max / 100d,
                            AccountMax  = (long)ccDepositLimits.AccountMax / 100d,
                            AccountUsed = (long)ccDepositLimits.AccountUsed / 100d,
                        },
                        Withdraw = new StatusViewLimits.MinMax()
                        {
                            Min         = (long)ccWithdrawLimits.Min / 100d,
                            Max         = (long)ccWithdrawLimits.Max / 100d,
                            AccountMax  = (long)ccWithdrawLimits.AccountMax / 100d,
                            AccountUsed = (long)ccWithdrawLimits.AccountUsed / 100d,
                        }
                    },
                },
            };

            return(APIResponse.Success(ret));
        }
Esempio n. 30
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,
            }
                       ));
        }