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()); }
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()); }
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, })); }
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)); }
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(), } )); }
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()); }
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)); }
public async Task <APIResponse> BannedCountries() { var list = await( from a in DbContext.BannedCountry select a.Code.ToUpper() ).AsNoTracking().ToArrayAsync(); return(APIResponse.Success(list)); }
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)); }
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); }
public async Task <APIResponse> ChangePassword([FromBody] ChangePasswordModel model) { // validate if (BaseValidableModel.IsInvalid(model, out var errFields)) { return(APIResponse.BadRequest(errFields)); } var user = await GetUserFromDb(); var agent = GetUserAgentInfo(); var userLocale = GetUserLocale(); // first check tfa if (user.TwoFactorEnabled && !Core.Tokens.GoogleAuthenticator.Validate(model.TfaCode, user.TfaSecret)) { return(APIResponse.BadRequest(nameof(model.TfaCode), "Invalid 2fa code")); } // check current password if (await UserManager.HasPasswordAsync(user) && (model.Current == null || !await UserManager.CheckPasswordAsync(user, model.Current))) { return(APIResponse.BadRequest(nameof(model.Current), "Invalid current password")); } // set new password await UserManager.RemovePasswordAsync(user); await UserManager.AddPasswordAsync(user, model.New); // notification await EmailComposer.FromTemplate(await TemplateProvider.GetEmailTemplate(EmailTemplate.PasswordChanged, userLocale)) .Initiator(agent.Ip, agent.Agent, DateTime.UtcNow) .Send(user.Email, user.UserName, EmailQueue) ; // activity var userActivity = CoreLogic.User.CreateUserActivity( user: user, type: Common.UserActivityType.Password, comment: "Password changed", ip: agent.Ip, agent: agent.Agent, locale: userLocale ); DbContext.UserActivity.Add(userActivity); await DbContext.SaveChangesAsync(); return(APIResponse.Success( new ChangePasswordView() { } )); }
public async Task <APIResponse> 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()), })); }
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))); }
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 ), } )); }
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)); }
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()); }
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, } )); }
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, } )); }
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))); }
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() { } )); }
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()); }
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 ), } )); }
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, } )); }
public async Task <APIResponse> Register([FromBody] RegisterModel model) { // validate if (BaseValidableModel.IsInvalid(model, out var errFields)) { return(APIResponse.BadRequest(errFields)); } var agent = GetUserAgentInfo(); var userLocale = GetUserLocale(); // captcha if (!HostingEnvironment.IsDevelopment()) { if (!await Core.Recaptcha.Verify(AppConfig.Services.Recaptcha.SecretKey, model.Captcha, agent.Ip)) { return(APIResponse.BadRequest(nameof(model.Captcha), "Failed to validate captcha")); } } var result = await Core.UserAccount.CreateUserAccount(HttpContext.RequestServices, model.Email, model.Password); if (result.User != null) { // confirmation token var token = Core.Tokens.JWT.CreateSecurityToken( appConfig: AppConfig, entityId: result.User.UserName, audience: JwtAudience.Cabinet, securityStamp: "", area: Common.JwtArea.Registration, validFor: TimeSpan.FromDays(2) ); var callbackUrl = this.MakeAppLink(JwtAudience.Cabinet, fragment: AppConfig.Apps.Cabinet.RouteSignUpConfirmation.Replace(":token", token)); // email confirmation await EmailComposer.FromTemplate(await TemplateProvider.GetEmailTemplate(EmailTemplate.EmailConfirmation, userLocale)) .Link(callbackUrl) .Send(model.Email, "", EmailQueue) ; // auth token return(APIResponse.Success( new Models.API.v1.User.UserModels.AuthenticateView() { Token = JWT.CreateAuthToken( appConfig: AppConfig, user: result.User, audience: JwtAudience.Cabinet, area: JwtArea.Authorized ), TfaRequired = false, } )); } else { if (result.IsUsernameExists || result.IsEmailExists) { return(APIResponse.BadRequest(APIErrorCode.AccountEmailTaken, "Email is already taken")); } } throw new Exception("Registration failed"); }
public async Task <APIResponse> VerificationView() { var user = await GetUserFromDb(); return(APIResponse.Success(MakeVerificationView(user))); }
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, })); }
public async Task <APIResponse> Password([FromBody] RestoreModel model) { // validate if (BaseValidableModel.IsInvalid(model, out var errFields)) { return(APIResponse.BadRequest(errFields)); } var agent = GetUserAgentInfo(); var userLocale = GetUserLocale(); // captcha if (!HostingEnvironment.IsDevelopment()) { if (!await Core.Recaptcha.Verify(AppConfig.Services.Recaptcha.SecretKey, model.Captcha, agent.Ip)) { return(APIResponse.BadRequest(nameof(model.Captcha), "Failed to validate captcha")); } } // try find user var user = await UserManager.FindByEmailAsync(model.Email); if (user == null || !(await UserManager.IsEmailConfirmedAsync(user))) { return(APIResponse.Success()); } // confirmation token var token = Core.Tokens.JWT.CreateSecurityToken( appConfig: AppConfig, entityId: user.UserName, audience: JwtAudience.Cabinet, area: Common.JwtArea.RestorePassword, securityStamp: "", validFor: TimeSpan.FromHours(24) ); var callbackUrl = this.MakeAppLink(JwtAudience.Cabinet, fragment: AppConfig.Apps.Cabinet.RoutePasswordRestoration.Replace(":token", token)); // restoration email await EmailComposer.FromTemplate(await TemplateProvider.GetEmailTemplate(EmailTemplate.PasswordRestoration, userLocale)) .Link(callbackUrl) .Initiator(agent.Ip, agent.Agent, DateTime.UtcNow) .Send(model.Email, user.UserName, EmailQueue) ; // activity var userActivity = CoreLogic.User.CreateUserActivity( user: user, type: Common.UserActivityType.Password, comment: "Password restoration requested", ip: agent.Ip, agent: agent.Agent, locale: userLocale ); DbContext.UserActivity.Add(userActivity); await DbContext.SaveChangesAsync(); return(APIResponse.Success()); }
public async Task <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() { } )); } } }
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)); }
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, } )); }