public Mnemonic GenerateWallet(string cryptoCode = "BTC", string seed = "", bool importkeys = false, bool privkeys = false, ScriptPubKeyType format = ScriptPubKeyType.Segwit) { var isImport = !string.IsNullOrEmpty(seed); Driver.FindElement(By.Id($"Modify{cryptoCode}")).Click(); // Replace previous wallet case if (Driver.PageSource.Contains("id=\"ChangeWalletLink\"")) { Driver.FindElement(By.Id("ActionsDropdownToggle")).Click(); Driver.WaitForElement(By.Id("ChangeWalletLink")).Click(); Driver.WaitForElement(By.Id("ConfirmInput")).SendKeys("REPLACE"); Driver.FindElement(By.Id("ConfirmContinue")).Click(); } if (isImport) { TestLogs.LogInformation("Progressing with existing seed"); Driver.FindElement(By.Id("ImportWalletOptionsLink")).Click(); Driver.FindElement(By.Id("ImportSeedLink")).Click(); Driver.FindElement(By.Id("ExistingMnemonic")).SendKeys(seed); Driver.SetCheckbox(By.Id("SavePrivateKeys"), privkeys); } else { var option = privkeys ? "Hotwallet" : "Watchonly"; TestLogs.LogInformation($"Generating new seed ({option})"); Driver.FindElement(By.Id("GenerateWalletLink")).Click(); Driver.FindElement(By.Id($"Generate{option}Link")).Click(); } Driver.FindElement(By.Id("ScriptPubKeyType")).Click(); Driver.FindElement(By.CssSelector($"#ScriptPubKeyType option[value={format}]")).Click(); Driver.ToggleCollapse("AdvancedSettings"); Driver.SetCheckbox(By.Id("ImportKeysToRPC"), importkeys); Driver.FindElement(By.Id("Continue")).Click(); if (isImport) { // Confirm addresses Driver.FindElement(By.Id("Confirm")).Click(); } else { // Seed backup FindAlertMessage(); if (string.IsNullOrEmpty(seed)) { seed = Driver.FindElements(By.Id("RecoveryPhrase")).First().GetAttribute("data-mnemonic"); } // Confirm seed backup Driver.FindElement(By.Id("confirm")).Click(); Driver.FindElement(By.Id("submit")).Click(); } WalletId = new WalletId(StoreId, cryptoCode); return(new Mnemonic(seed)); }
public async Task StartAsync() { Server.PayTester.NoCSP = true; await Server.StartAsync(); var windowSize = (Width : 1200, Height : 1000); var builder = new ConfigurationBuilder(); builder.AddUserSecrets("AB0AC1DD-9D26-485B-9416-56A33F268117"); var config = builder.Build(); // Run `dotnet user-secrets set RunSeleniumInBrowser true` to run tests in browser var runInBrowser = config["RunSeleniumInBrowser"] == "true"; // Reset this using `dotnet user-secrets remove RunSeleniumInBrowser` var chromeDriverPath = config["ChromeDriverDirectory"] ?? (Server.PayTester.InContainer ? "/usr/bin" : Directory.GetCurrentDirectory()); var options = new ChromeOptions(); if (!runInBrowser) { options.AddArguments("headless"); } options.AddArguments($"window-size={windowSize.Width}x{windowSize.Height}"); options.AddArgument("shm-size=2g"); options.AddArgument("start-maximized"); if (Server.PayTester.InContainer) { // Shot in the dark to fix https://stackoverflow.com/questions/53902507/unknown-error-session-deleted-because-of-page-crash-from-unknown-error-cannot options.AddArgument("--disable-dev-shm-usage"); Driver = new OpenQA.Selenium.Remote.RemoteWebDriver(new Uri("http://selenium:4444/wd/hub"), new RemoteSessionSettings(options)); var containerIp = File.ReadAllText("/etc/hosts").Split('\n', StringSplitOptions.RemoveEmptyEntries).Last() .Split('\t', StringSplitOptions.RemoveEmptyEntries)[0].Trim(); TestLogs.LogInformation($"Selenium: Container's IP {containerIp}"); ServerUri = new Uri(Server.PayTester.ServerUri.AbsoluteUri.Replace($"http://{Server.PayTester.HostName}", $"http://{containerIp}", StringComparison.OrdinalIgnoreCase), UriKind.Absolute); } else { var cds = ChromeDriverService.CreateDefaultService(chromeDriverPath); cds.EnableVerboseLogging = true; cds.Port = Utils.FreeTcpPort(); cds.HostName = "127.0.0.1"; cds.Start(); Driver = new ChromeDriver(cds, options, // A bit less than test timeout TimeSpan.FromSeconds(50)); ServerUri = Server.PayTester.ServerUri; } Driver.Manage().Window.Maximize(); TestLogs.LogInformation($"Selenium: Using {Driver.GetType()}"); TestLogs.LogInformation($"Selenium: Browsing to {ServerUri}"); TestLogs.LogInformation($"Selenium: Resolution {Driver.Manage().Window.Size}"); GoToRegister(); Driver.AssertNoError(); }
public string RegisterNewUser(bool isAdmin = false) { var usr = RandomUtils.GetUInt256().ToString().Substring(64 - 20) + "@a.com"; TestLogs.LogInformation($"User: {usr} with password 123456"); Driver.FindElement(By.Id("Email")).SendKeys(usr); Driver.FindElement(By.Id("Password")).SendKeys("123456"); Driver.FindElement(By.Id("ConfirmPassword")).SendKeys("123456"); if (isAdmin) { Driver.FindElement(By.Id("IsAdmin")).Click(); } Driver.FindElement(By.Id("RegisterButton")).Click(); Driver.AssertNoError(); return(usr); }
public async Task <T> TestApiAgainstAccessToken <T>(string apikey, string url, HttpClient client) { var uri = new Uri(client.BaseAddress, url); var httpRequest = new HttpRequestMessage(HttpMethod.Get, uri); httpRequest.Headers.Authorization = new AuthenticationHeaderValue("token", apikey); TestLogs.LogInformation($"Testing {uri}"); var result = await client.SendAsync(httpRequest); TestLogs.LogInformation($"Testing {uri} status: {result.StatusCode}"); result.EnsureSuccessStatusCode(); var rawJson = await result.Content.ReadAsStringAsync(); TestLogs.LogInformation($"Testing {uri} result: {rawJson}"); if (typeof(T).IsPrimitive || typeof(T) == typeof(string)) { return((T)Convert.ChangeType(rawJson, typeof(T))); } return(JsonConvert.DeserializeObject <T>(rawJson)); }
public (string storeName, string storeId) CreateNewStore(bool keepId = true) { // If there's no store yet, there is no dropdown toggle if (Driver.PageSource.Contains("id=\"StoreSelectorToggle\"")) { Driver.FindElement(By.Id("StoreSelectorToggle")).Click(); } Driver.WaitForElement(By.Id("StoreSelectorCreate")).Click(); var name = "Store" + RandomUtils.GetUInt64(); TestLogs.LogInformation($"Created store {name}"); Driver.WaitForElement(By.Id("Name")).SendKeys(name); Driver.WaitForElement(By.Id("Create")).Click(); Driver.FindElement(By.Id("StoreNav-StoreSettings")).Click(); Driver.FindElement(By.Id($"SectionNav-{StoreNavPages.General.ToString()}")).Click(); var storeId = Driver.WaitForElement(By.Id("Id")).GetAttribute("value"); if (keepId) { StoreId = storeId; } return(name, storeId); }
public async Task CanPayWithTwoCurrencies() { using (var tester = CreateServerTester()) { tester.ActivateLTC(); await tester.StartAsync(); var user = tester.NewAccount(); user.GrantAccess(); user.RegisterDerivationScheme("BTC"); // First we try payment with a merchant having only BTC var invoice = user.BitPay.CreateInvoice( new Invoice() { Price = 5000.0m, Currency = "USD", PosData = "posData", OrderId = "orderId", ItemDesc = "Some description", FullNotifications = true }, Facade.Merchant); var cashCow = tester.ExplorerNode; cashCow.Generate(2); // get some money in case var invoiceAddress = BitcoinAddress.Create(invoice.BitcoinAddress, cashCow.Network); var firstPayment = Money.Coins(0.04m); cashCow.SendToAddress(invoiceAddress, firstPayment); TestUtils.Eventually(() => { invoice = user.BitPay.GetInvoice(invoice.Id); Assert.True(invoice.BtcPaid == firstPayment); }); Assert.Single(invoice.CryptoInfo); // Only BTC should be presented var controller = tester.PayTester.GetController <UIInvoiceController>(null); var checkout = (Models.InvoicingModels.PaymentModel)((JsonResult)controller.GetStatus(invoice.Id, null) .GetAwaiter().GetResult()).Value; Assert.Single(checkout.AvailableCryptos); Assert.Equal("BTC", checkout.CryptoCode); Assert.Single(invoice.PaymentCodes); Assert.Single(invoice.SupportedTransactionCurrencies); Assert.Single(invoice.SupportedTransactionCurrencies); Assert.Single(invoice.PaymentSubtotals); Assert.Single(invoice.PaymentTotals); Assert.True(invoice.PaymentCodes.ContainsKey("BTC")); Assert.True(invoice.SupportedTransactionCurrencies.ContainsKey("BTC")); Assert.True(invoice.SupportedTransactionCurrencies["BTC"].Enabled); Assert.True(invoice.PaymentSubtotals.ContainsKey("BTC")); Assert.True(invoice.PaymentTotals.ContainsKey("BTC")); ////////////////////// // Retry now with LTC enabled user.RegisterDerivationScheme("LTC"); invoice = user.BitPay.CreateInvoice( new Invoice() { Price = 5000.0m, Currency = "USD", PosData = "posData", OrderId = "orderId", ItemDesc = "Some description", FullNotifications = true }, Facade.Merchant); cashCow = tester.ExplorerNode; invoiceAddress = BitcoinAddress.Create(invoice.BitcoinAddress, cashCow.Network); firstPayment = Money.Coins(0.04m); cashCow.SendToAddress(invoiceAddress, firstPayment); TestLogs.LogInformation("First payment sent to " + invoiceAddress); TestUtils.Eventually(() => { invoice = user.BitPay.GetInvoice(invoice.Id); Assert.True(invoice.BtcPaid == firstPayment); }); cashCow = tester.LTCExplorerNode; var ltcCryptoInfo = invoice.CryptoInfo.FirstOrDefault(c => c.CryptoCode == "LTC"); Assert.NotNull(ltcCryptoInfo); invoiceAddress = BitcoinAddress.Create(ltcCryptoInfo.Address, cashCow.Network); var secondPayment = Money.Coins(decimal.Parse(ltcCryptoInfo.Due, CultureInfo.InvariantCulture)); cashCow.Generate(4); // LTC is not worth a lot, so just to make sure we have money... cashCow.SendToAddress(invoiceAddress, secondPayment); TestLogs.LogInformation("Second payment sent to " + invoiceAddress); TestUtils.Eventually(() => { invoice = user.BitPay.GetInvoice(invoice.Id); Assert.Equal(Money.Zero, invoice.BtcDue); var ltcPaid = invoice.CryptoInfo.First(c => c.CryptoCode == "LTC"); Assert.Equal(Money.Zero, ltcPaid.Due); Assert.Equal(secondPayment, ltcPaid.CryptoPaid); Assert.Equal("paid", invoice.Status); Assert.False((bool)((JValue)invoice.ExceptionStatus).Value); }); controller = tester.PayTester.GetController <UIInvoiceController>(null); checkout = (Models.InvoicingModels.PaymentModel)((JsonResult)controller.GetStatus(invoice.Id, "LTC") .GetAwaiter().GetResult()).Value; Assert.Equal(2, checkout.AvailableCryptos.Count); Assert.Equal("LTC", checkout.CryptoCode); Assert.Equal(2, invoice.PaymentCodes.Count()); Assert.Equal(2, invoice.SupportedTransactionCurrencies.Count()); Assert.Equal(2, invoice.SupportedTransactionCurrencies.Count()); Assert.Equal(2, invoice.PaymentSubtotals.Count()); Assert.Equal(2, invoice.PaymentTotals.Count()); Assert.True(invoice.PaymentCodes.ContainsKey("LTC")); Assert.True(invoice.SupportedTransactionCurrencies.ContainsKey("LTC")); Assert.True(invoice.SupportedTransactionCurrencies["LTC"].Enabled); Assert.True(invoice.PaymentSubtotals.ContainsKey("LTC")); Assert.True(invoice.PaymentTotals.ContainsKey("LTC")); // Check if we can disable LTC invoice = user.BitPay.CreateInvoice( new Invoice() { Price = 5000.0m, Currency = "USD", PosData = "posData", OrderId = "orderId", ItemDesc = "Some description", FullNotifications = true, SupportedTransactionCurrencies = new Dictionary <string, InvoiceSupportedTransactionCurrency>() { { "BTC", new InvoiceSupportedTransactionCurrency() { Enabled = true } } } }, Facade.Merchant); Assert.Single(invoice.CryptoInfo.Where(c => c.CryptoCode == "BTC")); Assert.Empty(invoice.CryptoInfo.Where(c => c.CryptoCode == "LTC")); } }
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); }
async Task TestApiAgainstAccessToken(string accessToken, ServerTester tester, TestAccount testAccount, params string[] expectedPermissionsArr) { var expectedPermissions = Permission.ToPermissions(expectedPermissionsArr).ToArray(); expectedPermissions ??= new Permission[0]; var apikeydata = await TestApiAgainstAccessToken <ApiKeyData>(accessToken, $"api/v1/api-keys/current", tester.PayTester.HttpClient); var permissions = apikeydata.Permissions; TestLogs.LogInformation($"TestApiAgainstAccessToken: Permissions {permissions.Length}"); Assert.Equal(expectedPermissions.Length, permissions.Length); foreach (var expectPermission in expectedPermissions) { Assert.True(permissions.Any(p => p == expectPermission), $"Missing expected permission {expectPermission}"); } TestLogs.LogInformation("Testing CanViewProfile"); if (permissions.Contains(Permission.Create(Policies.CanViewProfile))) { var resultUser = await TestApiAgainstAccessToken <string>(accessToken, $"{TestApiPath}/me/id", tester.PayTester.HttpClient); Assert.Equal(testAccount.UserId, resultUser); } else { await Assert.ThrowsAnyAsync <HttpRequestException>(async() => { await TestApiAgainstAccessToken <string>(accessToken, $"{TestApiPath}/me/id", tester.PayTester.HttpClient); }); } //create a second user to see if any of its data gets messed up in our results. TestLogs.LogInformation("Testing second user"); var secondUser = tester.NewAccount(); await secondUser.GrantAccessAsync(); var canModifyAllStores = Permission.Create(Policies.CanModifyStoreSettings, null); var canModifyServer = Permission.Create(Policies.CanModifyServerSettings, null); var unrestricted = Permission.Create(Policies.Unrestricted, null); var selectiveStorePermissions = permissions.Where(p => p.Scope != null && p.Policy == Policies.CanModifyStoreSettings); TestLogs.LogInformation("Testing can edit store for first user"); if (permissions.Contains(canModifyAllStores) || selectiveStorePermissions.Any()) { var resultStores = await TestApiAgainstAccessToken <StoreData[]>(accessToken, $"{TestApiPath}/me/stores", tester.PayTester.HttpClient); foreach (var selectiveStorePermission in selectiveStorePermissions) { Assert.True(await TestApiAgainstAccessToken <bool>(accessToken, $"{TestApiPath}/me/stores/{selectiveStorePermission.Scope}/can-edit", tester.PayTester.HttpClient)); Assert.Contains(resultStores, data => data.Id.Equals(selectiveStorePermission.Scope, StringComparison.InvariantCultureIgnoreCase)); } bool shouldBeAuthorized = false; if (permissions.Contains(canModifyAllStores) || selectiveStorePermissions.Contains(Permission.Create(Policies.CanViewStoreSettings, testAccount.StoreId))) { Assert.True(await TestApiAgainstAccessToken <bool>(accessToken, $"{TestApiPath}/me/stores/{testAccount.StoreId}/can-view", tester.PayTester.HttpClient)); Assert.Contains(resultStores, data => data.Id.Equals(testAccount.StoreId, StringComparison.InvariantCultureIgnoreCase)); shouldBeAuthorized = true; } if (permissions.Contains(canModifyAllStores) || selectiveStorePermissions.Contains(Permission.Create(Policies.CanModifyStoreSettings, testAccount.StoreId))) { Assert.True(await TestApiAgainstAccessToken <bool>(accessToken, $"{TestApiPath}/me/stores/{testAccount.StoreId}/can-view", tester.PayTester.HttpClient)); Assert.True(await TestApiAgainstAccessToken <bool>(accessToken, $"{TestApiPath}/me/stores/{testAccount.StoreId}/can-edit", tester.PayTester.HttpClient)); Assert.Contains(resultStores, data => data.Id.Equals(testAccount.StoreId, StringComparison.InvariantCultureIgnoreCase)); shouldBeAuthorized = true; } if (!shouldBeAuthorized) { await Assert.ThrowsAnyAsync <HttpRequestException>(async() => { await TestApiAgainstAccessToken <bool>(accessToken, $"{TestApiPath}/me/stores/{testAccount.StoreId}/can-edit", tester.PayTester.HttpClient); }); await Assert.ThrowsAnyAsync <HttpRequestException>(async() => { await TestApiAgainstAccessToken <bool>(accessToken, $"{TestApiPath}/me/stores/{testAccount.StoreId}/can-view", tester.PayTester.HttpClient); }); Assert.DoesNotContain(resultStores, data => data.Id.Equals(testAccount.StoreId, StringComparison.InvariantCultureIgnoreCase)); } } else if (!permissions.Contains(unrestricted)) { await Assert.ThrowsAnyAsync <HttpRequestException>(async() => { await TestApiAgainstAccessToken <bool>(accessToken, $"{TestApiPath}/me/stores/{testAccount.StoreId}/can-edit", tester.PayTester.HttpClient); }); } else { await TestApiAgainstAccessToken <bool>(accessToken, $"{TestApiPath}/me/stores/{testAccount.StoreId}/can-edit", tester.PayTester.HttpClient); } TestLogs.LogInformation("Testing can edit store for second user"); if (!permissions.Contains(unrestricted)) { await Assert.ThrowsAnyAsync <HttpRequestException>(async() => { await TestApiAgainstAccessToken <bool>(accessToken, $"{TestApiPath}/me/stores/{secondUser.StoreId}/can-edit", tester.PayTester.HttpClient); }); } else { await TestApiAgainstAccessToken <bool>(accessToken, $"{TestApiPath}/me/stores/{secondUser.StoreId}/can-edit", tester.PayTester.HttpClient); } TestLogs.LogInformation("Testing can edit store for second user expectation met"); TestLogs.LogInformation($"Testing CanModifyServer with {permissions.Contains(canModifyServer)}"); if (permissions.Contains(canModifyServer)) { Assert.True(await TestApiAgainstAccessToken <bool>(accessToken, $"{TestApiPath}/me/is-admin", tester.PayTester.HttpClient)); } else { await Assert.ThrowsAnyAsync <HttpRequestException>(async() => { await TestApiAgainstAccessToken <bool>(accessToken, $"{TestApiPath}/me/is-admin", tester.PayTester.HttpClient); }); } TestLogs.LogInformation("Testing CanModifyServer expectation met"); }
public async Task CanComputeCrowdfundModel() { using var tester = CreateServerTester(); await tester.StartAsync(); var user = tester.NewAccount(); await user.GrantAccessAsync(); user.RegisterDerivationScheme("BTC"); await user.SetNetworkFeeMode(NetworkFeeMode.Never); var apps = user.GetController <UIAppsController>(); var vm = Assert.IsType <CreateAppViewModel>(Assert.IsType <ViewResult>(apps.CreateApp(user.StoreId)).Model); var appType = AppType.Crowdfund.ToString(); vm.AppName = "test"; vm.SelectedAppType = appType; Assert.IsType <RedirectToActionResult>(apps.CreateApp(user.StoreId, vm).Result); var appList = Assert.IsType <ListAppsViewModel>(Assert.IsType <ViewResult>(apps.ListApps(user.StoreId).Result).Model); var app = appList.Apps[0]; apps.HttpContext.SetAppData(new AppData { Id = app.Id, StoreDataId = app.StoreId, Name = app.AppName, AppType = appType }); TestLogs.LogInformation("We create an invoice with a hardcap"); var crowdfundViewModel = await apps.UpdateCrowdfund(app.Id).AssertViewModelAsync <UpdateCrowdfundViewModel>(); crowdfundViewModel.Enabled = true; crowdfundViewModel.EndDate = null; crowdfundViewModel.TargetAmount = 100; crowdfundViewModel.TargetCurrency = "BTC"; crowdfundViewModel.UseAllStoreInvoices = true; crowdfundViewModel.EnforceTargetAmount = true; Assert.IsType <RedirectToActionResult>(apps.UpdateCrowdfund(app.Id, crowdfundViewModel, "save").Result); var anonAppPubsController = tester.PayTester.GetController <UIAppsPublicController>(); var publicApps = user.GetController <UIAppsPublicController>(); var model = Assert.IsType <ViewCrowdfundViewModel>(Assert .IsType <ViewResult>(publicApps.ViewCrowdfund(app.Id, String.Empty).Result).Model); Assert.Equal(crowdfundViewModel.TargetAmount, model.TargetAmount); Assert.Equal(crowdfundViewModel.EndDate, model.EndDate); Assert.Equal(crowdfundViewModel.StartDate, model.StartDate); Assert.Equal(crowdfundViewModel.TargetCurrency, model.TargetCurrency); Assert.Equal(0m, model.Info.CurrentAmount); Assert.Equal(0m, model.Info.CurrentPendingAmount); Assert.Equal(0m, model.Info.ProgressPercentage); TestLogs.LogInformation("Unpaid invoices should show as pending contribution because it is hardcap"); TestLogs.LogInformation("Because UseAllStoreInvoices is true, we can manually create an invoice and it should show as contribution"); var invoice = await user.BitPay.CreateInvoiceAsync(new Invoice { Buyer = new Buyer() { email = "*****@*****.**" }, Price = 1m, Currency = "BTC", PosData = "posData", ItemDesc = "Some description", TransactionSpeed = "high", FullNotifications = true }, Facade.Merchant); model = Assert.IsType <ViewCrowdfundViewModel>(Assert .IsType <ViewResult>(publicApps.ViewCrowdfund(app.Id, string.Empty).Result).Model); Assert.Equal(0m, model.Info.CurrentAmount); Assert.Equal(1m, model.Info.CurrentPendingAmount); Assert.Equal(0m, model.Info.ProgressPercentage); Assert.Equal(1m, model.Info.PendingProgressPercentage); TestLogs.LogInformation("Let's check current amount change once payment is confirmed"); var invoiceAddress = BitcoinAddress.Create(invoice.CryptoInfo[0].Address, tester.ExplorerNode.Network); tester.ExplorerNode.SendToAddress(invoiceAddress, invoice.BtcDue); tester.ExplorerNode.Generate(1); // By default invoice confirmed at 1 block TestUtils.Eventually(() => { model = Assert.IsType <ViewCrowdfundViewModel>(Assert .IsType <ViewResult>(publicApps.ViewCrowdfund(app.Id, String.Empty).Result).Model); Assert.Equal(1m, model.Info.CurrentAmount); Assert.Equal(0m, model.Info.CurrentPendingAmount); }); TestLogs.LogInformation("Because UseAllStoreInvoices is true, let's make sure the invoice is tagged"); var invoiceEntity = tester.PayTester.InvoiceRepository.GetInvoice(invoice.Id).GetAwaiter().GetResult(); Assert.True(invoiceEntity.Version >= InvoiceEntity.InternalTagSupport_Version); Assert.Contains(AppService.GetAppInternalTag(app.Id), invoiceEntity.InternalTags); crowdfundViewModel.UseAllStoreInvoices = false; Assert.IsType <RedirectToActionResult>(apps.UpdateCrowdfund(app.Id, crowdfundViewModel, "save").Result); TestLogs.LogInformation("Because UseAllStoreInvoices is false, let's make sure the invoice is not tagged"); invoice = await user.BitPay.CreateInvoiceAsync(new Invoice { Buyer = new Buyer { email = "*****@*****.**" }, Price = 1m, Currency = "BTC", PosData = "posData", ItemDesc = "Some description", TransactionSpeed = "high", FullNotifications = true }, Facade.Merchant); invoiceEntity = tester.PayTester.InvoiceRepository.GetInvoice(invoice.Id).GetAwaiter().GetResult(); Assert.DoesNotContain(AppService.GetAppInternalTag(app.Id), invoiceEntity.InternalTags); TestLogs.LogInformation("After turning setting a softcap, let's check that only actual payments are counted"); crowdfundViewModel.EnforceTargetAmount = false; crowdfundViewModel.UseAllStoreInvoices = true; Assert.IsType <RedirectToActionResult>(apps.UpdateCrowdfund(app.Id, crowdfundViewModel, "save").Result); invoice = await user.BitPay.CreateInvoiceAsync(new Invoice { Buyer = new Buyer { email = "*****@*****.**" }, Price = 1m, Currency = "BTC", PosData = "posData", ItemDesc = "Some description", TransactionSpeed = "high", FullNotifications = true }, Facade.Merchant); Assert.Equal(0m, model.Info.CurrentPendingAmount); invoiceAddress = BitcoinAddress.Create(invoice.CryptoInfo[0].Address, tester.ExplorerNode.Network); await tester.ExplorerNode.SendToAddressAsync(invoiceAddress, Money.Coins(0.5m)); await tester.ExplorerNode.SendToAddressAsync(invoiceAddress, Money.Coins(0.2m)); TestUtils.Eventually(() => { model = Assert.IsType <ViewCrowdfundViewModel>(Assert .IsType <ViewResult>(publicApps.ViewCrowdfund(app.Id, string.Empty).Result).Model); Assert.Equal(0.7m, model.Info.CurrentPendingAmount); }); }