diff --git a/nodejs/package-lock.json b/nodejs/package-lock.json index 785c99f..124c84e 100644 --- a/nodejs/package-lock.json +++ b/nodejs/package-lock.json @@ -1,19 +1,19 @@ { "name": "proxy-api", - "version": "1.5.3", + "version": "1.7.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "proxy-api", - "version": "1.5.3", + "version": "1.7.0", "license": "MIT", "dependencies": { "@fortawesome/fontawesome-free": "^7.3.0", "@popperjs/core": "^2.11.8", "@simpleworkjs/app-stack": "^1.0.0", "@simpleworkjs/conf": "^1.2.0", - "@simpleworkjs/frontend": "^0.2.6", + "@simpleworkjs/frontend": "^0.2.7", "@simpleworkjs/ldap": "^1.0.0", "@simpleworkjs/oidc-client": "^1.0.0", "acme-client": "^5.4.0", @@ -310,9 +310,9 @@ } }, "node_modules/@simpleworkjs/frontend": { - "version": "0.2.6", - "resolved": "https://registry.npmjs.org/@simpleworkjs/frontend/-/frontend-0.2.6.tgz", - "integrity": "sha512-2uqvEjxyZ2LE+sfhP6rJcEMmqdViazJ3ZkitWJXInPMWF6DiEZuP5MYqBqJvfDko63CCHEt1/ChFQd7Ry85Pzg==", + "version": "0.2.7", + "resolved": "https://registry.npmjs.org/@simpleworkjs/frontend/-/frontend-0.2.7.tgz", + "integrity": "sha512-s5oBc9dKLjd1bVhOQWR6+97faqQsbVKi0QYn5sNqOP6pGkUYUg2mY88ruHHg4Fp710owrzO/F3of/7tteFiGCw==", "license": "MIT", "engines": { "node": ">=18.0.0" diff --git a/nodejs/package.json b/nodejs/package.json index 18b18a1..a860baa 100644 --- a/nodejs/package.json +++ b/nodejs/package.json @@ -23,7 +23,7 @@ "@popperjs/core": "^2.11.8", "@simpleworkjs/app-stack": "^1.0.0", "@simpleworkjs/conf": "^1.2.0", - "@simpleworkjs/frontend": "^0.2.6", + "@simpleworkjs/frontend": "^0.2.7", "@simpleworkjs/ldap": "^1.0.0", "@simpleworkjs/oidc-client": "^1.0.0", "acme-client": "^5.4.0", diff --git a/nodejs/public/css/styles.css b/nodejs/public/css/styles.css index a34ad78..7065eae 100755 --- a/nodejs/public/css/styles.css +++ b/nodejs/public/css/styles.css @@ -7,6 +7,12 @@ body { display: flex; flex-direction: column; min-height: 100vh; + /* Height of the fixed navbar (plus the update banner, while shown -- + see top.ejs's showUpdateBanner/dismissUpdateBanner). Lets an in-page + sticky element offset itself below both fixed elements via + `top: var(--sw-content-offset)` instead of colliding with them at the + viewport's true top:0. */ + --sw-content-offset: 4.5rem; } #spa-shell { diff --git a/nodejs/public/lib/js/app-base.js b/nodejs/public/lib/js/app-base.js index 3d4398d..88f4290 100644 --- a/nodejs/public/lib/js/app-base.js +++ b/nodejs/public/lib/js/app-base.js @@ -584,10 +584,31 @@ app.util = (function(app){ document.body.removeChild(element); } + // Scroll a just-added/-edited element into view and flash its + // background, so the user's eye lands on the row that changed instead of + // it silently appearing/updating somewhere off-screen. Takes a jQuery + // object or a raw DOM node (e.g. jq-repeat's `item.__jq_$el`). + function revealItem(el){ + var node = el && el.jquery ? el[0] : el; + if (!node) return; + if (typeof node.scrollIntoView === 'function') { + node.scrollIntoView({behavior: 'smooth', block: 'center'}); + } + var prevTransition = node.style.transition; + var prevBg = node.style.backgroundColor; + node.style.transition = 'background-color 1.5s ease'; + node.style.backgroundColor = 'var(--bs-success-bg-subtle, #d1e7dd)'; + setTimeout(function(){ + node.style.backgroundColor = prevBg; + setTimeout(function(){ node.style.transition = prevTransition; }, 1500); + }, 300); + } + return { downloadFile: downloadFile, getUrlParameter: getUrlParameter, escapeHtml: escapeHtml, + revealItem: revealItem, } })(app); diff --git a/nodejs/routes/user.js b/nodejs/routes/user.js index d89e4d1..526d943 100755 --- a/nodejs/routes/user.js +++ b/nodejs/routes/user.js @@ -81,11 +81,20 @@ router.put('/password', async function(req, res, next){ } }); -// Admin: reset another user's password. +// Admin: reset another user's password. Blocked for SSO/OIDC-provisioned +// accounts (backing === 'oidc') -- they authenticate through the IdP, not a +// local password, so resetting one here would be a no-op at best and a +// false sense of control at worst. Only applies to the redis user backend; +// LDAP/PAM-backed deployments have no per-record marker for this. router.put('/password/:username', authz.requireAdmin, async function(req, res, next){ try{ validatePassword(req.body.password); let user = await User.get(req.params.username); + if(user.backing === 'oidc'){ + let e = new Error('Cannot set a password for an SSO-authenticated user.'); + e.status = 403; + throw e; + } return res.json({results: await user.setPassword(req.body)}); }catch(error){ next(error); diff --git a/nodejs/views/dns.ejs b/nodejs/views/dns.ejs index 126462e..4cfeab1 100644 --- a/nodejs/views/dns.ejs +++ b/nodejs/views/dns.ejs @@ -113,6 +113,7 @@ }); +
+
<%- include('bottom') %> diff --git a/nodejs/views/groups.ejs b/nodejs/views/groups.ejs index f09cb70..54f07eb 100644 --- a/nodejs/views/groups.ejs +++ b/nodejs/views/groups.ejs @@ -78,6 +78,7 @@ }); +
+ <%- include('bottom') %> diff --git a/nodejs/views/hosts.ejs b/nodejs/views/hosts.ejs index 525d0b8..7ee94ba 100755 --- a/nodejs/views/hosts.ejs +++ b/nodejs/views/hosts.ejs @@ -752,6 +752,7 @@ }); +
+
<%- include('bottom') %> diff --git a/nodejs/views/permissions.ejs b/nodejs/views/permissions.ejs index 52e06b4..0652bd2 100644 --- a/nodejs/views/permissions.ejs +++ b/nodejs/views/permissions.ejs @@ -66,6 +66,7 @@ app.subscribe(/^model:Permission:create/, function(data){ $.scope.Permission.remove(data.id); $.scope.Permission.unshift(data); + setTimeout(function(){ app.util.revealItem($('#permission-row-' + data.id)); }, 100); }); app.subscribe(/^model:Permission:remove/, function(data, topic){ $.scope.Permission.remove(topic.split(':')[3]); @@ -73,6 +74,7 @@ }); +
@@ -145,34 +147,31 @@
-
- - - - - - - - - - - - - - - - - - - -
TypeSubjectScopeDomainRoleDelete
{{ subjectType }}{{ subject }}{{ scope }}{{ domain }}{{ role }} - -
+
+ + + + <%- include('bottom') %> diff --git a/nodejs/views/profile.ejs b/nodejs/views/profile.ejs index 165924c..5d3626f 100644 --- a/nodejs/views/profile.ejs +++ b/nodejs/views/profile.ejs @@ -69,6 +69,7 @@ }); +
@@ -317,4 +318,5 @@
+
<%- include('bottom') %> diff --git a/nodejs/views/top.ejs b/nodejs/views/top.ejs index 1fe6879..0ea839c 100755 --- a/nodejs/views/top.ejs +++ b/nodejs/views/top.ejs @@ -82,16 +82,24 @@ +
+ <%- include('bottom') %>