Merge pull request #1314 from btcpayserver/feature/errorpages

Adding error pages to handle HTTP errors
This commit is contained in:
Nicolas Dorier
2020-02-03 08:39:58 +00:00
committed by GitHub
18 changed files with 299 additions and 52 deletions

View File

@@ -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()

View File

@@ -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()

View 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);
}
}
}

View File

@@ -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);
}
}
}

View File

@@ -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 =>
{

View File

@@ -2,7 +2,7 @@
@inject BTCPayServer.HostedServices.CssThemeManager themeManager
@{
ViewData["Title"] = "Log in";
Layout = "_WelcomeLayout.cshtml";
Layout = "_LayoutWelcome";
}
@if (TempData.HasStatusMessage())
{

View File

@@ -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())
{

View 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>

View 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>

View 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>

View 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>

View 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>

View File

@@ -0,0 +1,3 @@
@{
Layout = "_LayoutError";
}

View 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>

View File

@@ -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()

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB