diff --git a/BTCPayServer.Tests/SeleniumTester.cs b/BTCPayServer.Tests/SeleniumTester.cs index c7f163312..e97b958d5 100644 --- a/BTCPayServer.Tests/SeleniumTester.cs +++ b/BTCPayServer.Tests/SeleniumTester.cs @@ -202,7 +202,7 @@ namespace BTCPayServer.Tests internal void AssertNotFound() { - Assert.Contains("Status Code: 404; Not Found", Driver.PageSource); + Assert.Contains("404 - Page not found", Driver.PageSource); } public void GoToHome() diff --git a/BTCPayServer.Tests/UnitTest1.cs b/BTCPayServer.Tests/UnitTest1.cs index 3b6b0fcb3..ef2b8327c 100644 --- a/BTCPayServer.Tests/UnitTest1.cs +++ b/BTCPayServer.Tests/UnitTest1.cs @@ -521,6 +521,39 @@ namespace BTCPayServer.Tests } } + [Fact] + [Trait("Integration", "Integration")] + public async Task CanThrowBitpay404Error() + { + using (var tester = ServerTester.Create()) + { + await tester.StartAsync(); + var user = tester.NewAccount(); + user.GrantAccess(); + user.RegisterDerivationScheme("BTC"); + + var invoice = user.BitPay.CreateInvoice(new Invoice() + { + Buyer = new Buyer() { email = "test@fwf.com" }, + Price = 5000.0m, + Currency = "USD", + PosData = "posData", + OrderId = "orderId", + ItemDesc = "Some description", + FullNotifications = true + }, Facade.Merchant); + + try + { + var throwsBitpay404Error = user.BitPay.GetInvoice(invoice.Id + "123"); + } + catch (BitPayException ex) + { + Assert.Equal("Object not found", ex.Errors.First()); + } + } + } + [Fact] [Trait("Fast", "Fast")] public void RoundupCurrenciesCorrectly() diff --git a/BTCPayServer/Controllers/ErrorController.cs b/BTCPayServer/Controllers/ErrorController.cs new file mode 100644 index 000000000..0cafdb4e5 --- /dev/null +++ b/BTCPayServer/Controllers/ErrorController.cs @@ -0,0 +1,27 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Mvc; + +namespace BTCPayServer.Controllers +{ + [Route("[controller]/[action]")] + public class ErrorController : Controller + { + public IActionResult Handle(int? statusCode = null) + { + if (statusCode.HasValue) + { + var specialPages = new[] { 404, 429, 500 }; + if (specialPages.Any(a => a == statusCode.Value)) + { + var viewName = statusCode.ToString(); + return View(viewName); + } + } + return View(statusCode); + } + } +} diff --git a/BTCPayServer/Hosting/BTCpayMiddleware.cs b/BTCPayServer/Hosting/BTCpayMiddleware.cs index d58c2953d..7175fd0d4 100644 --- a/BTCPayServer/Hosting/BTCpayMiddleware.cs +++ b/BTCPayServer/Hosting/BTCpayMiddleware.cs @@ -62,10 +62,12 @@ namespace BTCPayServer.Hosting catch (UnauthorizedAccessException ex) { await HandleBitpayHttpException(httpContext, new BitpayHttpException(401, ex.Message)); + return; } catch (BitpayHttpException ex) { await HandleBitpayHttpException(httpContext, ex); + return; } catch (Exception ex) { @@ -133,13 +135,9 @@ namespace BTCPayServer.Hosting private static async Task HandleBitpayHttpException(HttpContext httpContext, BitpayHttpException ex) { httpContext.Response.StatusCode = ex.StatusCode; - using (var writer = new StreamWriter(httpContext.Response.Body, new UTF8Encoding(false), 1024, true)) - { - httpContext.Response.ContentType = "application/json"; - var result = JsonConvert.SerializeObject(new BitpayErrorsModel(ex)); - writer.Write(result); - await writer.FlushAsync(); - } + httpContext.Response.ContentType = "application/json"; + var result = JsonConvert.SerializeObject(new BitpayErrorsModel(ex)); + await httpContext.Response.WriteAsync(result); } } } diff --git a/BTCPayServer/Hosting/Startup.cs b/BTCPayServer/Hosting/Startup.cs index 541f5cb3f..a88e7f037 100644 --- a/BTCPayServer/Hosting/Startup.cs +++ b/BTCPayServer/Hosting/Startup.cs @@ -241,6 +241,10 @@ namespace BTCPayServer.Hosting forwardingOptions.KnownProxies.Clear(); forwardingOptions.ForwardedHeaders = ForwardedHeaders.All; app.UseForwardedHeaders(forwardingOptions); + + + app.UseStatusCodePagesWithReExecute("/Error/Handle", "?statusCode={0}"); + app.UsePayServer(); app.UseRouting(); app.UseCors(); @@ -252,7 +256,6 @@ namespace BTCPayServer.Hosting app.UseSession(); app.UseWebSockets(); - app.UseStatusCodePages(); app.UseEndpoints(endpoints => { diff --git a/BTCPayServer/Views/Account/Login.cshtml b/BTCPayServer/Views/Account/Login.cshtml index 2fc0c4d41..b7eaadeca 100644 --- a/BTCPayServer/Views/Account/Login.cshtml +++ b/BTCPayServer/Views/Account/Login.cshtml @@ -2,7 +2,7 @@ @inject BTCPayServer.HostedServices.CssThemeManager themeManager @{ ViewData["Title"] = "Log in"; - Layout = "_WelcomeLayout.cshtml"; + Layout = "_LayoutWelcome"; } @if (TempData.HasStatusMessage()) { diff --git a/BTCPayServer/Views/Account/Register.cshtml b/BTCPayServer/Views/Account/Register.cshtml index a7b7e298c..b87603b1b 100644 --- a/BTCPayServer/Views/Account/Register.cshtml +++ b/BTCPayServer/Views/Account/Register.cshtml @@ -2,7 +2,7 @@ @{ ViewData["Title"] = "Register"; var useBasicLayout = ViewData["UseBasicLayout"] is true; - Layout = useBasicLayout ? "../Shared/_Layout.cshtml" : "_WelcomeLayout.cshtml"; + Layout = useBasicLayout ? "_Layout" : "_LayoutWelcome"; } @if (TempData.HasStatusMessage()) { diff --git a/BTCPayServer/Views/Error/404.cshtml b/BTCPayServer/Views/Error/404.cshtml new file mode 100644 index 000000000..10daba9ff --- /dev/null +++ b/BTCPayServer/Views/Error/404.cshtml @@ -0,0 +1,15 @@ +@{ + ViewData["ErrorTitle"] = "404 - Page not found"; +} + +

+ This is like searching for a person more beautiful than Nicolas Dorier. +

+ + Nicolas Dorier beauty + +

+ It doesn't exist. +

+ You can always try navigating back to home. +

diff --git a/BTCPayServer/Views/Error/429.cshtml b/BTCPayServer/Views/Error/429.cshtml new file mode 100644 index 000000000..9ef961fef --- /dev/null +++ b/BTCPayServer/Views/Error/429.cshtml @@ -0,0 +1,15 @@ +@{ + ViewData["ErrorTitle"] = "429 - Too Many Requests"; +} + +

+ Please send requests slower. Or face the wrath of Vin Diesel. +

+ + Vin is angry because you caused 429 + +

+ You sure you want to risk that? +

+ Slowly navigate back to home. +

diff --git a/BTCPayServer/Views/Error/500.cshtml b/BTCPayServer/Views/Error/500.cshtml new file mode 100644 index 000000000..bf014b3f7 --- /dev/null +++ b/BTCPayServer/Views/Error/500.cshtml @@ -0,0 +1,15 @@ +@{ + ViewData["ErrorTitle"] = "500 - Internal Server Error"; +} + +

+ Whoops, something really went wrong! Mr Kukks is so sorry. +

+ + Mr Kukks puppy eyes + +

+ Consult server log and consider submitting issue on BTCPayServer GitHub. +

+ Navigate back to home. +

diff --git a/BTCPayServer/Views/Error/Handle.cshtml b/BTCPayServer/Views/Error/Handle.cshtml new file mode 100644 index 000000000..12f058f32 --- /dev/null +++ b/BTCPayServer/Views/Error/Handle.cshtml @@ -0,0 +1,19 @@ +@using System.Net +@model int? +@{ + ViewData["ErrorTitle"] = "Generic Error occurred"; + if (Model.HasValue) + { + var httpCode = (HttpStatusCode)Model.Value; + ViewData["ErrorTitle"] = $"{(int)httpCode} - {httpCode.ToString()}"; + } +} + +

+ Generic error occurred, HTTP Code: @Model +

+ Consult server log for more details. +

+ Navigate back to home. +

+

diff --git a/BTCPayServer/Views/Error/_LayoutError.cshtml b/BTCPayServer/Views/Error/_LayoutError.cshtml new file mode 100644 index 000000000..d208baafc --- /dev/null +++ b/BTCPayServer/Views/Error/_LayoutError.cshtml @@ -0,0 +1,118 @@ +@{ + Layout = null; +} +@inject BTCPayServer.Services.BTCPayServerEnvironment env + + + + + + + + + +
+
+ + +
+
+
+ +

@ViewData["ErrorTitle"]

+
+
+
+
+
+ @RenderBody() +
+
+
+
+
+ @await Html.PartialAsync("_BTCPaySupporters") +
+
+
+
+
+ + diff --git a/BTCPayServer/Views/Error/_ViewStart.cshtml b/BTCPayServer/Views/Error/_ViewStart.cshtml new file mode 100644 index 000000000..5d3510360 --- /dev/null +++ b/BTCPayServer/Views/Error/_ViewStart.cshtml @@ -0,0 +1,3 @@ +@{ + Layout = "_LayoutError"; +} diff --git a/BTCPayServer/Views/Shared/_BTCPaySupporters.cshtml b/BTCPayServer/Views/Shared/_BTCPaySupporters.cshtml new file mode 100644 index 000000000..921df3b12 --- /dev/null +++ b/BTCPayServer/Views/Shared/_BTCPaySupporters.cshtml @@ -0,0 +1,41 @@ +

BTCPayServer Supporters

+
+ + Sponsor Square Crypto + + +
+
+ + Sponsor DG lab + +
+ DG Lab +
+
+
+ + Sponsor ACINQ + +
+ ACINQ +
+
+
+ + Sponsor LunaNode + +
+ LunaNode +
+
+
+ + Sponsor Wallet of Satoshi + + +
diff --git a/BTCPayServer/Views/Account/_WelcomeLayout.cshtml b/BTCPayServer/Views/Shared/_LayoutWelcome.cshtml similarity index 60% rename from BTCPayServer/Views/Account/_WelcomeLayout.cshtml rename to BTCPayServer/Views/Shared/_LayoutWelcome.cshtml index c04520c28..0429dc625 100644 --- a/BTCPayServer/Views/Account/_WelcomeLayout.cshtml +++ b/BTCPayServer/Views/Shared/_LayoutWelcome.cshtml @@ -102,47 +102,7 @@

-

Our supporters

- -
- - Sponsor DG lab - -
- DG Lab -
-
-
- - Sponsor ACINQ - -
- ACINQ -
-
-
- - Sponsor LunaNode - -
- LunaNode -
-
- + @await Html.PartialAsync("_BTCPaySupporters")
@RenderBody() diff --git a/BTCPayServer/wwwroot/img/errorpages/404_nicolas.jpg b/BTCPayServer/wwwroot/img/errorpages/404_nicolas.jpg new file mode 100644 index 000000000..20f741998 Binary files /dev/null and b/BTCPayServer/wwwroot/img/errorpages/404_nicolas.jpg differ diff --git a/BTCPayServer/wwwroot/img/errorpages/429_rockstardev.jpg b/BTCPayServer/wwwroot/img/errorpages/429_rockstardev.jpg new file mode 100644 index 000000000..ef75fd50f Binary files /dev/null and b/BTCPayServer/wwwroot/img/errorpages/429_rockstardev.jpg differ diff --git a/BTCPayServer/wwwroot/img/errorpages/500_mrkukks.jpg b/BTCPayServer/wwwroot/img/errorpages/500_mrkukks.jpg new file mode 100644 index 000000000..4fd4ef216 Binary files /dev/null and b/BTCPayServer/wwwroot/img/errorpages/500_mrkukks.jpg differ