Skip to content

Commit

Permalink
Improves layout on narrow screens; fixes logout caching problem
Browse files Browse the repository at this point in the history
  • Loading branch information
DougReeder committed Jul 22, 2024
1 parent c517309 commit 887724e
Show file tree
Hide file tree
Showing 12 changed files with 187 additions and 136 deletions.
4 changes: 2 additions & 2 deletions lib/assets/admin-users.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -43,11 +43,11 @@ async function submit(data) {
document.getElementById('shareContainer').hidden = false;
}

displayOutput(invite.text + '\n' + invite.url, 'Or, copy and paste this invite to a secure channel:');
displayOutput(invite.text + '\n' + invite.url, 'Or, copy and paste this to a secure channel:');
} else {
await displayNonsuccess(resp);
if (resp.status === 401) {
window.location = './login'
window.location = '/account/login'
}
}
} catch (err) {
Expand Down
1 change: 0 additions & 1 deletion lib/assets/login.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ import {startAuthentication} from './simplewebauthn-browser.js';
//
// document.getElementById('login').hidden = false;
document.getElementById('login')?.addEventListener('click', loginCatchingErrors);
displayMessage('Click the button below to log in with a passkey.\n\nIf you need to create a passkey for this device or browser, log in from your old device and invite yourself to create a new passkey.');
// });

async function loginCatchingErrors() {
Expand Down
73 changes: 55 additions & 18 deletions lib/assets/style.css
Original file line number Diff line number Diff line change
Expand Up @@ -191,7 +191,7 @@ header.topbar {
width: 100%;
max-width: calc(100vw - 2rem);
min-height: 3rem;
margin: 1rem 0;
margin: 1rem 0 0 0;
}

header.topbar h1 {
Expand Down Expand Up @@ -308,6 +308,8 @@ header.topbar .signup:focus {
section.hero {
width: 50rem;
max-width: calc(100vw - 2rem);
margin-left: auto;
margin-right: auto;
text-align: center;
}

Expand Down Expand Up @@ -362,6 +364,16 @@ section.hero header + p {
}
}

.artwork {
margin-top: 1rem;
}

.fitName {
font-size: 1.3rem;
font-size: math;
overflow: scroll;
}

.centeredBoxContent {
display: flex;
justify-content: center;
Expand Down Expand Up @@ -399,42 +411,51 @@ th {
tr:nth-of-type(even) {
background: var(--arma-bckgrd-color-alt);
}
td:first-child {
padding-left: 0.67em;
}
/*
Max width before this PARTICULAR table gets nasty
This query will take effect for any screen smaller than 760px
and also iPads specifically.
Max width before these PARTICULAR tables gets nasty
This query will take effect for any screen smaller than 500px
*/
@media
only screen and (max-width: 400px) {
only screen and (max-width: 500px) {

/* Force table to not be like tables anymore */
table, thead, tbody, th, td, tr {
table.adaptive, .adaptive thead, .adaptive tbody, .adaptive th, .adaptive td, .adaptive tr {
display: block;
}

/* Hide table headers (but not display: none;, for accessibility) */
thead tr {
position: absolute;
top: -9999px;
left: -9999px;
.adaptive thead tr {
border: 0;
padding: 0;
margin: 0;
position: absolute !important;
height: 1px;
width: 1px;
overflow: hidden;
clip: rect(1px 1px 1px 1px); /* IE6, IE7 - a 0 height clip, off to the bottom right of the visible 1px box */
clip: rect(1px, 1px, 1px, 1px); /*maybe deprecated but we need to support legacy browsers */
clip-path: inset(50%); /*modern browsers, clip-path works inwards from each corner*/
white-space: nowrap; /* added line to stop words getting smushed together (as they go onto seperate lines and some screen readers do not understand line feeds as a space */
}

tr { border: 1px solid #ccc; }
.adaptive tr { border: 1px solid #ccc; }

td {
.adaptive td {
/* Behave like a "row" */
border: none;
border-bottom: 1px solid #eee;
position: relative;
padding-left: 40%;
}

td:before {
.adaptive td:before {
/* Now like a table header */
position: absolute;
/* Top/left values mimic padding */
top: 6px;
left: 6px;
left: 0.67em;
width: 35%;
padding-right: 10px;
white-space: nowrap;
Expand All @@ -447,12 +468,13 @@ only screen and (max-width: 400px) {

#users td:nth-of-type(1):before { content: "Name"; }
#users td:nth-of-type(2):before { content: "Contact URL"; }
#users td:nth-of-type(3):before { content: "Last connected"; }
#users td:nth-of-type(3):before { content: "Last logged-in"; }
#users td:nth-of-type(4):before { content: "Privileges"; }
}

.borderSolid {
#output {
border: black 1px solid;
padding: 1em;
}

/* BODY FOOTER */
Expand Down Expand Up @@ -532,6 +554,11 @@ body > footer > p {

/* MAIN CONTENT */

main {
width: 100%;
max-width: 65rem;
}

main.content {
margin: auto;
}
Expand Down Expand Up @@ -562,6 +589,13 @@ main .message {
text-align: center;
}

.notTooWide {
width: 100%;
max-width: 30rem;
margin-left: auto;
margin-right: auto;
}

/* FORMS */

form {
Expand Down Expand Up @@ -884,7 +918,7 @@ button[name="deny"]:focus {
}

@media
only screen and (max-width: 400px) {
only screen and (max-width: 500px) {
.flexRowWrapResponsive {
display: flex;
flex-flow: row wrap;
Expand All @@ -893,6 +927,9 @@ only screen and (max-width: 400px) {
}
}

.preWrap {
white-space: pre-wrap;
}

/* ICONS */

Expand Down
2 changes: 1 addition & 1 deletion lib/routes/admin.js
Original file line number Diff line number Diff line change
Expand Up @@ -441,7 +441,7 @@ module.exports = async function (hostIdentity, jwtSecret, accountMgr, storeRoute
} else {
res.logNotes.add('session does not have ADMIN privilege');
if (['GET', 'HEAD'].includes(req.method)) {
res.redirect(307, './login');
res.redirect(307, '/admin/login');
} else { // TODO consider deleting this unused code
res.logNotes.add('session lacks ADMIN privilege');
res.status(401).end();
Expand Down
8 changes: 5 additions & 3 deletions lib/routes/login.js
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,9 @@ module.exports = async function (hostIdentity, jwtSecret, account, isAdminLogin)
host: getHost(req),
privileges: req.session.privileges || {},
accountPrivileges: req.session.user?.privileges || {},
message: 'select a passkey',
options: JSON.stringify(options)
message: isAdminLogin ? 'Click the button below to authenticate with a passkey.' : 'Click the button below to log in with a passkey.\n\nIf you need to create a passkey for this device or browser, log in from your old device and invite yourself to create a new passkey.',
options: JSON.stringify(options),
actionLabel: isAdminLogin ? 'Authenticate' : 'Log in'
});
} catch (err) {
removeUserDataFromSession(req.session);
Expand Down Expand Up @@ -87,6 +88,7 @@ module.exports = async function (hostIdentity, jwtSecret, account, isAdminLogin)
}
});

/** TODO: make this a POST, and change link to form */
router.get('/logout',
// csrfCheck,
async (req, res) => {
Expand All @@ -97,7 +99,7 @@ module.exports = async function (hostIdentity, jwtSecret, account, isAdminLogin)
req.session.destroy(err => { if (err) { reject(err); } else { resolve(); } });
});

res.set('Cache-Control', 'max-age=1500');
res.set('Cache-Control', 'private, no-store');
res.render('login/logout.html', {
title: 'Logged Out',
host: getHost(req),
Expand Down
104 changes: 54 additions & 50 deletions lib/views/account/account.html
Original file line number Diff line number Diff line change
Expand Up @@ -3,57 +3,61 @@
<script type="module" src="<%= basePath %>/assets/admin-users.mjs"></script>

<section class="hero">
<header><h1><%= title %></h1><h1><%= username + '@' + host %></h1></header>
<header>
<h1><%= title %></h1>
<h1 class="fitName"><%= username + '@' + host %></h1>
</header>
</section>

<table class="fullwidth centeredText">
<tbody>
<tr><td>Account Privileges</td><td><%= Object.keys(accountPrivileges).join(', ') || '«none»' %></td></tr>
<tr><td>Session Privileges</td><td><%= Object.keys(privileges).join(', ') || '«none»' %></td></tr>
</tbody>
</table>

<header class="flexRowCenter">
<h2>Passkeys &nbsp;</h2>
<img src="/assets/passkeymajor-svgrepo-com.svg" class="passkeyIcon" alt="">
</header>

<table id="credentials" class="fullwidth centeredText">
<thead>
<tr><th>Created using</th><th>Created on</th><th>Last used</th></tr>
</thead>
<tbody>
<% for (const cred of credentials) { %>
<tr>
<td><%= cred.name %></td>
<td><%= new Date(cred.createdAt).toLocaleDateString() %></td>
<td><%= cred.lastUsed ? new Date(cred.lastUsed).toLocaleString().replace(/:\d\d(?!:)/, '') : 'never' %></td>
</tr>
<% } %>
</tbody>
</table>

<hr>

<div class="marginTop marginSides centeredText">To create a passkey on a new device, invite yourself to create another passkey:</div>
<div class="marginTop marginSides flexRowCenter">
<button id="reinviteSelf" class="mainAction" data-username="<%= username %>" data-contacturl="<%= contactURL %>" data-privilegegrant="{&quot;STORE&quot;:true}" >Invite yourself to create another passkey</button>
</div>

<div id="progress" hidden><label>Generating: <progress></progress></label></div>

<div id="sendFromMeContainer" class="marginTop marginSides centeredText" hidden>
<a id="sendFromMe" href="" target="_blank" rel="noreferrer">Send invite from my account</a>
</div>

<div id="shareContainer" class="marginTop marginSides centeredText" hidden>
<button id="share" type="button" class="mainAction width10em">Share Invite from an account of mine</button>
</div>

<div id="outputDiv" class="marginTop marginSides" hidden>
<label id="outputLabel" for="output"></label>
<div id="output" class="borderSolid padding"></div>
</div>

<section class="fullwidth">
<table class="fullwidth centeredText">
<tbody>
<tr><td>Account Privileges</td><td><%= Object.keys(accountPrivileges).join(', ') || '«none»' %></td></tr>
<tr><td>Session Privileges</td><td><%= Object.keys(privileges).join(', ') || '«none»' %></td></tr>
</tbody>
</table>

<header class="flexRowCenter">
<h2>Passkeys &nbsp;</h2>
<img src="/assets/passkeymajor-svgrepo-com.svg" class="passkeyIcon" alt="">
</header>

<table id="credentials" class="fullwidth adaptive centeredText">
<thead>
<tr><th>Created using</th><th>Created on</th><th>Last used</th></tr>
</thead>
<tbody>
<% for (const cred of credentials) { %>
<tr>
<td><%= cred.name %></td>
<td><%= new Date(cred.createdAt).toLocaleDateString() %></td>
<td><%= cred.lastUsed ? new Date(cred.lastUsed).toLocaleString().replace(/:\d\d(?!:)/, '') : 'never' %></td>
</tr>
<% } %>
</tbody>
</table>

<hr>

<div class="marginTop marginSides centeredText">To create a passkey on a new device, invite yourself to create another passkey:</div>
<div class="marginTop marginSides flexRowCenter">
<button id="reinviteSelf" class="mainAction" data-username="<%= username %>" data-contacturl="<%= contactURL %>" data-privilegegrant="{&quot;STORE&quot;:true}" >Invite yourself to create another passkey</button>
</div>

<div id="progress" hidden><label>Generating: <progress></progress></label></div>

<div id="sendFromMeContainer" class="marginTop marginSides centeredText" hidden>
<a id="sendFromMe" href="" target="_blank" rel="noreferrer">Send invite from my account</a>
</div>

<div id="shareContainer" class="marginTop marginSides centeredText" hidden>
<button id="share" type="button" class="mainAction width10em">Share Invite from an account of mine</button>
</div>

<div id="outputDiv" hidden>
<label id="outputLabel" for="output"></label>
<div id="output"></div>
</div>
</section>

<%- include('../end.html'); %>
4 changes: 2 additions & 2 deletions lib/views/admin/invite-requests.html
Original file line number Diff line number Diff line change
Expand Up @@ -46,9 +46,9 @@
<button id="share" type="button" class="mainAction width10em">Share Invite from an account of mine</button>
</div>

<div id="outputDiv" class="marginTop marginSides" hidden>
<div id="outputDiv" hidden>
<label id="outputLabel" for="output"></label>
<div id="output" class="borderSolid padding"></div>
<div id="output"></div>
</div>

<%- include('../end.html'); %>
35 changes: 20 additions & 15 deletions lib/views/admin/invite-valid.html
Original file line number Diff line number Diff line change
Expand Up @@ -2,23 +2,28 @@

<script type="module" src="<%= basePath %>/assets/register.mjs"></script>

<section class="centeredText">
<h1><%= title %></h1>
<p>Contact URL: <%= contactURL %> </p>
<p>Privileges: <%= Object.keys(accountPrivileges).join(', ') || '«none»' %></p>
<div class="flexRowSpaceBetween">
<p>You will always use a passkey to log into your account. &nbsp; </p>
<img src="/assets/passkeymajor-svgrepo-com.svg" class="passkeyIcon" alt="">
</div>
<p id="message"><%= message %></p>
</section>
<main class="content">
<div class="flexRowSpaceBetween">
<section class="notTooWide">
<section class="centeredText marginSides">
<h1><%= title %></h1>
<p>Contact URL: <%= contactURL %> </p>
<p>Privileges: <%= Object.keys(accountPrivileges).join(', ') || '«none»' %></p>
<div class="flexRowSpaceBetween">
<p>You will always use a passkey to log into your account. &nbsp; </p>
<img src="/assets/passkeymajor-svgrepo-com.svg" class="passkeyIcon" alt="">
</div>
<p id="message"><%= message %></p>
</section>
<div class="flexRowSpaceBetween marginSides">
<label for="username">Username: </label> &nbsp;
<input type="text" id="username" value="<%= username %>" placeholder="Your choice" autofocus>
</div>
<input type="hidden" id="options" value="<%= options %>">
<div class="centeredBoxContent marginTop"><button id="register" class="mainAction" hidden>Create Passkey</button></div>
<div id="progress" hidden><label>Creating &amp; registering: <progress></progress></label></div>
</main>
<div class="centeredBoxContent marginTop">
<button id="register" class="mainAction" hidden>Create Passkey</button>
</div>
<div class="centeredBoxContent marginTop marginSides">
<div id="progress" hidden><label>Creating &amp; registering: <progress></progress></label></div>
</div>
</section>

<%- include('../end.html'); %>
Loading

0 comments on commit 887724e

Please sign in to comment.