diff --git a/lib/assets/admin-users.mjs b/lib/assets/admin-users.mjs index 9a54b2b..0288a94 100644 --- a/lib/assets/admin-users.mjs +++ b/lib/assets/admin-users.mjs @@ -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) { diff --git a/lib/assets/login.mjs b/lib/assets/login.mjs index 8ae6e4e..dac72de 100644 --- a/lib/assets/login.mjs +++ b/lib/assets/login.mjs @@ -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() { diff --git a/lib/assets/style.css b/lib/assets/style.css index 0cf21d9..d308c6c 100644 --- a/lib/assets/style.css +++ b/lib/assets/style.css @@ -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 { @@ -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; } @@ -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; @@ -399,29 +411,39 @@ 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; @@ -429,12 +451,11 @@ only screen and (max-width: 400px) { 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; @@ -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 */ @@ -532,6 +554,11 @@ body > footer > p { /* MAIN CONTENT */ +main { + width: 100%; + max-width: 65rem; +} + main.content { margin: auto; } @@ -562,6 +589,13 @@ main .message { text-align: center; } +.notTooWide { + width: 100%; + max-width: 30rem; + margin-left: auto; + margin-right: auto; +} + /* FORMS */ form { @@ -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; @@ -893,6 +927,9 @@ only screen and (max-width: 400px) { } } +.preWrap { + white-space: pre-wrap; +} /* ICONS */ diff --git a/lib/routes/admin.js b/lib/routes/admin.js index 4ca354c..378b6cd 100644 --- a/lib/routes/admin.js +++ b/lib/routes/admin.js @@ -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(); diff --git a/lib/routes/login.js b/lib/routes/login.js index 93370ac..f35dae9 100644 --- a/lib/routes/login.js +++ b/lib/routes/login.js @@ -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); @@ -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) => { @@ -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), diff --git a/lib/views/account/account.html b/lib/views/account/account.html index 3855c50..a147e30 100644 --- a/lib/views/account/account.html +++ b/lib/views/account/account.html @@ -3,57 +3,61 @@
-

<%= title %>

<%= username + '@' + host %>

+
+

<%= title %>

+

<%= username + '@' + host %>

+
- - - - - -
Account Privileges<%= Object.keys(accountPrivileges).join(', ') || '«none»' %>
Session Privileges<%= Object.keys(privileges).join(', ') || '«none»' %>
- -
-

Passkeys  

- -
- - - - - - - <% for (const cred of credentials) { %> - - - - - - <% } %> - -
Created usingCreated onLast used
<%= cred.name %><%= new Date(cred.createdAt).toLocaleDateString() %><%= cred.lastUsed ? new Date(cred.lastUsed).toLocaleString().replace(/:\d\d(?!:)/, '') : 'never' %>
- -
- -
To create a passkey on a new device, invite yourself to create another passkey:
-
- -
- - - - - - - - - +
+ + + + + +
Account Privileges<%= Object.keys(accountPrivileges).join(', ') || '«none»' %>
Session Privileges<%= Object.keys(privileges).join(', ') || '«none»' %>
+ +
+

Passkeys  

+ +
+ + + + + + + <% for (const cred of credentials) { %> + + + + + + <% } %> + +
Created usingCreated onLast used
<%= cred.name %><%= new Date(cred.createdAt).toLocaleDateString() %><%= cred.lastUsed ? new Date(cred.lastUsed).toLocaleString().replace(/:\d\d(?!:)/, '') : 'never' %>
+ +
+ +
To create a passkey on a new device, invite yourself to create another passkey:
+
+ +
+ + + + + + + + +
<%- include('../end.html'); %> diff --git a/lib/views/admin/invite-requests.html b/lib/views/admin/invite-requests.html index 8a49f09..0bd4589 100644 --- a/lib/views/admin/invite-requests.html +++ b/lib/views/admin/invite-requests.html @@ -46,9 +46,9 @@ -