diff --git a/CHANGELOG.md b/CHANGELOG.md
index 3186009..2146020 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,24 @@
# Changelog
+## Changes 5/8/2025 v1.3.3
+
+### Enhancements
+
+- **Admin API** (`updateConfig.php`):
+ - Now merges incoming payload onto existing on-disk settings instead of overwriting blanks.
+ - Preserves `clientId`, `clientSecret`, `providerUrl` and `redirectUri` when those fields are omitted or empty in the request.
+
+- **Admin API** (`getConfig.php`):
+ - Returns only a safe subset of admin settings (omits `clientSecret`) to prevent accidental exposure of sensitive data.
+
+- **Frontend** (`auth.js`):
+ - Update UI based on merged loginOptions from the server, ensuring blank or missing fields no longer revert your existing config.
+
+- **Auth API** (`auth.php`):
+ - Added `$oidc->addScope(['openid','profile','email']);` to OIDC flow. (This should resolve authentik issue)
+
+---
+
## Changes 5/8/2025 v1.3.2
### config/config.php
@@ -50,6 +69,10 @@
- In the “not authenticated” branch, only shows the login form if `authBypass` is false.
- No other core fetch/token logic changed; all existing flows remain intact.
+### Security
+
+- **Admin API**: `getConfig.php` now returns only a safe subset of admin settings (omits `clientSecret`) to prevent accidental exposure of sensitive data.
+
---
## Changes 5/4/2025 v1.3.1
diff --git a/public/js/adminPanel.js b/public/js/adminPanel.js
index c9a13a5..12b1804 100644
--- a/public/js/adminPanel.js
+++ b/public/js/adminPanel.js
@@ -3,7 +3,7 @@ import { loadAdminConfigFunc } from './auth.js';
import { showToast, toggleVisibility, attachEnterKeyListener } from './domUtils.js';
import { sendRequest } from './networkUtils.js';
-const version = "v1.3.2";
+const version = "v1.3.3";
const adminTitle = `${t("admin_panel")} ${version}`;
// ————— Inject updated styles —————
@@ -425,6 +425,9 @@ export function openAdminPanel() {
// — OIDC & TOTP —
document.getElementById("oidcContent").innerHTML = `
+
+ Note: OIDC credentials (Client ID/Secret) will show blank here after saving, but remain unchanged until you explicitly edit and save them.
+
diff --git a/public/js/auth.js b/public/js/auth.js
index 6066dab..b505f32 100644
--- a/public/js/auth.js
+++ b/public/js/auth.js
@@ -23,8 +23,8 @@ import { initializeApp } from './main.js';
// Production OIDC configuration (override via API as needed)
const currentOIDCConfig = {
providerUrl: "https://your-oidc-provider.com",
- clientId: "YOUR_CLIENT_ID",
- clientSecret: "YOUR_CLIENT_SECRET",
+ clientId: "",
+ clientSecret: "",
redirectUri: "https://yourdomain.com/api/auth/auth.php?oidc=callback",
globalOtpauthUrl: ""
};
diff --git a/src/controllers/AdminController.php b/src/controllers/AdminController.php
index 3ee5a42..997b1d3 100644
--- a/src/controllers/AdminController.php
+++ b/src/controllers/AdminController.php
@@ -54,23 +54,27 @@ class AdminController
{
header('Content-Type: application/json');
$config = AdminModel::getConfig();
-
if (isset($config['error'])) {
http_response_code(500);
+ echo json_encode(['error' => $config['error']]);
+ exit;
}
- if (!isset($config['loginOptions']) || !is_array($config['loginOptions'])) {
- $config['loginOptions'] = [];
- }
- if (!array_key_exists('authBypass', $config['loginOptions'])) {
- $config['loginOptions']['authBypass'] = false;
- }
- if (!array_key_exists('authHeaderName', $config['loginOptions'])) {
- $config['loginOptions']['authHeaderName'] = 'X-Remote-User';
- }
- // ← END INSERT
+ // Build a safe subset for the front-end
+ $safe = [
+ 'header_title' => $config['header_title'],
+ 'loginOptions' => $config['loginOptions'],
+ 'globalOtpauthUrl' => $config['globalOtpauthUrl'],
+ 'enableWebDAV' => $config['enableWebDAV'],
+ 'sharedMaxUploadSize' => $config['sharedMaxUploadSize'],
+ 'oidc' => [
+ 'providerUrl' => $config['oidc']['providerUrl'],
+ 'redirectUri' => $config['oidc']['redirectUri'],
+ // clientSecret and clientId never exposed here
+ ],
+ ];
- echo json_encode($config);
+ echo json_encode($safe);
exit;
}
@@ -133,119 +137,106 @@ class AdminController
* @return void Outputs a JSON response indicating success or failure.
*/
public function updateConfig(): void
- {
- header('Content-Type: application/json');
+{
+ header('Content-Type: application/json');
- // Ensure the user is authenticated and is an admin.
- if (
- !isset($_SESSION['authenticated']) || $_SESSION['authenticated'] !== true ||
- !isset($_SESSION['isAdmin']) || !$_SESSION['isAdmin']
- ) {
- http_response_code(403);
- echo json_encode(['error' => 'Unauthorized access.']);
- exit;
- }
-
- // Validate CSRF token.
- $headersArr = array_change_key_case(getallheaders(), CASE_LOWER);
- $receivedToken = isset($headersArr['x-csrf-token']) ? trim($headersArr['x-csrf-token']) : '';
- if (!isset($_SESSION['csrf_token']) || $receivedToken !== $_SESSION['csrf_token']) {
- http_response_code(403);
- echo json_encode(['error' => 'Invalid CSRF token.']);
- exit;
- }
-
- // Retrieve and decode JSON input.
- $input = file_get_contents('php://input');
- $data = json_decode($input, true);
- if (!is_array($data)) {
- http_response_code(400);
- echo json_encode(['error' => 'Invalid input.']);
- exit;
- }
-
- // Prepare existing settings
- $headerTitle = isset($data['header_title']) ? trim($data['header_title']) : "";
- $oidc = isset($data['oidc']) ? $data['oidc'] : [];
- $oidcProviderUrl = isset($oidc['providerUrl']) ? filter_var($oidc['providerUrl'], FILTER_SANITIZE_URL) : '';
- $oidcClientId = isset($oidc['clientId']) ? trim($oidc['clientId']) : '';
- $oidcClientSecret = isset($oidc['clientSecret']) ? trim($oidc['clientSecret']) : '';
- $oidcRedirectUri = isset($oidc['redirectUri']) ? filter_var($oidc['redirectUri'], FILTER_SANITIZE_URL) : '';
- if (!$oidcProviderUrl || !$oidcClientId || !$oidcClientSecret || !$oidcRedirectUri) {
- http_response_code(400);
- echo json_encode(['error' => 'Incomplete OIDC configuration.']);
- exit;
- }
-
- $disableFormLogin = false;
- if (isset($data['loginOptions']['disableFormLogin'])) {
- $disableFormLogin = filter_var($data['loginOptions']['disableFormLogin'], FILTER_VALIDATE_BOOLEAN);
- } elseif (isset($data['disableFormLogin'])) {
- $disableFormLogin = filter_var($data['disableFormLogin'], FILTER_VALIDATE_BOOLEAN);
- }
- $disableBasicAuth = false;
- if (isset($data['loginOptions']['disableBasicAuth'])) {
- $disableBasicAuth = filter_var($data['loginOptions']['disableBasicAuth'], FILTER_VALIDATE_BOOLEAN);
- } elseif (isset($data['disableBasicAuth'])) {
- $disableBasicAuth = filter_var($data['disableBasicAuth'], FILTER_VALIDATE_BOOLEAN);
- }
-
- $disableOIDCLogin = false;
- if (isset($data['loginOptions']['disableOIDCLogin'])) {
- $disableOIDCLogin = filter_var($data['loginOptions']['disableOIDCLogin'], FILTER_VALIDATE_BOOLEAN);
- } elseif (isset($data['disableOIDCLogin'])) {
- $disableOIDCLogin = filter_var($data['disableOIDCLogin'], FILTER_VALIDATE_BOOLEAN);
- }
- $globalOtpauthUrl = isset($data['globalOtpauthUrl']) ? trim($data['globalOtpauthUrl']) : "";
-
- // ── NEW: enableWebDAV flag ──────────────────────────────────────
- $enableWebDAV = false;
- if (array_key_exists('enableWebDAV', $data)) {
- $enableWebDAV = filter_var($data['enableWebDAV'], FILTER_VALIDATE_BOOLEAN);
- } elseif (isset($data['features']['enableWebDAV'])) {
- $enableWebDAV = filter_var($data['features']['enableWebDAV'], FILTER_VALIDATE_BOOLEAN);
- }
-
- // ── NEW: sharedMaxUploadSize ──────────────────────────────────────
- $sharedMaxUploadSize = null;
- if (array_key_exists('sharedMaxUploadSize', $data)) {
- $sharedMaxUploadSize = filter_var($data['sharedMaxUploadSize'], FILTER_VALIDATE_INT);
- } elseif (isset($data['features']['sharedMaxUploadSize'])) {
- $sharedMaxUploadSize = filter_var($data['features']['sharedMaxUploadSize'], FILTER_VALIDATE_INT);
- }
-
- $authBypass = filter_var(
- $data['loginOptions']['authBypass'] ?? false,
- FILTER_VALIDATE_BOOLEAN
- );
- $authHeaderName = trim($data['loginOptions']['authHeaderName'] ?? '') ?: 'X-Remote-User';
-
- $configUpdate = [
- 'header_title' => $headerTitle,
- 'oidc' => [
- 'providerUrl' => $oidcProviderUrl,
- 'clientId' => $oidcClientId,
- 'clientSecret' => $oidcClientSecret,
- 'redirectUri' => $oidcRedirectUri,
- ],
- 'loginOptions' => [
- 'disableFormLogin' => $disableFormLogin,
- 'disableBasicAuth' => $disableBasicAuth,
- 'disableOIDCLogin' => $disableOIDCLogin,
- 'authBypass' => $authBypass,
- 'authHeaderName' => $authHeaderName,
- ],
- 'globalOtpauthUrl' => $globalOtpauthUrl,
- 'enableWebDAV' => $enableWebDAV,
- 'sharedMaxUploadSize' => $sharedMaxUploadSize // ← NEW
- ];
-
- // Delegate to the model.
- $result = AdminModel::updateConfig($configUpdate);
- if (isset($result['error'])) {
- http_response_code(500);
- }
- echo json_encode($result);
+ // —– auth & CSRF checks —–
+ if (
+ !isset($_SESSION['authenticated']) || $_SESSION['authenticated'] !== true ||
+ !isset($_SESSION['isAdmin']) || !$_SESSION['isAdmin']
+ ) {
+ http_response_code(403);
+ echo json_encode(['error' => 'Unauthorized access.']);
exit;
}
+ $headersArr = array_change_key_case(getallheaders(), CASE_LOWER);
+ $receivedToken = trim($headersArr['x-csrf-token'] ?? '');
+ if (!isset($_SESSION['csrf_token']) || $receivedToken !== $_SESSION['csrf_token']) {
+ http_response_code(403);
+ echo json_encode(['error' => 'Invalid CSRF token.']);
+ exit;
+ }
+
+ // —– fetch payload —–
+ $data = json_decode(file_get_contents('php://input'), true);
+ if (!is_array($data)) {
+ http_response_code(400);
+ echo json_encode(['error' => 'Invalid input.']);
+ exit;
+ }
+
+ // —– load existing on-disk config —–
+ $existing = AdminModel::getConfig();
+
+ // —– start merge with existing as base —–
+ $merged = $existing;
+
+ // header_title
+ if (array_key_exists('header_title', $data)) {
+ $merged['header_title'] = trim($data['header_title']);
+ }
+
+ // loginOptions: inherit existing then override if provided
+ $merged['loginOptions'] = $existing['loginOptions'] ?? [
+ 'disableFormLogin' => false,
+ 'disableBasicAuth' => false,
+ 'disableOIDCLogin'=> false,
+ 'authBypass' => false,
+ 'authHeaderName' => 'X-Remote-User'
+ ];
+ foreach (['disableFormLogin','disableBasicAuth','disableOIDCLogin','authBypass'] as $flag) {
+ if (isset($data['loginOptions'][$flag])) {
+ $merged['loginOptions'][$flag] = filter_var(
+ $data['loginOptions'][$flag],
+ FILTER_VALIDATE_BOOLEAN
+ );
+ }
+ }
+ if (isset($data['loginOptions']['authHeaderName'])) {
+ $hdr = trim($data['loginOptions']['authHeaderName']);
+ if ($hdr !== '') {
+ $merged['loginOptions']['authHeaderName'] = $hdr;
+ }
+ }
+
+ // globalOtpauthUrl
+ if (array_key_exists('globalOtpauthUrl', $data)) {
+ $merged['globalOtpauthUrl'] = trim($data['globalOtpauthUrl']);
+ }
+
+ // enableWebDAV
+ if (array_key_exists('enableWebDAV', $data)) {
+ $merged['enableWebDAV'] = filter_var($data['enableWebDAV'], FILTER_VALIDATE_BOOLEAN);
+ }
+
+ // sharedMaxUploadSize
+ if (array_key_exists('sharedMaxUploadSize', $data)) {
+ $sms = filter_var($data['sharedMaxUploadSize'], FILTER_VALIDATE_INT);
+ if ($sms !== false) {
+ $merged['sharedMaxUploadSize'] = $sms;
+ }
+ }
+
+ // oidc: only overwrite non-empty inputs
+ $merged['oidc'] = $existing['oidc'] ?? [
+ 'providerUrl'=>'','clientId'=>'','clientSecret'=>'','redirectUri'=>''
+ ];
+ foreach (['providerUrl','clientId','clientSecret','redirectUri'] as $f) {
+ if (!empty($data['oidc'][$f])) {
+ $val = trim($data['oidc'][$f]);
+ if ($f === 'providerUrl' || $f === 'redirectUri') {
+ $val = filter_var($val, FILTER_SANITIZE_URL);
+ }
+ $merged['oidc'][$f] = $val;
+ }
+ }
+
+ // —– persist merged config —–
+ $result = AdminModel::updateConfig($merged);
+ if (isset($result['error'])) {
+ http_response_code(500);
+ }
+ echo json_encode($result);
+ exit;
+}
}
\ No newline at end of file
diff --git a/src/controllers/AuthController.php b/src/controllers/AuthController.php
index f07c2d6..cb99d6a 100644
--- a/src/controllers/AuthController.php
+++ b/src/controllers/AuthController.php
@@ -111,6 +111,8 @@ class AuthController
$cfg['oidc']['clientSecret']
);
$oidc->setRedirectURL($cfg['oidc']['redirectUri']);
+ $oidc->addScope(['openid','profile','email']);
+
if ($oidcAction === 'callback') {
try {
diff --git a/src/models/AdminModel.php b/src/models/AdminModel.php
index 5f0b483..a8eec7b 100644
--- a/src/models/AdminModel.php
+++ b/src/models/AdminModel.php
@@ -186,8 +186,8 @@ class AdminModel
'header_title' => "FileRise",
'oidc' => [
'providerUrl' => 'https://your-oidc-provider.com',
- 'clientId' => 'YOUR_CLIENT_ID',
- 'clientSecret' => 'YOUR_CLIENT_SECRET',
+ 'clientId' => '',
+ 'clientSecret' => '',
'redirectUri' => 'https://yourdomain.com/api/auth/auth.php?oidc=callback'
],
'loginOptions' => [