Improve 2FA auth UI

This commit is contained in:
Dennis Reimann 2022-01-18 09:54:22 +01:00 committed by Andrew Camilleri
parent d7b4dd2d4c
commit 801ab862a3
8 changed files with 105 additions and 107 deletions

View File

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

View File

@ -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">

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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