From 2810b97568630387d98ccb51d84a24c0f47c8801 Mon Sep 17 00:00:00 2001 From: Ryan Date: Sun, 23 Nov 2025 06:43:51 -0500 Subject: [PATCH] chore(demo): update manual sync script and lock TOTP for demo account - Update scripts/manual-sync.sh to pull v2.0.2, backup extra demo/Pro dirs, and safely rsync core code without touching data, bundles, or site overrides - After sync, automatically flip FR_DEMO_MODE to true in config/config.php so the droplet always runs in demo mode - Block TOTP enable/disable/setup and recovery code generation for the demo account when FR_DEMO_MODE is enabled, returning 403 with clear JSON errors --- scripts/manual-sync.sh | 40 ++++++++++++++++++++++-------- src/controllers/UserController.php | 34 +++++++++++++++++++++++++ 2 files changed, 63 insertions(+), 11 deletions(-) diff --git a/scripts/manual-sync.sh b/scripts/manual-sync.sh index ab5b6cb..18f04b6 100644 --- a/scripts/manual-sync.sh +++ b/scripts/manual-sync.sh @@ -1,19 +1,24 @@ #!/usr/bin/env bash -# === Update FileRise to v1.9.1 (safe rsync) === -# shellcheck disable=SC2155 # we intentionally assign 'stamp' with command substitution - +# === Update FileRise to v2.0.2 (safe rsync) === set -Eeuo pipefail -VER="v1.9.1" -ASSET="FileRise-${VER}.zip" # If the asset name is different, set it exactly (e.g. FileRise-v1.9.0.zip) +VER="v2.0.2" +ASSET="FileRise-${VER}.zip" # matches GitHub release asset name WEBROOT="/var/www" TMP="/tmp/filerise-update" -# 0) (optional) quick backup of critical bits +# 0) quick backup of critical bits (include Pro/demo stuff too) stamp="$(date +%F-%H%M)" mkdir -p /root/backups tar -C "$WEBROOT" -czf "/root/backups/filerise-$stamp.tgz" \ - public/.htaccess config users uploads metadata || true + public/.htaccess \ + config \ + users \ + uploads \ + metadata \ + filerise-bundles \ + filerise-config \ + filerise-site || true echo "Backup saved to /root/backups/filerise-$stamp.tgz" # 1) Fetch the release zip @@ -29,12 +34,15 @@ STAGE_DIR="$(find "$TMP" -maxdepth 1 -type d -name 'FileRise*' ! -path "$TMP" | # 3) Sync code into /var/www # - keep public/.htaccess # - keep data dirs and current config.php +# - DO NOT touch filerise-site / bundles / demo config rsync -a --delete \ --exclude='public/.htaccess' \ --exclude='uploads/***' \ --exclude='users/***' \ --exclude='metadata/***' \ - --exclude='config/config.php' \ + --exclude='filerise-bundles/***' \ + --exclude='filerise-config/***' \ + --exclude='filerise-site/***' \ --exclude='.github/***' \ --exclude='docker-compose.yml' \ "$STAGE_DIR"/ "$WEBROOT"/ @@ -42,13 +50,23 @@ rsync -a --delete \ # 4) Ownership (Ubuntu/Debian w/ Apache) chown -R www-data:www-data "$WEBROOT" -# 5) (optional) Composer autoload optimization if composer is available +# 5) Composer autoload optimization if composer is available if command -v composer >/dev/null 2>&1; then cd "$WEBROOT" || { echo "cd to $WEBROOT failed" >&2; exit 1; } composer install --no-dev --optimize-autoloader fi -# 6) Reload Apache (don’t fail the whole script if reload isn’t available) +# 6) Force demo mode ON in config/config.php +CFG_FILE="$WEBROOT/config/config.php" +if [[ -f "$CFG_FILE" ]]; then + # Make a one-time backup of config.php before editing + cp "$CFG_FILE" "${CFG_FILE}.bak.$stamp" || true + + # Flip FR_DEMO_MODE to true if it exists as false + sed -i "s/define('FR_DEMO_MODE',[[:space:]]*false);/define('FR_DEMO_MODE', true);/" "$CFG_FILE" || true +fi + +# 7) Reload Apache (don’t fail the whole script if reload isn’t available) systemctl reload apache2 2>/dev/null || true -echo "✅ FileRise updated to ${VER} (code). Data and public/.htaccess preserved." \ No newline at end of file +echo "FileRise updated to ${VER} (code). Demo mode forced ON. Data, Pro bundles, and demo site preserved." \ No newline at end of file diff --git a/src/controllers/UserController.php b/src/controllers/UserController.php index 9277bec..92712a0 100644 --- a/src/controllers/UserController.php +++ b/src/controllers/UserController.php @@ -327,6 +327,14 @@ class UserController exit; } + if (defined('FR_DEMO_MODE') && FR_DEMO_MODE && $username === 'demo') { + http_response_code(403); + echo json_encode([ + 'error' => 'TOTP settings are disabled for the demo account.' + ]); + exit; + } + $totp_enabled = isset($data['totp_enabled']) ? filter_var($data['totp_enabled'], FILTER_VALIDATE_BOOLEAN) : false; $result = UserModel::updateUserPanel($username, $totp_enabled); echo json_encode($result); @@ -348,6 +356,14 @@ class UserController exit; } + if (defined('FR_DEMO_MODE') && FR_DEMO_MODE && $username === 'demo') { + http_response_code(403); + echo json_encode([ + 'error' => 'TOTP settings are disabled for the demo account.' + ]); + exit; + } + $result = UserModel::disableTOTPSecret($username); if ($result) { echo json_encode(["success" => true, "message" => "TOTP disabled successfully."]); @@ -412,6 +428,16 @@ class UserController } $userId = $_SESSION['username']; + + if (defined('FR_DEMO_MODE') && FR_DEMO_MODE && $userId === 'demo') { + http_response_code(403); + echo json_encode([ + 'status' => 'error', + 'message' => 'TOTP settings are disabled for the demo account.', + ]); + exit; + } + if (!preg_match(REGEX_USER, $userId)) { http_response_code(400); echo json_encode(['status' => 'error', 'message' => 'Invalid user identifier']); @@ -438,6 +464,14 @@ class UserController exit; } + $username = $_SESSION['username'] ?? ($_SESSION['pending_login_user'] ?? ''); + if (defined('FR_DEMO_MODE') && FR_DEMO_MODE && $username === 'demo') { + http_response_code(403); + header('Content-Type: application/json'); + echo json_encode(['error' => 'TOTP setup is disabled for the demo account.']); + } + + self::requireCsrf(); // Fix: if username not present (pending flow), fall back to pending_login_user