UI: Improve access token pairing (#4237)

Closes #4133.
This commit is contained in:
d11n
2022-10-27 01:57:54 +02:00
committed by GitHub
parent 1fa297fb73
commit c0125b83d1
2 changed files with 67 additions and 62 deletions

View File

@@ -109,6 +109,10 @@ namespace BTCPayServer.Controllers
private readonly EventAggregator _EventAggregator; private readonly EventAggregator _EventAggregator;
private readonly IOptions<ExternalServicesOptions> _externalServiceOptions; private readonly IOptions<ExternalServicesOptions> _externalServiceOptions;
public string? GeneratedPairingCode { get; set; }
public WebhookSender WebhookNotificationManager { get; }
public IDataProtector DataProtector { get; }
[TempData] [TempData]
public bool StoreNotConfigured public bool StoreNotConfigured
{ {
@@ -736,8 +740,7 @@ namespace BTCPayServer.Controllers
return new DerivationSchemeSettings(strategy, network); return new DerivationSchemeSettings(strategy, network);
} }
[HttpGet] [HttpGet("{storeId}/tokens")]
[Route("{storeId}/Tokens")]
public async Task<IActionResult> ListTokens() public async Task<IActionResult> ListTokens()
{ {
var model = new TokensViewModel(); var model = new TokensViewModel();
@@ -780,8 +783,7 @@ namespace BTCPayServer.Controllers
return RedirectToAction(nameof(ListTokens), new { storeId = token?.StoreId }); return RedirectToAction(nameof(ListTokens), new { storeId = token?.StoreId });
} }
[HttpGet] [HttpGet("{storeId}/tokens/{tokenId}")]
[Route("{storeId}/tokens/{tokenId}")]
public async Task<IActionResult> ShowToken(string tokenId) public async Task<IActionResult> ShowToken(string tokenId)
{ {
var token = await _TokenRepository.GetToken(tokenId); var token = await _TokenRepository.GetToken(tokenId);
@@ -790,8 +792,18 @@ namespace BTCPayServer.Controllers
return View(token); return View(token);
} }
[HttpPost] [HttpGet("{storeId}/tokens/create")]
[Route("{storeId}/Tokens/Create")] public IActionResult CreateToken(string storeId)
{
var model = new CreateTokenViewModel();
ViewBag.HidePublicKey = storeId == null;
ViewBag.ShowStores = storeId == null;
ViewBag.ShowMenu = storeId != null;
model.StoreId = storeId;
return View(model);
}
[HttpPost("{storeId}/tokens/create")]
public async Task<IActionResult> CreateToken(string storeId, CreateTokenViewModel model) public async Task<IActionResult> CreateToken(string storeId, CreateTokenViewModel model)
{ {
if (!ModelState.IsValid) if (!ModelState.IsValid)
@@ -832,29 +844,12 @@ namespace BTCPayServer.Controllers
GeneratedPairingCode = pairingCode; GeneratedPairingCode = pairingCode;
return RedirectToAction(nameof(RequestPairing), new return RedirectToAction(nameof(RequestPairing), new
{ {
pairingCode = pairingCode, pairingCode,
selectedStore = storeId selectedStore = storeId
}); });
} }
public string? GeneratedPairingCode { get; set; } [HttpGet("/api-tokens")]
public WebhookSender WebhookNotificationManager { get; }
public IDataProtector DataProtector { get; }
[HttpGet]
[Route("{storeId}/Tokens/Create")]
public IActionResult CreateToken(string storeId)
{
var model = new CreateTokenViewModel();
ViewBag.HidePublicKey = storeId == null;
ViewBag.ShowStores = storeId == null;
ViewBag.ShowMenu = storeId != null;
model.StoreId = storeId;
return View(model);
}
[HttpGet]
[Route("/api-tokens")]
[AllowAnonymous] [AllowAnonymous]
public async Task<IActionResult> CreateToken() public async Task<IActionResult> CreateToken()
{ {
@@ -875,16 +870,14 @@ namespace BTCPayServer.Controllers
return View(model); return View(model);
} }
[HttpPost] [HttpPost("/api-tokens")]
[Route("/api-tokens")]
[AllowAnonymous] [AllowAnonymous]
public Task<IActionResult> CreateToken2(CreateTokenViewModel model) public Task<IActionResult> CreateToken2(CreateTokenViewModel model)
{ {
return CreateToken(model.StoreId, model); return CreateToken(model.StoreId, model);
} }
[HttpPost] [HttpPost("{storeId}/tokens/apikey")]
[Route("{storeId}/tokens/apikey")]
public async Task<IActionResult> GenerateAPIKey(string storeId, string command = "") public async Task<IActionResult> GenerateAPIKey(string storeId, string command = "")
{ {
var store = HttpContext.GetStoreData(); var store = HttpContext.GetStoreData();
@@ -907,50 +900,48 @@ namespace BTCPayServer.Controllers
}); });
} }
[HttpGet] [HttpGet("/api-access-request")]
[Route("/api-access-request")]
[AllowAnonymous] [AllowAnonymous]
public async Task<IActionResult> RequestPairing(string pairingCode, string? selectedStore = null) public async Task<IActionResult> RequestPairing(string pairingCode, string? selectedStore = null)
{ {
var userId = GetUserId(); var userId = GetUserId();
if (userId == null) if (userId == null)
return Challenge(AuthenticationSchemes.Cookie); return Challenge(AuthenticationSchemes.Cookie);
if (pairingCode == null) if (pairingCode == null)
return NotFound(); return NotFound();
if (selectedStore != null) if (selectedStore != null)
{ {
var store = await _Repo.FindStore(selectedStore, userId); var store = await _Repo.FindStore(selectedStore, userId);
if (store == null) if (store == null)
return NotFound(); return NotFound();
HttpContext.SetStoreData(store); HttpContext.SetStoreData(store);
ViewBag.ShowStores = false;
} }
var pairing = await _TokenRepository.GetPairingAsync(pairingCode); var pairing = await _TokenRepository.GetPairingAsync(pairingCode);
if (pairing == null) if (pairing == null)
{ {
TempData[WellKnownTempData.ErrorMessage] = "Unknown pairing code"; TempData[WellKnownTempData.ErrorMessage] = "Unknown pairing code";
return RedirectToAction(nameof(UIHomeController.Index), "UIHome"); return RedirectToAction(nameof(UIHomeController.Index), "UIHome");
} }
else
var stores = await _Repo.GetStoresByUserId(userId);
return View(new PairingModel
{ {
var stores = await _Repo.GetStoresByUserId(userId); Id = pairing.Id,
return View(new PairingModel Label = pairing.Label,
SIN = pairing.SIN ?? "Server-Initiated Pairing",
StoreId = selectedStore ?? stores.FirstOrDefault()?.Id,
Stores = stores.Where(u => u.Role == StoreRoles.Owner).Select(s => new PairingModel.StoreViewModel
{ {
Id = pairing.Id, Id = s.Id,
Label = pairing.Label, Name = string.IsNullOrEmpty(s.StoreName) ? s.Id : s.StoreName
SIN = pairing.SIN ?? "Server-Initiated Pairing", }).ToArray()
StoreId = selectedStore ?? stores.FirstOrDefault()?.Id, });
Stores = stores.Where(u => u.Role == StoreRoles.Owner).Select(s => new PairingModel.StoreViewModel()
{
Id = s.Id,
Name = string.IsNullOrEmpty(s.StoreName) ? s.Id : s.StoreName
}).ToArray()
});
}
} }
[HttpPost] [HttpPost("/api-access-request")]
[Route("/api-access-request")]
public async Task<IActionResult> Pair(string pairingCode, string storeId) public async Task<IActionResult> Pair(string pairingCode, string storeId)
{ {
if (pairingCode == null) if (pairingCode == null)

View File

@@ -1,12 +1,22 @@
@model PairingModel @model PairingModel
@{ @{
Layout = "../Shared/_NavLayout.cshtml"; var store = Context.GetStoreData();
ViewData.SetActivePage(StoreNavPages.Tokens, "Pairing Permission", Context.GetStoreData()?.Id); Layout = store is null ? "_LayoutWizard" : "_NavLayout";
ViewData.SetActivePage(StoreNavPages.Tokens, "Pairing Permission", store?.Id);
}
@if (store is null)
{
@section Navbar {
<button type="button" class="cancel" onclick="history.back()">
<vc:icon symbol="close" />
</button>
}
} }
<h3 class="mb-0">@ViewData["Title"]</h3>
<div class="row"> <div class="row">
<div class="col-md-4"> <div class="col-sm-8 col-md-6 @(store is null ? "mx-auto" : "")">
<h3 class="mb-0">@ViewData["Title"]</h3>
<table class="table table-hover"> <table class="table table-hover">
<tr> <tr>
<th>Label</th> <th>Label</th>
@@ -17,17 +27,21 @@
<td class="text-end">@Model.SIN</td> <td class="text-end">@Model.SIN</td>
</tr> </tr>
</table> </table>
</div>
</div>
<div class="row">
<div class="col-md-4">
<form asp-action="Pair" method="post"> <form asp-action="Pair" method="post">
<div class="form-group"> @if (store is null)
<label asp-for="StoreId" class="form-label">Pair To Store</label> {
<select asp-for="StoreId" asp-items="@(new SelectList(Model.Stores,"Id","Name"))" class="form-select"></select> <div class="form-group">
<span asp-validation-for="StoreId" class="text-danger"></span> <label asp-for="StoreId" class="form-label">Pair To Store</label>
</div> <select asp-for="StoreId" asp-items="@(new SelectList(Model.Stores, "Id", "Name"))" class="form-select"></select>
<input type="hidden" name="pairingCode" value="@Model.Id" /> <span asp-validation-for="StoreId" class="text-danger"></span>
</div>
}
else
{
<input asp-for="StoreId" type="hidden" />
}
<input type="hidden" name="pairingCode" value="@Model.Id"/>
<button id="ApprovePairing" type="submit" class="btn btn-primary mt-3" title="Approve this pairing demand">Approve</button> <button id="ApprovePairing" type="submit" class="btn btn-primary mt-3" title="Approve this pairing demand">Approve</button>
</form> </form>
</div> </div>