public async Task <IActionResult> UpdateStoreEmailSettings(string storeId, EmailSettings request)
        {
            var store = HttpContext.GetStoreData();

            if (store == null)
            {
                return(StoreNotFound());
            }

            if (!string.IsNullOrEmpty(request.From) && !MailboxAddressValidator.IsMailboxAddress(request.From))
            {
                request.AddModelError(e => e.From,
                                      "Invalid email address", this);
                return(this.CreateValidationError(ModelState));
            }
            var blob = store.GetStoreBlob();

            blob.EmailSettings = request;
            if (store.SetStoreBlob(blob))
            {
                await _storeRepository.UpdateStore(store);
            }

            return(Ok(FromModel(store)));
        }
        protected override ValidationResult IsValid(object value, ValidationContext validationContext)
        {
            if (value is null)
            {
                return(ValidationResult.Success);
            }
            var str = value as string;

            if (MailboxAddressValidator.IsMailboxAddress(str))
            {
                return(ValidationResult.Success);
            }
            return(new ValidationResult(ErrorMessage));
        }
 public void Validate(string prefixKey, ModelStateDictionary modelState)
 {
     if (string.IsNullOrWhiteSpace(From))
     {
         modelState.AddModelError($"{prefixKey}{nameof(From)}", new RequiredAttribute().FormatErrorMessage(nameof(From)));
     }
     if (!MailboxAddressValidator.IsMailboxAddress(From))
     {
         modelState.AddModelError($"{prefixKey}{nameof(From)}", MailboxAddressAttribute.ErrorMessageConst);
     }
     if (string.IsNullOrWhiteSpace(Server))
     {
         modelState.AddModelError($"{prefixKey}{nameof(Server)}", new RequiredAttribute().FormatErrorMessage(nameof(Server)));
     }
     if (Port is null)
     {
         modelState.AddModelError($"{prefixKey}{nameof(Port)}", new RequiredAttribute().FormatErrorMessage(nameof(Port)));
     }
 }
 public bool IsComplete()
 {
     return(MailboxAddressValidator.IsMailboxAddress(From) &&
            !string.IsNullOrWhiteSpace(Server) &&
            Port is int);
 }
        public async Task <IActionResult> CreateUser(CreateApplicationUserRequest request, CancellationToken cancellationToken = default)
        {
            if (request.Email is null)
            {
                ModelState.AddModelError(nameof(request.Email), "Email is missing");
            }
            if (!string.IsNullOrEmpty(request.Email) && !MailboxAddressValidator.IsMailboxAddress(request.Email))
            {
                ModelState.AddModelError(nameof(request.Email), "Invalid email");
            }
            if (request.Password is null)
            {
                ModelState.AddModelError(nameof(request.Password), "Password is missing");
            }
            if (!ModelState.IsValid)
            {
                return(this.CreateValidationError(ModelState));
            }
            if (User.Identity is null)
            {
                throw new JsonHttpException(this.StatusCode(401));
            }
            var anyAdmin = (await _userManager.GetUsersInRoleAsync(Roles.ServerAdmin)).Any();
            var policies = await _settingsRepository.GetSettingAsync <PoliciesSettings>() ?? new PoliciesSettings();

            var isAuth = User.Identity.AuthenticationType == GreenfieldConstants.AuthenticationType;

            // If registration are locked and that an admin exists, don't accept unauthenticated connection
            if (anyAdmin && policies.LockSubscription && !isAuth)
            {
                return(this.CreateAPIError(401, "unauthenticated", "New user creation isn't authorized to users who are not admin"));
            }

            // Even if subscription are unlocked, it is forbidden to create admin unauthenticated
            if (anyAdmin && request.IsAdministrator is true && !isAuth)
            {
                return(this.CreateAPIError(401, "unauthenticated", "New admin creation isn't authorized to users who are not admin"));
            }
            // You are de-facto admin if there is no other admin, else you need to be auth and pass policy requirements
            bool isAdmin = anyAdmin ? (await _authorizationService.AuthorizeAsync(User, null, new PolicyRequirement(Policies.CanModifyServerSettings))).Succeeded &&
                           (await _authorizationService.AuthorizeAsync(User, null, new PolicyRequirement(Policies.Unrestricted))).Succeeded &&
                           isAuth
                                    : true;

            // You need to be admin to create an admin
            if (request.IsAdministrator is true && !isAdmin)
            {
                return(this.CreateAPIPermissionError(Policies.Unrestricted, $"Insufficient API Permissions. Please use an API key with permission: {Policies.Unrestricted} and be an admin."));
            }

            if (!isAdmin && (policies.LockSubscription || PoliciesSettings.DisableNonAdminCreateUserApi))
            {
                // If we are not admin and subscriptions are locked, we need to check the Policies.CanCreateUser.Key permission
                var canCreateUser = (await _authorizationService.AuthorizeAsync(User, null, new PolicyRequirement(Policies.CanCreateUser))).Succeeded;
                if (!isAuth || !canCreateUser)
                {
                    return(this.CreateAPIPermissionError(Policies.CanCreateUser));
                }
            }

            var user = new ApplicationUser
            {
                UserName = request.Email,
                Email    = request.Email,
                RequiresEmailConfirmation = policies.RequiresConfirmedEmail,
                Created = DateTimeOffset.UtcNow,
            };
            var passwordValidation = await this._passwordValidator.ValidateAsync(_userManager, user, request.Password);

            if (!passwordValidation.Succeeded)
            {
                foreach (var error in passwordValidation.Errors)
                {
                    ModelState.AddModelError(nameof(request.Password), error.Description);
                }
                return(this.CreateValidationError(ModelState));
            }
            if (!isAdmin)
            {
                if (!await _throttleService.Throttle(ZoneLimits.Register, this.HttpContext.Connection.RemoteIpAddress, cancellationToken))
                {
                    return(new TooManyRequestsResult(ZoneLimits.Register));
                }
            }
            var identityResult = await _userManager.CreateAsync(user, request.Password);

            if (!identityResult.Succeeded)
            {
                foreach (var error in identityResult.Errors)
                {
                    if (error.Code == "DuplicateUserName")
                    {
                        ModelState.AddModelError(nameof(request.Email), error.Description);
                    }
                    else
                    {
                        ModelState.AddModelError(string.Empty, error.Description);
                    }
                }
                return(this.CreateValidationError(ModelState));
            }

            if (request.IsAdministrator is true)
            {
                if (!anyAdmin)
                {
                    await _roleManager.CreateAsync(new IdentityRole(Roles.ServerAdmin));
                }
                await _userManager.AddToRoleAsync(user, Roles.ServerAdmin);

                if (!anyAdmin)
                {
                    var settings = await _settingsRepository.GetSettingAsync <ThemeSettings>();

                    if (settings != null)
                    {
                        settings.FirstRun = false;
                        await _settingsRepository.UpdateSetting(settings);
                    }

                    await _settingsRepository.FirstAdminRegistered(policies, _options.UpdateUrl != null, _options.DisableRegistration, Logs);
                }
            }
            _eventAggregator.Publish(new UserRegisteredEvent()
            {
                RequestUri = Request.GetAbsoluteRootUri(), User = user, Admin = request.IsAdministrator is true
            });
        internal async Task <InvoiceEntity> CreateInvoiceCoreRaw(InvoiceEntity entity, StoreData store, IPaymentFilter?invoicePaymentMethodFilter, string[]?additionalSearchTerms = null, CancellationToken cancellationToken = default)
        {
            InvoiceLogs logs = new InvoiceLogs();

            logs.Write("Creation of invoice starting", InvoiceEventData.EventSeverity.Info);
            var storeBlob = store.GetStoreBlob();

            if (string.IsNullOrEmpty(entity.Currency))
            {
                entity.Currency = storeBlob.DefaultCurrency;
            }
            entity.Currency = entity.Currency.Trim().ToUpperInvariant();
            entity.Price    = Math.Max(0.0m, entity.Price);
            var currencyInfo = _CurrencyNameTable.GetNumberFormatInfo(entity.Currency, false);

            if (currencyInfo != null)
            {
                entity.Price = entity.Price.RoundToSignificant(currencyInfo.CurrencyDecimalDigits);
            }
            if (entity.Metadata.TaxIncluded is decimal taxIncluded)
            {
                if (currencyInfo != null)
                {
                    taxIncluded = taxIncluded.RoundToSignificant(currencyInfo.CurrencyDecimalDigits);
                }
                taxIncluded = Math.Max(0.0m, taxIncluded);
                taxIncluded = Math.Min(taxIncluded, entity.Price);
                entity.Metadata.TaxIncluded = taxIncluded;
            }

            var getAppsTaggingStore = _InvoiceRepository.GetAppsTaggingStore(store.Id);

            if (entity.Metadata.BuyerEmail != null)
            {
                if (!MailboxAddressValidator.IsMailboxAddress(entity.Metadata.BuyerEmail))
                {
                    throw new BitpayHttpException(400, "Invalid email");
                }
                entity.RefundMail = entity.Metadata.BuyerEmail;
            }
            entity.Status = InvoiceStatusLegacy.New;
            HashSet <CurrencyPair> currencyPairsToFetch = new HashSet <CurrencyPair>();
            var rules         = storeBlob.GetRateRules(_NetworkProvider);
            var excludeFilter = storeBlob.GetExcludedPaymentMethods(); // Here we can compose filters from other origin with PaymentFilter.Any()

            if (invoicePaymentMethodFilter != null)
            {
                excludeFilter = PaymentFilter.Or(excludeFilter,
                                                 invoicePaymentMethodFilter);
            }
            foreach (var network in store.GetSupportedPaymentMethods(_NetworkProvider)
                     .Where(s => !excludeFilter.Match(s.PaymentId))
                     .Select(c => _NetworkProvider.GetNetwork <BTCPayNetworkBase>(c.PaymentId.CryptoCode))
                     .Where(c => c != null))
            {
                currencyPairsToFetch.Add(new CurrencyPair(network.CryptoCode, entity.Currency));
                foreach (var paymentMethodCriteria in storeBlob.PaymentMethodCriteria)
                {
                    if (paymentMethodCriteria.Value != null)
                    {
                        currencyPairsToFetch.Add(new CurrencyPair(network.CryptoCode, paymentMethodCriteria.Value.Currency));
                    }
                }
            }

            var rateRules = storeBlob.GetRateRules(_NetworkProvider);
            var fetchingByCurrencyPair = _RateProvider.FetchRates(currencyPairsToFetch, rateRules, cancellationToken);
            var fetchingAll            = WhenAllFetched(logs, fetchingByCurrencyPair);

            List <ISupportedPaymentMethod> supported = new List <ISupportedPaymentMethod>();
            var paymentMethods = new PaymentMethodDictionary();

            bool noNeedForMethods = entity.Type != InvoiceType.TopUp && entity.Price == 0m;

            if (!noNeedForMethods)
            {
                // This loop ends with .ToList so we are querying all payment methods at once
                // instead of sequentially to improve response time
                var x1 = store.GetSupportedPaymentMethods(_NetworkProvider)
                         .Where(s => !excludeFilter.Match(s.PaymentId) &&
                                _paymentMethodHandlerDictionary.Support(s.PaymentId))
                         .Select(c =>
                                 (Handler: _paymentMethodHandlerDictionary[c.PaymentId],
                                  SupportedPaymentMethod: c,
                                  Network: _NetworkProvider.GetNetwork <BTCPayNetworkBase>(c.PaymentId.CryptoCode)))
                         .Where(c => c.Network != null).ToList();
                var pmis = x1.Select(tuple => tuple.SupportedPaymentMethod.PaymentId).ToHashSet();
                foreach (var o in x1
                         .Select(o =>
                                 (SupportedPaymentMethod: o.SupportedPaymentMethod,
                                  PaymentMethod: CreatePaymentMethodAsync(fetchingByCurrencyPair, o.Handler,
                                                                          o.SupportedPaymentMethod, o.Network, entity, store, logs, pmis)))
                         .ToList())
                {
                    var paymentMethod = await o.PaymentMethod;
                    if (paymentMethod == null)
                    {
                        continue;
                    }
                    supported.Add(o.SupportedPaymentMethod);
                    paymentMethods.Add(paymentMethod);
                }

                if (supported.Count == 0)
                {
                    StringBuilder errors = new StringBuilder();
                    if (!store.GetSupportedPaymentMethods(_NetworkProvider).Any())
                    {
                        errors.AppendLine(
                            "Warning: No wallet has been linked to your BTCPay Store. See the following link for more information on how to connect your store and wallet. (https://docs.btcpayserver.org/WalletSetup/)");
                    }
                    else
                    {
                        errors.AppendLine("Warning: You have payment methods configured but none of them match any of the requested payment methods (e.g., you requested on-chain BTC invoice but don't have an on-chain wallet configured)");
                    }
                    foreach (var error in logs.ToList())
                    {
                        errors.AppendLine(error.ToString());
                    }

                    throw new BitpayHttpException(400, errors.ToString());
                }
            }
            entity.SetSupportedPaymentMethods(supported);
            entity.SetPaymentMethods(paymentMethods);
            foreach (var app in await getAppsTaggingStore)
            {
                entity.InternalTags.Add(AppService.GetAppInternalTag(app.Id));
            }

            using (logs.Measure("Saving invoice"))
            {
                entity = await _InvoiceRepository.CreateInvoiceAsync(store.Id, entity, additionalSearchTerms);
            }
            _ = Task.Run(async() =>
            {
                try
                {
                    await fetchingAll;
                }
                catch (AggregateException ex)
                {
                    ex.Handle(e => { logs.Write($"Error while fetching rates {ex}", InvoiceEventData.EventSeverity.Error); return(true); });
                }
                await _InvoiceRepository.AddInvoiceLogs(entity.Id, logs);
            });
            _EventAggregator.Publish(new Events.InvoiceEvent(entity, InvoiceEvent.Created));
            return(entity);
        }