public async Task ServerInfoControllerTests() { using (var tester = ServerTester.Create()) { await tester.StartAsync(); var unauthClient = new BTCPayServerClient(tester.PayTester.ServerUri); await AssertHttpError(401, async() => await unauthClient.GetServerInfo()); var user = tester.NewAccount(); user.GrantAccess(); var clientBasic = await user.CreateClient(); var serverInfoData = await clientBasic.GetServerInfo(); Assert.NotNull(serverInfoData); Assert.NotNull(serverInfoData.Version); Assert.NotNull(serverInfoData.Onion); Assert.True(serverInfoData.FullySynched); Assert.Contains("BTC", serverInfoData.SupportedPaymentMethods); Assert.Contains("BTC_LightningLike", serverInfoData.SupportedPaymentMethods); Assert.NotNull(serverInfoData.SyncStatus); Assert.Single(serverInfoData.SyncStatus.Select(s => s.CryptoCode == "BTC")); } }
public async Task UsersControllerTests() { using (var tester = ServerTester.Create()) { await tester.StartAsync(); var user = tester.NewAccount(); user.GrantAccess(); await user.MakeAdmin(); string apiKeyProfile = await GenerateAPIKey(tester, user, Permissions.ProfileManagement); string apiKeyInsufficient = await GenerateAPIKey(tester, user, Permissions.StoreManagement); var clientProfile = new BTCPayServerClient(tester.PayTester.ServerUri, apiKeyProfile); var clientInsufficient = new BTCPayServerClient(tester.PayTester.ServerUri, apiKeyInsufficient); var apiKeyProfileUserData = await clientProfile.GetCurrentUser(); Assert.NotNull(apiKeyProfileUserData); Assert.Equal(apiKeyProfileUserData.Id, user.UserId); Assert.Equal(apiKeyProfileUserData.Email, user.RegisterDetails.Email); await Assert.ThrowsAsync <HttpRequestException>(async() => await clientInsufficient.GetCurrentUser()); } }
public async Task ApiKeysControllerTests() { using (var tester = ServerTester.Create()) { await tester.StartAsync(); var user = tester.NewAccount(); user.GrantAccess(); await user.MakeAdmin(); string apiKey = await GenerateAPIKey(tester, user, Permissions.ServerManagement, Permissions.StoreManagement); var client = new BTCPayServerClient(tester.PayTester.ServerUri, apiKey); //Get current api key var apiKeyData = await client.GetCurrentAPIKeyInfo(); Assert.NotNull(apiKeyData); Assert.Equal(apiKey, apiKeyData.ApiKey); Assert.Equal(user.UserId, apiKeyData.UserId); Assert.Equal(2, apiKeyData.Permissions.Length); //revoke current api key await client.RevokeCurrentAPIKeyInfo(); await Assert.ThrowsAsync <HttpRequestException>(async() => { await client.GetCurrentAPIKeyInfo(); }); } }
public async Task <IActionResult> InitiatePayment(PaymentMethodId paymentMethodId, string[] payoutIds) { await using var ctx = this._dbContextFactory.CreateContext(); ctx.ChangeTracker.QueryTrackingBehavior = QueryTrackingBehavior.NoTracking; var pmi = paymentMethodId.ToString(); var payouts = await ctx.Payouts.Include(data => data.PullPaymentData) .Where(data => payoutIds.Contains(data.Id) && pmi == data.PaymentMethodId && data.State == PayoutState.AwaitingPayment) .ToListAsync(); var pullPaymentIds = payouts.Select(data => data.PullPaymentDataId).Distinct().Where(s => s != null).ToArray(); var storeId = payouts.First().StoreDataId; var network = _btcPayNetworkProvider.GetNetwork <BTCPayNetwork>(paymentMethodId.CryptoCode); List <string> bip21 = new List <string>(); foreach (var payout in payouts) { if (payout.Proof != null) { continue; } var blob = payout.GetBlob(_jsonSerializerSettings); if (payout.GetPaymentMethodId() != paymentMethodId) { continue; } var claim = await ParseClaimDestination(paymentMethodId, blob.Destination); switch (claim.destination) { case UriClaimDestination uriClaimDestination: uriClaimDestination.BitcoinUrl.Amount = new Money(blob.CryptoAmount.Value, MoneyUnit.BTC); var newUri = new UriBuilder(uriClaimDestination.BitcoinUrl.Uri); BTCPayServerClient.AppendPayloadToQuery(newUri, new KeyValuePair <string, object>("payout", payout.Id)); bip21.Add(newUri.Uri.ToString()); break; case AddressClaimDestination addressClaimDestination: var bip21New = network.GenerateBIP21(addressClaimDestination.Address.ToString(), new Money(blob.CryptoAmount.Value, MoneyUnit.BTC)); bip21New.QueryParams.Add("payout", payout.Id); bip21.Add(bip21New.ToString()); break; } } if (bip21.Any()) { return(new RedirectToActionResult("WalletSend", "UIWallets", new { walletId = new WalletId(storeId, paymentMethodId.CryptoCode).ToString(), bip21 })); } return(new RedirectToActionResult("Payouts", "UIWallets", new { walletId = new WalletId(storeId, paymentMethodId.CryptoCode).ToString(), pullPaymentId = pullPaymentIds.Length == 1 ? pullPaymentIds.First() : null })); }
private string GetRedirectToApplicationUrl(Uri redirect, APIKeyData key) { var uri = new UriBuilder(redirect); var permissions = key.GetBlob().Permissions; BTCPayServerClient.AppendPayloadToQuery(uri, new Dictionary <string, object>() { { "key", key.Id }, { "permissions", permissions }, { "user", key.UserId } }); return(uri.Uri.AbsoluteUri); }
public BTCPayService(string endpoint, string storeId, string apiKey, ILogger <BTCPayService> logger) { if (apiKey == null || storeId == null || endpoint == null) { logger.LogWarning("BTCPay Server settings missing, cannot instantiate BTCPayService."); } else { _storeId = storeId; _baseUri = new Uri(endpoint); _client = new BTCPayServerClient(_baseUri, apiKey); } }
public async Task HealthControllerTests() { using (var tester = ServerTester.Create()) { await tester.StartAsync(); var unauthClient = new BTCPayServerClient(tester.PayTester.ServerUri); var apiHealthData = await unauthClient.GetHealth(); Assert.NotNull(apiHealthData); Assert.True(apiHealthData.Synchronized); } }
public async Task SpecificCanModifyStoreCantCreateNewStore() { using (var tester = ServerTester.Create()) { await tester.StartAsync(); var acc = tester.NewAccount(); await acc.GrantAccessAsync(); var unrestricted = await acc.CreateClient(); var response = await unrestricted.CreateStore(new CreateStoreRequest() { Name = "mystore" }); var apiKey = (await unrestricted.CreateAPIKey(new CreateApiKeyRequest() { Permissions = new[] { Permission.Create("btcpay.store.canmodifystoresettings", response.Id) } })).ApiKey; var restricted = new BTCPayServerClient(unrestricted.Host, apiKey); // Unscoped permission should be required for create store await this.AssertHttpError(403, async() => await restricted.CreateStore(new CreateStoreRequest() { Name = "store2" })); // Unrestricted should work fine await unrestricted.CreateStore(new CreateStoreRequest() { Name = "store2" }); // Restricted but unscoped should work fine apiKey = (await unrestricted.CreateAPIKey(new CreateApiKeyRequest() { Permissions = new[] { Permission.Create("btcpay.store.canmodifystoresettings") } })).ApiKey; restricted = new BTCPayServerClient(unrestricted.Host, apiKey); await restricted.CreateStore(new CreateStoreRequest() { Name = "store2" }); } }
public async Task CanCreateApiKeys() { //there are 2 ways to create api keys: //as a user through your profile //as an external application requesting an api key from a user using (var s = SeleniumTester.Create()) { await s.StartAsync(); var tester = s.Server; var user = tester.NewAccount(); user.GrantAccess(); await user.CreateStoreAsync(); s.GoToLogin(); s.Login(user.RegisterDetails.Email, user.RegisterDetails.Password); s.GoToProfile(ManageNavPages.APIKeys); s.Driver.FindElement(By.Id("AddApiKey")).Click(); if (!user.IsAdmin) { //not an admin, so this permission should not show Assert.DoesNotContain("ServerManagementPermission", s.Driver.PageSource); await user.MakeAdmin(); s.Logout(); s.GoToLogin(); s.Login(user.RegisterDetails.Email, user.RegisterDetails.Password); s.GoToProfile(ManageNavPages.APIKeys); s.Driver.FindElement(By.Id("AddApiKey")).Click(); } //server management should show now s.SetCheckbox(s, "ServerManagementPermission", true); s.SetCheckbox(s, "StoreManagementPermission", true); s.Driver.FindElement(By.Id("Generate")).Click(); var superApiKey = s.AssertHappyMessage().FindElement(By.TagName("code")).Text; //this api key has access to everything await TestApiAgainstAccessToken(superApiKey, tester, user, Permissions.ServerManagement, Permissions.StoreManagement); s.Driver.FindElement(By.Id("AddApiKey")).Click(); s.SetCheckbox(s, "ServerManagementPermission", true); s.Driver.FindElement(By.Id("Generate")).Click(); var serverOnlyApiKey = s.AssertHappyMessage().FindElement(By.TagName("code")).Text; await TestApiAgainstAccessToken(serverOnlyApiKey, tester, user, Permissions.ServerManagement); s.Driver.FindElement(By.Id("AddApiKey")).Click(); s.SetCheckbox(s, "StoreManagementPermission", true); s.Driver.FindElement(By.Id("Generate")).Click(); var allStoreOnlyApiKey = s.AssertHappyMessage().FindElement(By.TagName("code")).Text; await TestApiAgainstAccessToken(allStoreOnlyApiKey, tester, user, Permissions.StoreManagement); s.Driver.FindElement(By.Id("AddApiKey")).Click(); s.Driver.FindElement(By.CssSelector("button[value=change-store-mode]")).Click(); //there should be a store already by default in the dropdown var dropdown = s.Driver.FindElement(By.Name("SpecificStores[0]")); var option = dropdown.FindElement(By.TagName("option")); var storeId = option.GetAttribute("value"); option.Click(); s.Driver.FindElement(By.Id("Generate")).Click(); var selectiveStoreApiKey = s.AssertHappyMessage().FindElement(By.TagName("code")).Text; await TestApiAgainstAccessToken(selectiveStoreApiKey, tester, user, Permissions.GetStorePermission(storeId)); s.Driver.FindElement(By.Id("AddApiKey")).Click(); s.Driver.FindElement(By.Id("Generate")).Click(); var noPermissionsApiKey = s.AssertHappyMessage().FindElement(By.TagName("code")).Text; await TestApiAgainstAccessToken(noPermissionsApiKey, tester, user); await Assert.ThrowsAnyAsync <HttpRequestException>(async() => { await TestApiAgainstAccessToken <bool>("incorrect key", $"{TestApiPath}/me/id", tester.PayTester.HttpClient); }); //let's test the authorized screen now //options for authorize are: //applicationName //redirect //permissions //strict //selectiveStores var authUrl = BTCPayServerClient.GenerateAuthorizeUri(tester.PayTester.ServerUri, new[] { Permissions.StoreManagement, Permissions.ServerManagement }).ToString(); s.Driver.Navigate().GoToUrl(authUrl); s.Driver.PageSource.Contains("kukksappname"); Assert.Equal("hidden", s.Driver.FindElement(By.Id("StoreManagementPermission")).GetAttribute("type").ToLowerInvariant()); Assert.Equal("true", s.Driver.FindElement(By.Id("StoreManagementPermission")).GetAttribute("value").ToLowerInvariant()); Assert.Equal("hidden", s.Driver.FindElement(By.Id("ServerManagementPermission")).GetAttribute("type").ToLowerInvariant()); Assert.Equal("true", s.Driver.FindElement(By.Id("ServerManagementPermission")).GetAttribute("value").ToLowerInvariant()); Assert.DoesNotContain("change-store-mode", s.Driver.PageSource); s.Driver.FindElement(By.Id("consent-yes")).Click(); var url = s.Driver.Url; IEnumerable <KeyValuePair <string, string> > results = url.Split("?").Last().Split("&") .Select(s1 => new KeyValuePair <string, string>(s1.Split("=")[0], s1.Split("=")[1])); var apiKeyRepo = s.Server.PayTester.GetService <APIKeyRepository>(); await TestApiAgainstAccessToken(results.Single(pair => pair.Key == "key").Value, tester, user, (await apiKeyRepo.GetKey(results.Single(pair => pair.Key == "key").Value)).GetPermissions()); authUrl = BTCPayServerClient.GenerateAuthorizeUri(tester.PayTester.ServerUri, new[] { Permissions.StoreManagement, Permissions.ServerManagement }, false, true).ToString(); s.Driver.Navigate().GoToUrl(authUrl); Assert.DoesNotContain("kukksappname", s.Driver.PageSource); Assert.Equal("checkbox", s.Driver.FindElement(By.Id("StoreManagementPermission")).GetAttribute("type").ToLowerInvariant()); Assert.Equal("true", s.Driver.FindElement(By.Id("StoreManagementPermission")).GetAttribute("value").ToLowerInvariant()); Assert.Equal("checkbox", s.Driver.FindElement(By.Id("ServerManagementPermission")).GetAttribute("type").ToLowerInvariant()); Assert.Equal("true", s.Driver.FindElement(By.Id("ServerManagementPermission")).GetAttribute("value").ToLowerInvariant()); s.SetCheckbox(s, "ServerManagementPermission", false); Assert.Contains("change-store-mode", s.Driver.PageSource); s.Driver.FindElement(By.Id("consent-yes")).Click(); url = s.Driver.Url; results = url.Split("?").Last().Split("&") .Select(s1 => new KeyValuePair <string, string>(s1.Split("=")[0], s1.Split("=")[1])); await TestApiAgainstAccessToken(results.Single(pair => pair.Key == "key").Value, tester, user, (await apiKeyRepo.GetKey(results.Single(pair => pair.Key == "key").Value)).GetPermissions()); } }
public TestApiKeyController(UserManager <ApplicationUser> userManager, StoreRepository storeRepository, BTCPayServerClient localBTCPayServerClient) { _userManager = userManager; _storeRepository = storeRepository; _localBTCPayServerClient = localBTCPayServerClient; }
public async Task CanCreateApiKeys() { //there are 2 ways to create api keys: //as a user through your profile //as an external application requesting an api key from a user using var s = CreateSeleniumTester(); await s.StartAsync(); var tester = s.Server; var user = tester.NewAccount(); await user.GrantAccessAsync(); await user.MakeAdmin(false); s.GoToLogin(); s.LogIn(user.RegisterDetails.Email, user.RegisterDetails.Password); s.GoToProfile(ManageNavPages.APIKeys); s.Driver.FindElement(By.Id("AddApiKey")).Click(); TestLogs.LogInformation("Checking admin permissions"); //not an admin, so this permission should not show Assert.DoesNotContain("btcpay.server.canmodifyserversettings", s.Driver.PageSource); await user.MakeAdmin(); s.Logout(); s.GoToLogin(); s.LogIn(user.RegisterDetails.Email, user.RegisterDetails.Password); s.GoToProfile(ManageNavPages.APIKeys); s.Driver.FindElement(By.Id("AddApiKey")).Click(); Assert.Contains("btcpay.server.canmodifyserversettings", s.Driver.PageSource); //server management should show now s.Driver.SetCheckbox(By.Id("btcpay.server.canmodifyserversettings"), true); s.Driver.SetCheckbox(By.Id("btcpay.store.canmodifystoresettings"), true); s.Driver.SetCheckbox(By.Id("btcpay.user.canviewprofile"), true); s.Driver.FindElement(By.Id("Generate")).Click(); var superApiKey = s.FindAlertMessage().FindElement(By.TagName("code")).Text; TestLogs.LogInformation("Checking super admin key"); //this api key has access to everything await TestApiAgainstAccessToken(superApiKey, tester, user, Policies.CanModifyServerSettings, Policies.CanModifyStoreSettings, Policies.CanViewProfile); s.Driver.FindElement(By.Id("AddApiKey")).Click(); s.Driver.SetCheckbox(By.Id("btcpay.server.canmodifyserversettings"), true); s.Driver.FindElement(By.Id("Generate")).Click(); var serverOnlyApiKey = s.FindAlertMessage().FindElement(By.TagName("code")).Text; TestLogs.LogInformation("Checking CanModifyServerSettings permissions"); await TestApiAgainstAccessToken(serverOnlyApiKey, tester, user, Policies.CanModifyServerSettings); s.Driver.FindElement(By.Id("AddApiKey")).Click(); s.Driver.SetCheckbox(By.Id("btcpay.store.canmodifystoresettings"), true); s.Driver.FindElement(By.Id("Generate")).Click(); var allStoreOnlyApiKey = s.FindAlertMessage().FindElement(By.TagName("code")).Text; TestLogs.LogInformation("Checking CanModifyStoreSettings permissions"); await TestApiAgainstAccessToken(allStoreOnlyApiKey, tester, user, Policies.CanModifyStoreSettings); s.Driver.FindElement(By.Id("AddApiKey")).Click(); s.Driver.FindElement(By.CssSelector("button[value='btcpay.store.canmodifystoresettings:change-store-mode']")).Click(); //there should be a store already by default in the dropdown var getPermissionValueIndex = s.Driver.FindElement(By.CssSelector("input[value='btcpay.store.canmodifystoresettings']")) .GetAttribute("name") .Replace(".Permission", ".SpecificStores[0]"); var dropdown = s.Driver.FindElement(By.Name(getPermissionValueIndex)); var option = dropdown.FindElement(By.TagName("option")); var storeId = option.GetAttribute("value"); option.Click(); s.Driver.WaitForAndClick(By.Id("Generate")); var selectiveStoreApiKey = s.FindAlertMessage().FindElement(By.TagName("code")).Text; TestLogs.LogInformation("Checking CanModifyStoreSettings with StoreId permissions"); await TestApiAgainstAccessToken(selectiveStoreApiKey, tester, user, Permission.Create(Policies.CanModifyStoreSettings, storeId).ToString()); TestLogs.LogInformation("Adding API key for no permissions"); s.Driver.WaitForAndClick(By.Id("AddApiKey")); TestLogs.LogInformation("Generating API key for no permissions"); s.Driver.WaitForAndClick(By.Id("Generate")); var noPermissionsApiKey = s.FindAlertMessage().FindElement(By.TagName("code")).Text; TestLogs.LogInformation($"Checking no permissions: {noPermissionsApiKey}"); await TestApiAgainstAccessToken(noPermissionsApiKey, tester, user); await Assert.ThrowsAnyAsync <HttpRequestException>(async() => { await TestApiAgainstAccessToken <bool>("incorrect key", $"{TestApiPath}/me/id", tester.PayTester.HttpClient); }); TestLogs.LogInformation("Checking authorize screen"); //let's test the authorized screen now //options for authorize are: //applicationName //redirect //permissions //strict //selectiveStores //redirect //appidentifier var appidentifier = "testapp"; var callbackUrl = s.ServerUri + "postredirect-callback-test"; var authUrl = BTCPayServerClient.GenerateAuthorizeUri(s.ServerUri, new[] { Policies.CanModifyStoreSettings, Policies.CanModifyServerSettings }, applicationDetails: (appidentifier, new Uri(callbackUrl))).ToString(); TestLogs.LogInformation($"Going to auth URL {authUrl}"); s.GoToUrl(authUrl); Assert.Contains(appidentifier, s.Driver.PageSource); Assert.Equal("hidden", s.Driver.FindElement(By.Id("btcpay.store.canmodifystoresettings")).GetAttribute("type").ToLowerInvariant()); Assert.Equal("true", s.Driver.FindElement(By.Id("btcpay.store.canmodifystoresettings")).GetAttribute("value").ToLowerInvariant()); Assert.Equal("hidden", s.Driver.FindElement(By.Id("btcpay.server.canmodifyserversettings")).GetAttribute("type").ToLowerInvariant()); Assert.Equal("true", s.Driver.FindElement(By.Id("btcpay.server.canmodifyserversettings")).GetAttribute("value").ToLowerInvariant()); Assert.DoesNotContain("change-store-mode", s.Driver.PageSource); TestLogs.LogInformation("Going to callback URL"); s.Driver.WaitForAndClick(By.Id("consent-yes")); Assert.Equal(callbackUrl, s.Driver.Url); TestLogs.LogInformation("On callback URL"); var apiKeyRepo = s.Server.PayTester.GetService <APIKeyRepository>(); var accessToken = GetAccessTokenFromCallbackResult(s.Driver); TestLogs.LogInformation($"Access token: {accessToken}"); await TestApiAgainstAccessToken(accessToken, tester, user, (await apiKeyRepo.GetKey(accessToken)).GetBlob().Permissions); authUrl = BTCPayServerClient.GenerateAuthorizeUri(s.ServerUri, new[] { Policies.CanModifyStoreSettings, Policies.CanModifyServerSettings }, false, true, applicationDetails: (null, new Uri(callbackUrl))).ToString(); TestLogs.LogInformation($"Going to auth URL 2 {authUrl}"); s.GoToUrl(authUrl); TestLogs.LogInformation("On auth URL 2"); Assert.DoesNotContain("kukksappname", s.Driver.PageSource); Assert.Equal("checkbox", s.Driver.FindElement(By.Id("btcpay.store.canmodifystoresettings")).GetAttribute("type").ToLowerInvariant()); Assert.Equal("true", s.Driver.FindElement(By.Id("btcpay.store.canmodifystoresettings")).GetAttribute("value").ToLowerInvariant()); Assert.Equal("checkbox", s.Driver.FindElement(By.Id("btcpay.server.canmodifyserversettings")).GetAttribute("type").ToLowerInvariant()); Assert.Equal("true", s.Driver.FindElement(By.Id("btcpay.server.canmodifyserversettings")).GetAttribute("value").ToLowerInvariant()); s.Driver.SetCheckbox(By.Id("btcpay.server.canmodifyserversettings"), false); Assert.Contains("change-store-mode", s.Driver.PageSource); TestLogs.LogInformation("Going to callback URL 2"); s.Driver.WaitForAndClick(By.Id("consent-yes")); Assert.Equal(callbackUrl, s.Driver.Url); TestLogs.LogInformation("On callback URL 2"); accessToken = GetAccessTokenFromCallbackResult(s.Driver); TestLogs.LogInformation($"Access token: {accessToken}"); TestLogs.LogInformation("Checking authorized permissions"); await TestApiAgainstAccessToken(accessToken, tester, user, (await apiKeyRepo.GetKey(accessToken)).GetBlob().Permissions); //let's test the app identifier system TestLogs.LogInformation("Checking app identifier system"); authUrl = BTCPayServerClient.GenerateAuthorizeUri(s.ServerUri, new[] { Policies.CanModifyStoreSettings, Policies.CanModifyServerSettings }, false, true, (appidentifier, new Uri(callbackUrl))).ToString(); //if it's the same, go to the confirm page TestLogs.LogInformation($"Going to auth URL 3 {authUrl}"); s.GoToUrl(authUrl); TestLogs.LogInformation("On auth URL 3"); s.Driver.WaitForAndClick(By.Id("continue")); TestLogs.LogInformation("Going to callback URL 3"); Assert.Equal(callbackUrl, s.Driver.Url); TestLogs.LogInformation("On callback URL 3"); //same app but different redirect = nono authUrl = BTCPayServerClient.GenerateAuthorizeUri(s.ServerUri, new[] { Policies.CanModifyStoreSettings, Policies.CanModifyServerSettings }, false, true, (appidentifier, new Uri("https://international.local/callback"))).ToString(); TestLogs.LogInformation($"Going to auth URL 4 {authUrl}"); s.GoToUrl(authUrl); TestLogs.LogInformation("On auth URL 4"); Assert.False(s.Driver.Url.StartsWith("https://international.com/callback")); // Make sure we can check all permissions when not an admin TestLogs.LogInformation("Make sure we can check all permissions when not an admin"); await user.MakeAdmin(false); s.Logout(); s.GoToLogin(); s.LogIn(user.RegisterDetails.Email, user.RegisterDetails.Password); TestLogs.LogInformation("Go to API Keys page"); s.GoToUrl("/account/apikeys"); TestLogs.LogInformation("On API Keys page"); s.Driver.WaitForAndClick(By.Id("AddApiKey")); int checkedPermissionCount = s.Driver.FindElements(By.ClassName("form-check-input")).Count; TestLogs.LogInformation($"Adding API key: {checkedPermissionCount} permissions"); s.Driver.ExecuteJavaScript("document.querySelectorAll('#Permissions .form-check-input').forEach(i => i.click())"); TestLogs.LogInformation($"Clicked {checkedPermissionCount}"); TestLogs.LogInformation("Generating API key"); s.Driver.WaitForAndClick(By.Id("Generate")); var allAPIKey = s.FindAlertMessage().FindElement(By.TagName("code")).Text; TestLogs.LogInformation($"Checking API key permissions: {allAPIKey}"); var apikeydata = await TestApiAgainstAccessToken <ApiKeyData>(allAPIKey, "api/v1/api-keys/current", tester.PayTester.HttpClient); Assert.Equal(checkedPermissionCount, apikeydata.Permissions.Length); }
public async Task CanCreateUsersViaAPI() { using (var tester = ServerTester.Create(newDb: true)) { tester.PayTester.DisableRegistration = true; await tester.StartAsync(); var unauthClient = new BTCPayServerClient(tester.PayTester.ServerUri); await AssertHttpError(400, async() => await unauthClient.CreateUser(new CreateApplicationUserRequest())); await AssertHttpError(400, async() => await unauthClient.CreateUser(new CreateApplicationUserRequest() { Email = "*****@*****.**" })); // Pass too simple await AssertHttpError(400, async() => await unauthClient.CreateUser(new CreateApplicationUserRequest() { Email = "*****@*****.**", Password = "******" })); // We have no admin, so it should work var user1 = await unauthClient.CreateUser(new CreateApplicationUserRequest() { Email = "*****@*****.**", Password = "******" }); // We have no admin, so it should work var user2 = await unauthClient.CreateUser(new CreateApplicationUserRequest() { Email = "*****@*****.**", Password = "******" }); // Duplicate email await AssertHttpError(400, async() => await unauthClient.CreateUser(new CreateApplicationUserRequest() { Email = "*****@*****.**", Password = "******" })); // Let's make an admin var admin = await unauthClient.CreateUser(new CreateApplicationUserRequest() { Email = "*****@*****.**", Password = "******", IsAdministrator = true }); // Creating a new user without proper creds is now impossible (unauthorized) // Because if registration are locked and that an admin exists, we don't accept unauthenticated connection await AssertHttpError(401, async() => await unauthClient.CreateUser(new CreateApplicationUserRequest() { Email = "*****@*****.**", Password = "******" })); // But should be ok with subscriptions unlocked var settings = tester.PayTester.GetService <SettingsRepository>(); await settings.UpdateSetting <PoliciesSettings>(new PoliciesSettings() { LockSubscription = false }); await unauthClient.CreateUser(new CreateApplicationUserRequest() { Email = "*****@*****.**", Password = "******" }); // But it should be forbidden to create an admin without being authenticated await AssertHttpError(403, async() => await unauthClient.CreateUser(new CreateApplicationUserRequest() { Email = "*****@*****.**", Password = "******", IsAdministrator = true })); await settings.UpdateSetting <PoliciesSettings>(new PoliciesSettings() { LockSubscription = true }); var adminAcc = tester.NewAccount(); adminAcc.UserId = admin.Id; adminAcc.IsAdmin = true; var adminClient = await adminAcc.CreateClient(Policies.CanModifyProfile); // We should be forbidden to create a new user without proper admin permissions await AssertHttpError(403, async() => await adminClient.CreateUser(new CreateApplicationUserRequest() { Email = "*****@*****.**", Password = "******" })); await AssertHttpError(403, async() => await adminClient.CreateUser(new CreateApplicationUserRequest() { Email = "*****@*****.**", Password = "******", IsAdministrator = true })); // However, should be ok with the unrestricted permissions of an admin adminClient = await adminAcc.CreateClient(Policies.Unrestricted); await adminClient.CreateUser(new CreateApplicationUserRequest() { Email = "*****@*****.**", Password = "******" }); // Even creating new admin should be ok await adminClient.CreateUser(new CreateApplicationUserRequest() { Email = "*****@*****.**", Password = "******", IsAdministrator = true }); var user1Acc = tester.NewAccount(); user1Acc.UserId = user1.Id; user1Acc.IsAdmin = false; var user1Client = await user1Acc.CreateClient(Policies.CanModifyServerSettings); // User1 trying to get server management would still fail to create user await AssertHttpError(403, async() => await user1Client.CreateUser(new CreateApplicationUserRequest() { Email = "*****@*****.**", Password = "******" })); // User1 should be able to create user if subscription unlocked await settings.UpdateSetting <PoliciesSettings>(new PoliciesSettings() { LockSubscription = false }); await user1Client.CreateUser(new CreateApplicationUserRequest() { Email = "*****@*****.**", Password = "******" }); // But not an admin await AssertHttpError(403, async() => await user1Client.CreateUser(new CreateApplicationUserRequest() { Email = "*****@*****.**", Password = "******", IsAdministrator = true })); } }
public async Task CanUsePullPaymentViaAPI() { using (var tester = ServerTester.Create()) { await tester.StartAsync(); var acc = tester.NewAccount(); acc.Register(); acc.CreateStore(); var storeId = (await acc.RegisterDerivationSchemeAsync("BTC", importKeysToNBX: true)).StoreId; var client = await acc.CreateClient(); var result = await client.CreatePullPayment(storeId, new Client.Models.CreatePullPaymentRequest() { Name = "Test", Amount = 12.3m, Currency = "BTC", PaymentMethods = new[] { "BTC" } }); void VerifyResult() { Assert.Equal("Test", result.Name); Assert.Null(result.Period); // If it contains ? it means that we are resolving an unknown route with the link generator Assert.DoesNotContain("?", result.ViewLink); Assert.False(result.Archived); Assert.Equal("BTC", result.Currency); Assert.Equal(12.3m, result.Amount); } VerifyResult(); var unauthenticated = new BTCPayServerClient(tester.PayTester.ServerUri); result = await unauthenticated.GetPullPayment(result.Id); VerifyResult(); await AssertHttpError(404, async() => await unauthenticated.GetPullPayment("lol")); // Can't list pull payments unauthenticated await AssertHttpError(401, async() => await unauthenticated.GetPullPayments(storeId)); var pullPayments = await client.GetPullPayments(storeId); result = Assert.Single(pullPayments); VerifyResult(); Thread.Sleep(1000); var test2 = await client.CreatePullPayment(storeId, new Client.Models.CreatePullPaymentRequest() { Name = "Test 2", Amount = 12.3m, Currency = "BTC", PaymentMethods = new[] { "BTC" } }); Logs.Tester.LogInformation("Can't archive without knowing the walletId"); await Assert.ThrowsAsync <HttpRequestException>(async() => await client.ArchivePullPayment("lol", result.Id)); Logs.Tester.LogInformation("Can't archive without permission"); await Assert.ThrowsAsync <HttpRequestException>(async() => await unauthenticated.ArchivePullPayment(storeId, result.Id)); await client.ArchivePullPayment(storeId, result.Id); result = await unauthenticated.GetPullPayment(result.Id); Assert.True(result.Archived); var pps = await client.GetPullPayments(storeId); result = Assert.Single(pps); Assert.Equal("Test 2", result.Name); pps = await client.GetPullPayments(storeId, true); Assert.Equal(2, pps.Length); Assert.Equal("Test 2", pps[0].Name); Assert.Equal("Test", pps[1].Name); var payouts = await unauthenticated.GetPayouts(pps[0].Id); Assert.Empty(payouts); var destination = (await tester.ExplorerNode.GetNewAddressAsync()).ToString(); await this.AssertAPIError("overdraft", async() => await unauthenticated.CreatePayout(pps[0].Id, new CreatePayoutRequest() { Destination = destination, Amount = 1_000_000m, PaymentMethod = "BTC", }));
public async Task <ApplicationUserData> GetUserDataForApiKey(string userApiKey) { var client = new BTCPayServerClient(_baseUri, userApiKey); return(await client.GetCurrentUser()); }
public async Task CanCreateApiKeys() { //there are 2 ways to create api keys: //as a user through your profile //as an external application requesting an api key from a user using (var s = SeleniumTester.Create()) { await s.StartAsync(); var tester = s.Server; var user = tester.NewAccount(); user.GrantAccess(); await user.MakeAdmin(false); s.GoToLogin(); s.Login(user.RegisterDetails.Email, user.RegisterDetails.Password); s.GoToProfile(ManageNavPages.APIKeys); s.Driver.FindElement(By.Id("AddApiKey")).Click(); //not an admin, so this permission should not show Assert.DoesNotContain("btcpay.server.canmodifyserversettings", s.Driver.PageSource); await user.MakeAdmin(); s.Logout(); s.GoToLogin(); s.Login(user.RegisterDetails.Email, user.RegisterDetails.Password); s.GoToProfile(ManageNavPages.APIKeys); s.Driver.FindElement(By.Id("AddApiKey")).Click(); Assert.Contains("btcpay.server.canmodifyserversettings", s.Driver.PageSource); //server management should show now s.SetCheckbox(s, "btcpay.server.canmodifyserversettings", true); s.SetCheckbox(s, "btcpay.store.canmodifystoresettings", true); s.SetCheckbox(s, "btcpay.user.canviewprofile", true); s.Driver.FindElement(By.Id("Generate")).Click(); var superApiKey = s.AssertHappyMessage().FindElement(By.TagName("code")).Text; //this api key has access to everything await TestApiAgainstAccessToken(superApiKey, tester, user, Policies.CanModifyServerSettings, Policies.CanModifyStoreSettings, Policies.CanViewProfile); s.Driver.FindElement(By.Id("AddApiKey")).Click(); s.SetCheckbox(s, "btcpay.server.canmodifyserversettings", true); s.Driver.FindElement(By.Id("Generate")).Click(); var serverOnlyApiKey = s.AssertHappyMessage().FindElement(By.TagName("code")).Text; await TestApiAgainstAccessToken(serverOnlyApiKey, tester, user, Policies.CanModifyServerSettings); s.Driver.FindElement(By.Id("AddApiKey")).Click(); s.SetCheckbox(s, "btcpay.store.canmodifystoresettings", true); s.Driver.FindElement(By.Id("Generate")).Click(); var allStoreOnlyApiKey = s.AssertHappyMessage().FindElement(By.TagName("code")).Text; await TestApiAgainstAccessToken(allStoreOnlyApiKey, tester, user, Policies.CanModifyStoreSettings); s.Driver.FindElement(By.Id("AddApiKey")).Click(); s.Driver.FindElement(By.CssSelector("button[value='btcpay.store.canmodifystoresettings:change-store-mode']")).Click(); //there should be a store already by default in the dropdown var dropdown = s.Driver.FindElement(By.Name("PermissionValues[3].SpecificStores[0]")); var option = dropdown.FindElement(By.TagName("option")); var storeId = option.GetAttribute("value"); option.Click(); s.Driver.FindElement(By.Id("Generate")).Click(); var selectiveStoreApiKey = s.AssertHappyMessage().FindElement(By.TagName("code")).Text; await TestApiAgainstAccessToken(selectiveStoreApiKey, tester, user, Permission.Create(Policies.CanModifyStoreSettings, storeId).ToString()); s.Driver.FindElement(By.Id("AddApiKey")).Click(); s.Driver.FindElement(By.Id("Generate")).Click(); var noPermissionsApiKey = s.AssertHappyMessage().FindElement(By.TagName("code")).Text; await TestApiAgainstAccessToken(noPermissionsApiKey, tester, user); await Assert.ThrowsAnyAsync <HttpRequestException>(async() => { await TestApiAgainstAccessToken <bool>("incorrect key", $"{TestApiPath}/me/id", tester.PayTester.HttpClient); }); //let's test the authorized screen now //options for authorize are: //applicationName //redirect //permissions //strict //selectiveStores //redirect //appidentifier var appidentifier = "testapp"; var callbackUrl = tester.PayTester.ServerUri + "postredirect-callback-test"; var authUrl = BTCPayServerClient.GenerateAuthorizeUri(tester.PayTester.ServerUri, new[] { Policies.CanModifyStoreSettings, Policies.CanModifyServerSettings }, applicationDetails: (appidentifier, new Uri(callbackUrl))).ToString(); s.Driver.Navigate().GoToUrl(authUrl); Assert.Contains(appidentifier, s.Driver.PageSource); Assert.Equal("hidden", s.Driver.FindElement(By.Id("btcpay.store.canmodifystoresettings")).GetAttribute("type").ToLowerInvariant()); Assert.Equal("true", s.Driver.FindElement(By.Id("btcpay.store.canmodifystoresettings")).GetAttribute("value").ToLowerInvariant()); Assert.Equal("hidden", s.Driver.FindElement(By.Id("btcpay.server.canmodifyserversettings")).GetAttribute("type").ToLowerInvariant()); Assert.Equal("true", s.Driver.FindElement(By.Id("btcpay.server.canmodifyserversettings")).GetAttribute("value").ToLowerInvariant()); Assert.DoesNotContain("change-store-mode", s.Driver.PageSource); s.Driver.FindElement(By.Id("consent-yes")).Click(); Assert.Equal(callbackUrl, s.Driver.Url); var apiKeyRepo = s.Server.PayTester.GetService <APIKeyRepository>(); var accessToken = GetAccessTokenFromCallbackResult(s.Driver); await TestApiAgainstAccessToken(accessToken, tester, user, (await apiKeyRepo.GetKey(accessToken)).GetBlob().Permissions); authUrl = BTCPayServerClient.GenerateAuthorizeUri(tester.PayTester.ServerUri, new[] { Policies.CanModifyStoreSettings, Policies.CanModifyServerSettings }, false, true, applicationDetails: (null, new Uri(callbackUrl))).ToString(); s.Driver.Navigate().GoToUrl(authUrl); Assert.DoesNotContain("kukksappname", s.Driver.PageSource); Assert.Equal("checkbox", s.Driver.FindElement(By.Id("btcpay.store.canmodifystoresettings")).GetAttribute("type").ToLowerInvariant()); Assert.Equal("true", s.Driver.FindElement(By.Id("btcpay.store.canmodifystoresettings")).GetAttribute("value").ToLowerInvariant()); Assert.Equal("checkbox", s.Driver.FindElement(By.Id("btcpay.server.canmodifyserversettings")).GetAttribute("type").ToLowerInvariant()); Assert.Equal("true", s.Driver.FindElement(By.Id("btcpay.server.canmodifyserversettings")).GetAttribute("value").ToLowerInvariant()); s.SetCheckbox(s, "btcpay.server.canmodifyserversettings", false); Assert.Contains("change-store-mode", s.Driver.PageSource); s.Driver.FindElement(By.Id("consent-yes")).Click(); Assert.Equal(callbackUrl, s.Driver.Url); accessToken = GetAccessTokenFromCallbackResult(s.Driver); await TestApiAgainstAccessToken(accessToken, tester, user, (await apiKeyRepo.GetKey(accessToken)).GetBlob().Permissions); //let's test the app identifier system authUrl = BTCPayServerClient.GenerateAuthorizeUri(tester.PayTester.ServerUri, new[] { Policies.CanModifyStoreSettings, Policies.CanModifyServerSettings }, false, true, (appidentifier, new Uri(callbackUrl))).ToString(); //if it's the same, go to the confirm page s.Driver.Navigate().GoToUrl(authUrl); s.Driver.FindElement(By.Id("continue")).Click(); Assert.Equal(callbackUrl, s.Driver.Url); //same app but different redirect = nono authUrl = BTCPayServerClient.GenerateAuthorizeUri(tester.PayTester.ServerUri, new[] { Policies.CanModifyStoreSettings, Policies.CanModifyServerSettings }, false, true, (appidentifier, new Uri("https://international.local/callback"))).ToString(); s.Driver.Navigate().GoToUrl(authUrl); Assert.False(s.Driver.Url.StartsWith("https://international.com/callback")); } }