mirror of
https://github.com/aljazceru/btcpayserver.git
synced 2026-01-07 16:14:20 +01:00
Merge pull request #1314 from btcpayserver/feature/errorpages
Adding error pages to handle HTTP errors
This commit is contained in:
@@ -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</h1>", Driver.PageSource);
|
||||
}
|
||||
|
||||
public void GoToHome()
|
||||
|
||||
@@ -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()
|
||||
|
||||
27
BTCPayServer/Controllers/ErrorController.cs
Normal file
27
BTCPayServer/Controllers/ErrorController.cs
Normal file
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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 =>
|
||||
{
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
@inject BTCPayServer.HostedServices.CssThemeManager themeManager
|
||||
@{
|
||||
ViewData["Title"] = "Log in";
|
||||
Layout = "_WelcomeLayout.cshtml";
|
||||
Layout = "_LayoutWelcome";
|
||||
}
|
||||
@if (TempData.HasStatusMessage())
|
||||
{
|
||||
|
||||
@@ -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())
|
||||
{
|
||||
|
||||
15
BTCPayServer/Views/Error/404.cshtml
Normal file
15
BTCPayServer/Views/Error/404.cshtml
Normal file
@@ -0,0 +1,15 @@
|
||||
@{
|
||||
ViewData["ErrorTitle"] = "404 - Page not found";
|
||||
}
|
||||
|
||||
<p class="lead-login">
|
||||
This is like searching for a person more beautiful than <a href="https://twitter.com/NicolasDorier" target="_blank">Nicolas Dorier</a>.
|
||||
<br /><br />
|
||||
<a href="https://twitter.com/NicolasDorier" target="_blank">
|
||||
<img src="~/img/errorpages/404_nicolas.jpg" alt="Nicolas Dorier beauty" title="Slowly stroke the image" />
|
||||
</a>
|
||||
<br /><br />
|
||||
It doesn't exist.
|
||||
<br /><br />
|
||||
You can always try <a href="/">navigating back to home</a>.
|
||||
</p>
|
||||
15
BTCPayServer/Views/Error/429.cshtml
Normal file
15
BTCPayServer/Views/Error/429.cshtml
Normal file
@@ -0,0 +1,15 @@
|
||||
@{
|
||||
ViewData["ErrorTitle"] = "429 - Too Many Requests";
|
||||
}
|
||||
|
||||
<p class="lead-login">
|
||||
Please send requests slower. Or face the wrath of <a href="https://twitter.com/r0ckstardev" target="_blank">Vin Diesel</a>.
|
||||
<br /><br />
|
||||
<a href="https://twitter.com/r0ckstardev" target="_blank">
|
||||
<img src="~/img/errorpages/429_rockstardev.jpg" alt="Vin is angry because you caused 429" title="Move away that cursor" />
|
||||
</a>
|
||||
<br /><br />
|
||||
You sure you want to risk that?
|
||||
<br /><br />
|
||||
Slowly <a href="/">navigate back to home</a>.
|
||||
</p>
|
||||
15
BTCPayServer/Views/Error/500.cshtml
Normal file
15
BTCPayServer/Views/Error/500.cshtml
Normal file
@@ -0,0 +1,15 @@
|
||||
@{
|
||||
ViewData["ErrorTitle"] = "500 - Internal Server Error";
|
||||
}
|
||||
|
||||
<p class="lead-login">
|
||||
Whoops, something really went wrong! <a href="https://twitter.com/mrkukks">Mr Kukks</a> is so sorry.
|
||||
<br /><br />
|
||||
<a href="https://twitter.com/mrkukks" target="_blank">
|
||||
<img src="~/img/errorpages/500_mrkukks.jpg" alt="Mr Kukks puppy eyes" title="The most innocent look you'll ever see" />
|
||||
</a>
|
||||
<br /><br />
|
||||
Consult server log and consider submitting issue on BTCPayServer GitHub.
|
||||
<br /><br />
|
||||
<a href="/">Navigate back to home</a>.
|
||||
</p>
|
||||
19
BTCPayServer/Views/Error/Handle.cshtml
Normal file
19
BTCPayServer/Views/Error/Handle.cshtml
Normal file
@@ -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()}";
|
||||
}
|
||||
}
|
||||
|
||||
<p class="lead-login">
|
||||
Generic error occurred, HTTP Code: @Model
|
||||
<br /><br />
|
||||
Consult server log for more details.
|
||||
<br /><br />
|
||||
<a href="/">Navigate back to home</a>.
|
||||
<br /><br />
|
||||
</p>
|
||||
118
BTCPayServer/Views/Error/_LayoutError.cshtml
Normal file
118
BTCPayServer/Views/Error/_LayoutError.cshtml
Normal file
@@ -0,0 +1,118 @@
|
||||
@{
|
||||
Layout = null;
|
||||
}
|
||||
@inject BTCPayServer.Services.BTCPayServerEnvironment env
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<partial name="Header" />
|
||||
|
||||
<link href="~/main/fonts/Montserrat.css" rel="stylesheet">
|
||||
<style>
|
||||
.content-wrapper {
|
||||
padding: 20px 0;
|
||||
}
|
||||
|
||||
@@media screen and (min-width: 768px) {
|
||||
.content-wrapper {
|
||||
padding: 20px 0;
|
||||
}
|
||||
}
|
||||
|
||||
.col-head {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
@@media screen and (min-width: 768px) {
|
||||
.col-head {
|
||||
text-align: left;
|
||||
flex-direction: row;
|
||||
justify-content: start;
|
||||
}
|
||||
}
|
||||
|
||||
.head-logo {
|
||||
height: 70px;
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
|
||||
@@media screen and (min-width: 768px) {
|
||||
.head-logo {
|
||||
height: 100px;
|
||||
margin-bottom: 0;
|
||||
margin-right: 50px;
|
||||
}
|
||||
}
|
||||
|
||||
.lead-title {
|
||||
font-family: Montserrat;
|
||||
font-style: normal;
|
||||
font-weight: bold;
|
||||
font-size: 24px;
|
||||
line-height: 1.2;
|
||||
/* or 150% */
|
||||
letter-spacing: 0.1em;
|
||||
}
|
||||
|
||||
@@media screen and (min-width: 768px) {
|
||||
.lead-title {
|
||||
font-size: 40px;
|
||||
}
|
||||
}
|
||||
|
||||
.lead-login {
|
||||
font-family: Montserrat;
|
||||
font-style: normal;
|
||||
font-weight: normal;
|
||||
font-size: 18px;
|
||||
line-height: 33px;
|
||||
/* or 183% */
|
||||
letter-spacing: 0.1em;
|
||||
}
|
||||
|
||||
.lead-h {
|
||||
font-family: Montserrat;
|
||||
font-style: normal;
|
||||
margin-bottom: 30px;
|
||||
font-weight: 600;
|
||||
font-size: 14px;
|
||||
line-height: 18px;
|
||||
/* identical to box height, or 129% */
|
||||
letter-spacing: 0.1em;
|
||||
text-transform: uppercase;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<center>
|
||||
<section class="content-wrapper">
|
||||
<!-- Dummy navbar-brand, hackish way to keep test AssertNoError passing -->
|
||||
<div class="navbar-brand" style="display:none;"></div>
|
||||
<div class="container">
|
||||
<div class="row">
|
||||
<div class="col-12 col-head" style="justify-content:center;">
|
||||
<a asp-controller="Home" asp-action="Index"><img src="~/img/btcpay-logo.svg" alt="BTCPay Server" class="head-logo" /></a>
|
||||
<h1 class="lead-title text-uppercase">@ViewData["ErrorTitle"]</h1>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-12">
|
||||
<hr class="primary ml-0" style="margin:20px auto;" />
|
||||
@RenderBody()
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-12">
|
||||
<hr class="primary ml-0" style="margin:20px auto;" />
|
||||
@await Html.PartialAsync("_BTCPaySupporters")
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</center>
|
||||
</body>
|
||||
</html>
|
||||
3
BTCPayServer/Views/Error/_ViewStart.cshtml
Normal file
3
BTCPayServer/Views/Error/_ViewStart.cshtml
Normal file
@@ -0,0 +1,3 @@
|
||||
@{
|
||||
Layout = "_LayoutError";
|
||||
}
|
||||
41
BTCPayServer/Views/Shared/_BTCPaySupporters.cshtml
Normal file
41
BTCPayServer/Views/Shared/_BTCPaySupporters.cshtml
Normal file
@@ -0,0 +1,41 @@
|
||||
<h3 class="lead-h">BTCPayServer Supporters <a href="https://foundation.btcpayserver.org/" target="_blank"><span class="fa fa-question-circle-o" title="More information..."></span></a></h3>
|
||||
<div class="figure">
|
||||
<a href="https://twitter.com/sqcrypto" target="_blank">
|
||||
<img src="~/img/squarecrypto.svg" alt="Sponsor Square Crypto" height="75" />
|
||||
</a>
|
||||
<div class="figure-caption text-center">
|
||||
<a href="https://twitter.com/sqcrypto" class="text-muted small" target="_blank">Square Crypto</a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="figure ml-4">
|
||||
<a href="https://www.dglab.com/en/" target="_blank">
|
||||
<img src="~/img/dglab.svg" alt="Sponsor DG lab" height="75" />
|
||||
</a>
|
||||
<div class="figure-caption text-center">
|
||||
<a href="https://www.dglab.com/en/" class="text-muted small" target="_blank">DG Lab</a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="figure ml-4">
|
||||
<a href="https://acinq.co/" target="_blank">
|
||||
<img src="~/img/acinq-logo.svg" alt="Sponsor ACINQ" height="75" />
|
||||
</a>
|
||||
<div class="figure-caption text-center">
|
||||
<a href="https://acinq.co/" class="text-muted small" target="_blank">ACINQ</a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="figure ml-4">
|
||||
<a href="https://lunanode.com/" target="_blank">
|
||||
<img src="~/img/lunanode.svg" alt="Sponsor LunaNode" height="75" />
|
||||
</a>
|
||||
<div class="figure-caption text-center">
|
||||
<a href="https://lunanode.com/" class="text-muted small" target="_blank">LunaNode</a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="figure ml-4">
|
||||
<a href="https://walletofsatoshi.com/" target="_blank">
|
||||
<img src="~/img/walletofsatoshi.svg" alt="Sponsor Wallet of Satoshi" height="75" />
|
||||
</a>
|
||||
<div class="figure-caption text-center">
|
||||
<a href="https://walletofsatoshi.com/" class="text-muted small" target="_blank">Wallet of Satoshi</a>
|
||||
</div>
|
||||
</div>
|
||||
@@ -102,47 +102,7 @@
|
||||
<div class="col-md-7 order-md-1 order-2">
|
||||
<hr class="primary ml-0" style="margin:30px auto;">
|
||||
<p class="lead-login" style="margin-bottom:69px;">BTCPay Server is a self-hosted, open-source cryptocurrency payment processor. It is secure, private, censorship-resistant and free.</p>
|
||||
<h3 class="lead-h">Our supporters <a href="https://foundation.btcpayserver.org/" target="_blank"><span class="fa fa-question-circle-o" title="More information..."></span></a></h3>
|
||||
<div class="figure">
|
||||
<a href="https://twitter.com/sqcrypto" target="_blank">
|
||||
<img src="~/img/squarecrypto.svg" alt="Sponsor Square Crypto" height="75" />
|
||||
</a>
|
||||
<div class="figure-caption text-center">
|
||||
<a href="https://twitter.com/sqcrypto" class="text-muted small" target="_blank">Square Crypto</a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="figure ml-4">
|
||||
<a href="https://www.dglab.com/en/" target="_blank">
|
||||
<img src="~/img/dglab.svg" alt="Sponsor DG lab" height="75" />
|
||||
</a>
|
||||
<div class="figure-caption text-center">
|
||||
<a href="https://www.dglab.com/en/" class="text-muted small" target="_blank">DG Lab</a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="figure ml-4">
|
||||
<a href="https://acinq.co/" target="_blank">
|
||||
<img src="~/img/acinq-logo.svg" alt="Sponsor ACINQ" height="75" />
|
||||
</a>
|
||||
<div class="figure-caption text-center">
|
||||
<a href="https://acinq.co/" class="text-muted small" target="_blank">ACINQ</a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="figure ml-4">
|
||||
<a href="https://lunanode.com/" target="_blank">
|
||||
<img src="~/img/lunanode.svg" alt="Sponsor LunaNode" height="75" />
|
||||
</a>
|
||||
<div class="figure-caption text-center">
|
||||
<a href="https://lunanode.com/" class="text-muted small" target="_blank">LunaNode</a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="figure ml-4">
|
||||
<a href="https://walletofsatoshi.com/" target="_blank">
|
||||
<img src="~/img/walletofsatoshi.svg" alt="Sponsor Wallet of Satoshi" height="75" />
|
||||
</a>
|
||||
<div class="figure-caption text-center">
|
||||
<a href="https://walletofsatoshi.com/" class="text-muted small" target="_blank">Wallet of Satoshi</a>
|
||||
</div>
|
||||
</div>
|
||||
@await Html.PartialAsync("_BTCPaySupporters")
|
||||
</div>
|
||||
<div class="col-md-5 order-md-2 order-1">
|
||||
@RenderBody()
|
||||
BIN
BTCPayServer/wwwroot/img/errorpages/404_nicolas.jpg
Normal file
BIN
BTCPayServer/wwwroot/img/errorpages/404_nicolas.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 14 KiB |
BIN
BTCPayServer/wwwroot/img/errorpages/429_rockstardev.jpg
Normal file
BIN
BTCPayServer/wwwroot/img/errorpages/429_rockstardev.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 15 KiB |
BIN
BTCPayServer/wwwroot/img/errorpages/500_mrkukks.jpg
Normal file
BIN
BTCPayServer/wwwroot/img/errorpages/500_mrkukks.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 18 KiB |
Reference in New Issue
Block a user