Update version to 1.0.2 and enhance user navigation with personal Security access for authors and editors
This commit is contained in:
1 parent
6a90258ddd
commit
941312ac35
5 files changed
+67
-5
No files matched your search
@@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
OIDC SSO, TOTP and passkey second-factor authentication for **Bludit 3.22.0**.
|
OIDC SSO, TOTP and passkey second-factor authentication for **Bludit 3.22.0**.
|
||||||
|
|
||||||
Current version: **1.0.1**.
|
Current version: **1.0.2**.
|
||||||
|
|
||||||
## Features
|
## 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.
|
- 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.
|
- 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.
|
- 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.
|
- 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.
|
- 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.
|
- 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 \
|
docker cp bludit:/usr/share/nginx/html/bl-plugins/bludit-secure \
|
||||||
"/tmp/bludit-secure-backup-$(date +%Y%m%d-%H%M%S)"
|
"/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/
|
bludit:/usr/share/nginx/html/bl-plugins/bludit-secure/
|
||||||
|
|
||||||
docker restart bludit
|
docker restart bludit
|
||||||
@@ -91,6 +92,8 @@ Logging out ends the Bludit session only. Provider-wide logout and OIDC back-cha
|
|||||||
|
|
||||||
In **Security**:
|
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.
|
- **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.
|
- **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.
|
- **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.
|
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
|
## Changes in 1.0.1
|
||||||
|
|
||||||
- Applies native form styling and spacing to the passkey name input.
|
- Applies native form styling and spacing to the passkey name input.
|
||||||
|
|||||||
@@ -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
@@ -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
@@ -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>';
|
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() {
|
public function adminBodyEnd() {
|
||||||
return (new \BluditSecure\App($this))->usersViewEnhancement();
|
$app = new \BluditSecure\App($this);
|
||||||
|
return $app->navigationView().$app->usersViewEnhancement();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -397,6 +397,15 @@ final class App
|
|||||||
'emailVerified'=>$oidc->getVerifiedClaims('email_verified') === true
|
'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 {
|
public function usersViewEnhancement(): string {
|
||||||
global $layout, $users;
|
global $layout, $users;
|
||||||
if (($layout['view'] ?? '') !== 'users') { return ''; }
|
if (($layout['view'] ?? '') !== 'users') { return ''; }
|
||||||
|
|||||||
Reference in new issue
Block a user