mirror of
https://github.com/btcpayserver/btcpayserver.git
synced 2024-11-19 18:11:36 +01:00
Improve 2FA auth UI
This commit is contained in:
parent
d7b4dd2d4c
commit
801ab862a3
@ -7,58 +7,57 @@
|
||||
{ "Bech32", LNURL.EncodeUri(Model, "login", true).ToString().ToUpperInvariant() },
|
||||
{ "URI", LNURL.EncodeUri(Model, "login", false).ToString().ToUpperInvariant() }
|
||||
};
|
||||
|
||||
|
||||
}
|
||||
|
||||
<div class="row">
|
||||
<div class="col-lg-8">
|
||||
<div id="info-message" class="align-items-center">
|
||||
<div class="tab-content">
|
||||
@for (int i = 0; i < formats.Count; i++)
|
||||
{
|
||||
var mode = formats.ElementAt(i);
|
||||
<div class="tab-pane @(i == 0 ? "active" : "")" id="@mode.Key" role="tabpanel">
|
||||
<div class="qr-container text-center" style="min-height: 256px;">
|
||||
<vc:qr-code data="@mode.Value"></vc:qr-code>
|
||||
</div>
|
||||
<a href="@mode.Value" class="btn btn-primary w-100 mt-2" rel="noreferrer noopener">
|
||||
Open in wallet
|
||||
</a>
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
<h3 class="mb-3">@ViewData["Title"]</h3>
|
||||
|
||||
<ul class="nav justify-content-center bg-light text-dark my-2">
|
||||
@for (int i = 0; i < formats.Count; i++)
|
||||
{
|
||||
var mode = formats.ElementAt(i);
|
||||
<li class="nav-item">
|
||||
<a class="nav-link @(i == 0 ? "active" : "")"
|
||||
data-bs-toggle="tab" data-bs-target="#@mode.Key" role="tab"
|
||||
href="#">
|
||||
@mode.Key
|
||||
</a>
|
||||
</li>
|
||||
}
|
||||
</ul>
|
||||
<span>Scan the QR code with your lightning wallet and link to your user account.</span>
|
||||
</div>
|
||||
<p>Scan the QR code with your Lightning wallet to link it to your user account.</p>
|
||||
|
||||
<div id="info-message" class="d-inline-block">
|
||||
<ul class="nav nav-pills justify-content-center my-2">
|
||||
@for (int i = 0; i < formats.Count; i++)
|
||||
{
|
||||
var mode = formats.ElementAt(i);
|
||||
<li class="nav-item">
|
||||
<a class="nav-link @(i == 0 ? "active" : "")"
|
||||
data-bs-toggle="tab" data-bs-target="#@mode.Key" role="tab"
|
||||
href="#">
|
||||
@mode.Key
|
||||
</a>
|
||||
</li>
|
||||
}
|
||||
</ul>
|
||||
<div class="tab-content">
|
||||
@for (int i = 0; i < formats.Count; i++)
|
||||
{
|
||||
var mode = formats.ElementAt(i);
|
||||
<div class="tab-pane text-center @(i == 0 ? "active" : "")" id="@mode.Key" role="tabpanel">
|
||||
<div class="qr-container" style="min-height: 256px;">
|
||||
<vc:qr-code data="@mode.Value" />
|
||||
</div>
|
||||
<a href="@mode.Value" class="btn btn-primary mt-3" rel="noreferrer noopener">
|
||||
Open in wallet
|
||||
</a>
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
<script>
|
||||
function check(){
|
||||
const request = new XMLHttpRequest();
|
||||
request.onload = function() {
|
||||
if (request.readyState === 4 && request.status === 200) {
|
||||
setTimeout(check, 1000);
|
||||
} else if (request.readyState === 4 ){
|
||||
window.location.href = @Safe.Json(Url.Action("RedirectToList", new {successMessage = "The lightning node will now act as a security device for your account"}));
|
||||
}
|
||||
|
||||
@section PageFootContent {
|
||||
<script>
|
||||
function check(){
|
||||
const request = new XMLHttpRequest();
|
||||
request.onload = function() {
|
||||
if (request.readyState === 4 && request.status === 200) {
|
||||
setTimeout(check, 1000);
|
||||
} else if (request.readyState === 4 ){
|
||||
window.location.href = @Safe.Json(Url.Action("RedirectToList", new { successMessage = "The lightning node will now act as a security device for your account" }));
|
||||
}
|
||||
}
|
||||
|
||||
request.open("GET", window.location.pathname + "/check", true);
|
||||
request.send(new FormData());
|
||||
}
|
||||
|
||||
request.open("GET", window.location.pathname + "/check", true);
|
||||
request.send(new FormData());
|
||||
}
|
||||
check();
|
||||
</script>
|
||||
check();
|
||||
</script>
|
||||
}
|
||||
|
@ -3,7 +3,6 @@
|
||||
<div class="row pt-5">
|
||||
<div class="col-lg-12 section-heading">
|
||||
<h2>Two-factor authentication</h2>
|
||||
<hr class="primary">
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mb-3">
|
||||
|
@ -10,12 +10,14 @@
|
||||
<div class="row pt-5">
|
||||
<div class="col-lg-12 section-heading">
|
||||
<h2>FIDO2 Authentication</h2>
|
||||
<hr class="primary">
|
||||
<div id="info-message">
|
||||
<span id="spinner" class="fa fa-spinner fa-spin float-end ms-3 me-5 mt-1 fido-running" style="font-size:2.5em"></span>
|
||||
<p>Insert your security key into your computer's USB port. If it has a button, tap on it.</p>
|
||||
<p>Insert your security device and proceed.</p>
|
||||
<div id="info-message" class="alert alert-info mb-3 d-none">
|
||||
<div class="d-flex align-items-center">
|
||||
<span id="spinner" class="fa fa-spinner fa-spin me-3 mt-1 fido-running" style="font-size:1.5rem"></span>
|
||||
<span>If your security device has a button, tap on it.</span>
|
||||
</div>
|
||||
</div>
|
||||
<button id="btn-start" class="btn btn-outline-primary w-100 btn-lg d-none" type="button">Start</button>
|
||||
<button id="btn-start" class="btn btn-outline-primary d-none" type="button">Start</button>
|
||||
<p id="error-message" class="d-none alert alert-danger"></p>
|
||||
<button id="btn-retry" class="btn btn-secondary d-none" type="button">Retry</button>
|
||||
</div>
|
||||
@ -23,9 +25,8 @@
|
||||
|
||||
<script>
|
||||
document.getElementById('btn-retry').addEventListener('click', () => window.location.reload())
|
||||
// send to server for registering
|
||||
// send to server for registering
|
||||
window.makeAssertionOptions = @Safe.Json(Model.Data);
|
||||
</script>
|
||||
<script src="~/js/webauthn/helpers.js" asp-append-version="true"></script>
|
||||
<script src="~/js/webauthn/login.js" asp-append-version="true"></script>
|
||||
|
||||
|
@ -5,8 +5,6 @@
|
||||
{ "Bech32", LNURL.LNURL.EncodeUri(Model.LNURLEndpoint, "login", true).ToString().ToUpperInvariant() },
|
||||
{ "URI", LNURL.LNURL.EncodeUri(Model.LNURLEndpoint, "login", true).ToString().ToUpperInvariant() }
|
||||
};
|
||||
|
||||
|
||||
}
|
||||
|
||||
<section class="pt-5" id="lnurlauth-section">
|
||||
@ -14,24 +12,8 @@
|
||||
<div class="row">
|
||||
<div class="col-lg-12 section-heading">
|
||||
<h2>LNURL Auth</h2>
|
||||
<hr class="primary">
|
||||
<div class="align-items-center">
|
||||
<div class="tab-content">
|
||||
@for (int i = 0; i < formats.Count; i++)
|
||||
{
|
||||
var mode = formats.ElementAt(i);
|
||||
<div class="tab-pane @(i == 0 ? "active" : "")" id="@mode.Key" role="tabpanel">
|
||||
<div class="qr-container text-center" style="min-height: 256px;">
|
||||
<vc:qr-code data="@mode.Value"></vc:qr-code>
|
||||
</div>
|
||||
<a href="@mode.Value" class="btn btn-primary w-100 mt-2" rel="noreferrer noopener">
|
||||
Open in wallet
|
||||
</a>
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
|
||||
<ul class="nav justify-content-center bg-light text-dark my-2">
|
||||
<ul class="nav nav-pills justify-content-center my-2">
|
||||
@for (int i = 0; i < formats.Count; i++)
|
||||
{
|
||||
var mode = formats.ElementAt(i);
|
||||
@ -44,20 +26,35 @@
|
||||
</li>
|
||||
}
|
||||
</ul>
|
||||
<div class="tab-content">
|
||||
@for (int i = 0; i < formats.Count; i++)
|
||||
{
|
||||
var mode = formats.ElementAt(i);
|
||||
<div class="tab-pane text-center @(i == 0 ? "active" : "")" id="@mode.Key" role="tabpanel">
|
||||
<div class="qr-container" style="min-height: 256px;">
|
||||
<vc:qr-code data="@mode.Value"></vc:qr-code>
|
||||
</div>
|
||||
<a href="@mode.Value" class="btn btn-primary mt-3" rel="noreferrer noopener">
|
||||
Open in wallet
|
||||
</a>
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
<p>Scan the QR code with your lightning wallet and link to your user account.</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<form id="authform" asp-action="LoginWithLNURLAuth" method="post" asp-route-returnUrl="@ViewData["ReturnUrl"]">
|
||||
<input type="hidden" asp-for="LNURLEndpoint"/>
|
||||
<input type="hidden" asp-for="UserId"/>
|
||||
</form>
|
||||
|
||||
<script>
|
||||
function check(){
|
||||
const request = new XMLHttpRequest();
|
||||
function check() {
|
||||
const request = new XMLHttpRequest();
|
||||
request.onload = function() {
|
||||
if (request.readyState === 4 && request.status === 200) {
|
||||
setTimeout(check, 1000);
|
||||
@ -65,7 +62,7 @@
|
||||
document.getElementById("authform").submit();
|
||||
}
|
||||
}
|
||||
request.open("GET", @Safe.Json(Url.Action("LoginCheck", "LNURLAuth", new {userId = Model.UserId})), true);
|
||||
request.open("GET", @Safe.Json(Url.Action("LoginCheck", "LNURLAuth", new { userId = Model.UserId })), true);
|
||||
request.send(new FormData());
|
||||
}
|
||||
check();
|
||||
|
@ -3,26 +3,34 @@
|
||||
ViewData.SetActivePage(ManageNavPages.TwoFactorAuthentication, "Register your security device");
|
||||
}
|
||||
|
||||
<h3 class="mb-3">@ViewData["Title"]</h3>
|
||||
|
||||
<p>Insert your security device and proceed.</p>
|
||||
|
||||
<form asp-action="CreateResponse" id="registerForm">
|
||||
<input type="hidden" name="data" id="data"/>
|
||||
<input type="hidden" name="name" id="name" value="@(ViewData.ContainsKey("CredentialName") ? ViewData["CredentialName"] : string.Empty)"/>
|
||||
</form>
|
||||
<div class="row">
|
||||
<div class="col-lg-8">
|
||||
<div id="info-message" class="alert alert-info my-3 d-flex justify-content-center align-items-center">
|
||||
<span id="spinner" class="fa fa-spinner fa-spin float-end me-3 fido-running" style="font-size:2.5em"></span>
|
||||
<span>Insert your security device into your computer's USB port. If it has a button, tap on it.</span>
|
||||
<div id="info-message" class="alert alert-info mb-3 d-none">
|
||||
<div class="d-flex align-items-center">
|
||||
<span id="spinner" class="fa fa-spinner fa-spin me-3 fido-running" style="font-size:1.5rem"></span>
|
||||
<span>If your security device has a button, tap on it.</span>
|
||||
</div>
|
||||
</div>
|
||||
<button id="btn-start" class="btn btn-primary btn-lg w-100 d-none" type="button">Start</button>
|
||||
<button id="btn-start" class="btn btn-primary d-none" type="button">Start</button>
|
||||
<p id="error-message" class="d-none alert alert-danger"></p>
|
||||
<a id="btn-retry" class="btn btn-secondary d-none">Retry</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
document.getElementById('btn-retry').addEventListener('click', function () { window.location.reload() });
|
||||
// send to server for registering
|
||||
window.makeCredentialOptions = @Json.Serialize(Model);
|
||||
</script>
|
||||
<script src="~/js/webauthn/helpers.js"></script>
|
||||
<script src="~/js/webauthn/register.js"></script>
|
||||
@section PageFootContent {
|
||||
<script>
|
||||
document.getElementById('btn-retry').addEventListener('click', function () { window.location.reload() });
|
||||
// send to server for registering
|
||||
window.makeCredentialOptions = @Json.Serialize(Model);
|
||||
</script>
|
||||
<script src="~/js/webauthn/helpers.js"></script>
|
||||
<script src="~/js/webauthn/register.js"></script>
|
||||
}
|
||||
|
@ -132,7 +132,7 @@
|
||||
<form asp-action="CreateCredential">
|
||||
<div class="input-group">
|
||||
<input type="text" class="form-control" name="Name" placeholder="Security device name"/>
|
||||
<select asp-items="@Html.GetEnumSelectList<Fido2Credential.CredentialType>()" class="form-select" name="type"></select>
|
||||
<select asp-items="@Html.GetEnumSelectList<Fido2Credential.CredentialType>()" class="form-select w-auto" name="type"></select>
|
||||
<button id="btn-add" type="submit" class="btn btn-primary">
|
||||
<span class="fa fa-plus"></span>
|
||||
Add
|
||||
|
@ -23,7 +23,6 @@ async function login(makeAssertionOptions) {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Sends the credential to the the FIDO2 server for assertion
|
||||
* @param {any} assertedCredential
|
||||
@ -50,14 +49,11 @@ async function verifyAssertionWithServer(assertedCredential) {
|
||||
document.getElementById("fidoForm").submit();
|
||||
}
|
||||
|
||||
|
||||
|
||||
document.addEventListener('DOMContentLoaded', () => {
|
||||
if (detectFIDOSupport() && makeAssertionOptions) {
|
||||
const infoMessage = document.getElementById("info-message");
|
||||
const startButton = document.getElementById("btn-start");
|
||||
if (isSafari()) {
|
||||
const infoMessage= document.getElementById("info-message");
|
||||
infoMessage.classList.add("d-none");
|
||||
const startButton = document.getElementById("btn-start");
|
||||
startButton.addEventListener("click", ev => {
|
||||
login(makeAssertionOptions);
|
||||
infoMessage.classList.remove("d-none");
|
||||
@ -65,6 +61,7 @@ document.addEventListener('DOMContentLoaded', () => {
|
||||
});
|
||||
startButton.classList.remove("d-none");
|
||||
} else {
|
||||
infoMessage.classList.remove("d-none");
|
||||
login(makeAssertionOptions);
|
||||
}
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
async function register(makeCredentialOptions) {
|
||||
console.log("Credential Options Object", makeCredentialOptions);
|
||||
console.debug("Credential Options Object", makeCredentialOptions);
|
||||
// Turn the challenge back into the accepted format of padded base64
|
||||
makeCredentialOptions.challenge = coerceToArrayBuffer(makeCredentialOptions.challenge);
|
||||
// Turn ID into a UInt8Array Buffer for some reason
|
||||
@ -12,10 +12,8 @@ async function register(makeCredentialOptions) {
|
||||
|
||||
if (makeCredentialOptions.authenticatorSelection.authenticatorAttachment == null) makeCredentialOptions.authenticatorSelection.authenticatorAttachment = undefined;
|
||||
|
||||
console.log("Credential Options Formatted", makeCredentialOptions);
|
||||
|
||||
|
||||
console.log("Creating PublicKeyCredential...");
|
||||
console.debug("Credential Options Formatted", makeCredentialOptions);
|
||||
console.debug("Creating PublicKeyCredential...");
|
||||
|
||||
let newCredential;
|
||||
try {
|
||||
@ -28,14 +26,13 @@ async function register(makeCredentialOptions) {
|
||||
return;
|
||||
}
|
||||
|
||||
console.log("PublicKeyCredential Created", newCredential);
|
||||
console.debug("PublicKeyCredential Created", newCredential);
|
||||
|
||||
try {
|
||||
registerNewCredential(newCredential);
|
||||
|
||||
} catch (e) {
|
||||
showErrorAlert(err.message ? err.message : err);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@ -63,10 +60,9 @@ async function registerNewCredential(newCredential) {
|
||||
|
||||
document.addEventListener('DOMContentLoaded', () => {
|
||||
if (detectFIDOSupport() && makeCredentialOptions) {
|
||||
const infoMessage = document.getElementById("info-message");
|
||||
const startButton = document.getElementById("btn-start");
|
||||
if (isSafari()) {
|
||||
const infoMessage= document.getElementById("info-message");
|
||||
infoMessage.classList.add("d-none");
|
||||
const startButton = document.getElementById("btn-start");
|
||||
startButton.addEventListener("click", ev => {
|
||||
register(makeCredentialOptions);
|
||||
infoMessage.classList.remove("d-none");
|
||||
@ -74,6 +70,7 @@ document.addEventListener('DOMContentLoaded', () => {
|
||||
});
|
||||
startButton.classList.remove("d-none");
|
||||
} else {
|
||||
infoMessage.classList.remove("d-none");
|
||||
register(makeCredentialOptions);
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user