Update version to 1.0.2 and enhance user navigation with personal Security access for authors and editors

This commit is contained in:
spleenftw committed 2026-11-03 15:02:38 +01:00
1 parent 6a90258ddd
commit 941312ac35
5 files changed
+67 -5

No files matched your search

+12 -3
View File
@@ -2,7 +2,7 @@
OIDC SSO, TOTP and passkey second-factor authentication for **Bludit 3.22.0**.
Current version: **1.0.1**.
Current version: **1.0.2**.
## Features
@@ -10,6 +10,7 @@ Current version: **1.0.1**.
- Adds a full-width, slate-grey **Sign in with XYZ** button with a configurable provider name.
- Automatically opens the browser passkey prompt after password verification when a passkey is enabled. Cancellation does not trigger a prompt loop; an explicit retry remains available.
- Integrates **Security** into the native admin dashboard, including its sidebar, shield icon and Bootstrap controls. Sign out through the existing **Log out** sidebar entry.
- Gives authors, editors and administrators access to their own Security page through desktop and mobile navigation, with an additional shortcut in their own Profile → Security tab.
- Shows SSO link status, provider, SSO username and SSO email in the administrator's native **Users** list and the user's **Security** page.
- Lets each user register TOTP, multiple named passkeys and an OIDC identity, then choose their own second-factor policy: disabled, TOTP, passkey, or either method.
- Optionally requires the local second factor after SSO as well.
@@ -55,9 +56,9 @@ For `bludit/docker`, copy the extracted plugin into `/usr/share/nginx/html/bl-pl
docker cp bludit:/usr/share/nginx/html/bl-plugins/bludit-secure \
"/tmp/bludit-secure-backup-$(date +%Y%m%d-%H%M%S)"
unzip -o /tmp/bludit-secure-1.0.1.zip -d /tmp/bludit-secure-1.0.1
unzip -o /tmp/bludit-secure-1.0.2.zip -d /tmp/bludit-secure-1.0.2
docker cp /tmp/bludit-secure-1.0.1/bludit-secure/. \
docker cp /tmp/bludit-secure-1.0.2/bludit-secure/. \
bludit:/usr/share/nginx/html/bl-plugins/bludit-secure/
docker restart bludit
@@ -91,6 +92,8 @@ Logging out ends the Bludit session only. Provider-wide logout and OIDC back-cha
In **Security**:
Every signed-in author, editor and administrator can manage their own methods. Open **Security** in desktop or mobile navigation, or **Profile → Security → Manage authentication methods**. The direct page is `/admin/plugin/pluginbluditsecure`, adjusted for your configured admin path. Global SSO configuration and the Users list remain administrator-only.
- **TOTP:** select **Set up TOTP**, copy the `otpauth://` setup URI into your authenticator app and confirm a code. TOTP uses SHA-1, six digits and a 30-second period. Previously accepted codes cannot be reused.
- **Passkeys:** select **Add passkey**, enter a name and choose your password manager or authenticator in the browser. Multiple passkeys are supported, with user verification required. The browser selects the authenticator; the plugin does not force a particular manager.
- **Second factor:** choose the required method and whether it also applies after SSO. **TOTP or passkey** requires both methods to be registered.
@@ -118,6 +121,12 @@ The plugin protects **web sessions under `/admin`**. It does not change authenti
JavaScript URLs include a content hash so updated passkey behavior is not hidden by stale asset caches.
## Changes in 1.0.2
- Makes personal Security navigation available to authors, whose native plugin sidebar is hidden by Bludit.
- Adds the personal Security link to mobile navigation for authors and editors.
- Adds an authentication-management shortcut to the user's own Profile → Security tab.
## Changes in 1.0.1
- Applies native form styling and spacing to the passkey name input.
+43
View File
@@ -0,0 +1,43 @@
'use strict';
(() => {
const data = document.getElementById('bs-security-navigation');
if (!data) return;
const config = JSON.parse(data.textContent);
const account = new URL(config.account, document.baseURI).href;
const logout = new URL(config.logout, document.baseURI).href;
const href = link => new URL(link.getAttribute('href'), document.baseURI).href;
const makeLink = () => {
const link = document.createElement('a');
link.href = account;
link.className = 'nav-link';
const icon = document.createElement('span');
icon.className = 'fa fa-shield';
icon.setAttribute('aria-hidden', 'true');
link.append(icon, document.createTextNode('Security'));
return link;
};
// Native themes hide plugin sidebar hooks from authors and mobile editors.
for (const nav of document.querySelectorAll('.sidebar .nav, #navbarNav .navbar-nav')) {
if (Array.from(nav.querySelectorAll('a[href]')).some(link => href(link) === account)) continue;
const item = document.createElement('li');
item.className = 'nav-item';
item.appendChild(makeLink());
const logoutItem = Array.from(nav.children).find(child => Array.from(child.querySelectorAll('a[href]')).some(link => href(link) === logout));
nav.insertBefore(item, logoutItem || null);
}
if (config.ownProfile) {
const section = document.querySelector('#security.tab-pane');
if (!section || section.querySelector('[data-bs-security-profile]')) return;
const box = document.createElement('div');
box.className = 'mb-4';
box.setAttribute('data-bs-security-profile', 'true');
const description = document.createElement('p');
description.textContent = 'Manage TOTP, passkeys, SSO and recovery codes for your account.';
const link = document.createElement('a');
link.href = account;
link.className = 'btn btn-outline-primary';
link.textContent = 'Manage authentication methods';
box.append(description, link);
section.prepend(box);
}
})();
+1 -1
View File
@@ -1 +1 @@
{"author":"Interlope","version":"1.0.1","releaseDate":"2026-11-03","license":"MIT","compatible":"3.22.0","notes":"Per-user OIDC SSO, TOTP, passkeys and recovery codes. Requires PHP 8.2+, HTTPS, sodium, curl, mbstring and openssl."}
{"author":"Interlope","version":"1.0.2","releaseDate":"2026-11-03","license":"MIT","compatible":"3.22.0","notes":"Per-user OIDC SSO, TOTP, passkeys and recovery codes. Requires PHP 8.2+, HTTPS, sodium, curl, mbstring and openssl."}
+2 -1
View File
@@ -77,6 +77,7 @@ class pluginBluditSecure extends Plugin
return '<a class="nav-link" href="'.HTML_PATH_ADMIN_ROOT.'plugin/pluginbluditsecure"><span class="fa fa-shield" aria-hidden="true"></span>Security</a>';
}
public function adminBodyEnd() {
return (new \BluditSecure\App($this))->usersViewEnhancement();
$app = new \BluditSecure\App($this);
return $app->navigationView().$app->usersViewEnhancement();
}
}
+9
View File
@@ -397,6 +397,15 @@ final class App
'emailVerified'=>$oidc->getVerifiedClaims('email_verified') === true
];
}
public function navigationView(): string {
global $layout, $user;
$name = $this->authenticated();
if ($name === null) { return ''; }
$ownProfile = ($layout['view'] ?? '') === 'edit-user' && isset($user) && is_object($user) && method_exists($user, 'username') && $user->username() === $name;
$data = json_encode(['account'=>$this->accountUrl(), 'logout'=>DOMAIN_ADMIN.'logout', 'ownProfile'=>$ownProfile], JSON_HEX_TAG | JSON_HEX_AMP | JSON_HEX_APOS | JSON_HEX_QUOT | JSON_THROW_ON_ERROR);
$version = substr(hash_file('sha256', dirname(__DIR__).'/assets/navigation.js'), 0, 16);
return '<script type="application/json" id="bs-security-navigation">'.$data.'</script><script src="'.$this->e($this->plugin->htmlPath().'assets/navigation.js?v='.$version).'" defer></script>';
}
public function usersViewEnhancement(): string {
global $layout, $users;
if (($layout['view'] ?? '') !== 'users') { return ''; }