feat: Allow updating CloudFlare settings in visitor mode
This commit is contained in:
@@ -178,7 +178,7 @@ export const updateSettings = async (
|
||||
const mergedSettings = { ...defaultSettings, ...existingSettings };
|
||||
|
||||
// Check if visitor mode is enabled
|
||||
// If visitor mode is enabled, only allow disabling it (setting visitorMode to false)
|
||||
// If visitor mode is enabled, only allow disabling it (setting visitorMode to false) or updating CloudFlare settings
|
||||
if (mergedSettings.visitorMode === true) {
|
||||
// If visitorMode is being explicitly set to false, allow the update
|
||||
if (newSettings.visitorMode === false) {
|
||||
@@ -206,12 +206,30 @@ export const updateSettings = async (
|
||||
});
|
||||
return;
|
||||
}
|
||||
// If visitor mode is enabled and trying to change other settings (without explicitly disabling visitor mode), block it
|
||||
res.status(403).json({
|
||||
success: false,
|
||||
error: "Visitor mode is enabled. Only disabling visitor mode is allowed.",
|
||||
});
|
||||
return;
|
||||
|
||||
// Allow CloudFlare tunnel settings updates (read-only access mechanism, doesn't violate visitor mode)
|
||||
const isOnlyCloudflareUpdate =
|
||||
(newSettings.cloudflaredTunnelEnabled !== undefined ||
|
||||
newSettings.cloudflaredToken !== undefined) &&
|
||||
Object.keys(newSettings).every(
|
||||
(key) =>
|
||||
key === "cloudflaredTunnelEnabled" ||
|
||||
key === "cloudflaredToken" ||
|
||||
key === "visitorMode"
|
||||
);
|
||||
|
||||
if (isOnlyCloudflareUpdate) {
|
||||
// Allow CloudFlare settings updates even in visitor mode
|
||||
// Continue with normal settings update flow below
|
||||
} else {
|
||||
// If visitor mode is enabled and trying to change other settings (without explicitly disabling visitor mode), block it
|
||||
res.status(403).json({
|
||||
success: false,
|
||||
error:
|
||||
"Visitor mode is enabled. Only disabling visitor mode or updating CloudFlare settings is allowed.",
|
||||
});
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Validate settings if needed
|
||||
@@ -282,6 +300,15 @@ export const updateSettings = async (
|
||||
}
|
||||
}
|
||||
|
||||
// Preserve CloudFlare settings if not explicitly provided (to prevent stopping tunnel when enabling visitor mode)
|
||||
if (newSettings.cloudflaredTunnelEnabled === undefined) {
|
||||
newSettings.cloudflaredTunnelEnabled =
|
||||
existingSettings.cloudflaredTunnelEnabled;
|
||||
}
|
||||
if (newSettings.cloudflaredToken === undefined) {
|
||||
newSettings.cloudflaredToken = existingSettings.cloudflaredToken;
|
||||
}
|
||||
|
||||
storageService.saveSettings(newSettings);
|
||||
|
||||
// Check for moveSubtitlesToVideoFolder change
|
||||
@@ -315,11 +342,16 @@ export const updateSettings = async (
|
||||
}
|
||||
|
||||
// Handle Cloudflare Tunnel settings changes
|
||||
if (
|
||||
// Only process changes if the values were explicitly provided (not undefined)
|
||||
const cloudflaredEnabledChanged =
|
||||
newSettings.cloudflaredTunnelEnabled !== undefined &&
|
||||
newSettings.cloudflaredTunnelEnabled !==
|
||||
existingSettings.cloudflaredTunnelEnabled ||
|
||||
newSettings.cloudflaredToken !== existingSettings.cloudflaredToken
|
||||
) {
|
||||
existingSettings.cloudflaredTunnelEnabled;
|
||||
const cloudflaredTokenChanged =
|
||||
newSettings.cloudflaredToken !== undefined &&
|
||||
newSettings.cloudflaredToken !== existingSettings.cloudflaredToken;
|
||||
|
||||
if (cloudflaredEnabledChanged || cloudflaredTokenChanged) {
|
||||
// If we are enabling it (or it was enabled and config changed)
|
||||
if (newSettings.cloudflaredTunnelEnabled) {
|
||||
// Determine port
|
||||
@@ -342,8 +374,8 @@ export const updateSettings = async (
|
||||
cloudflaredService.start(undefined, port);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// If disabled, stop
|
||||
} else if (cloudflaredEnabledChanged) {
|
||||
// Only stop if explicitly disabled (not if it was undefined)
|
||||
cloudflaredService.stop();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -26,12 +26,15 @@ export const visitorModeSettingsMiddleware = (
|
||||
return;
|
||||
}
|
||||
|
||||
// For POST requests, check if it's trying to disable visitor mode or verify password
|
||||
// For POST requests, check if it's trying to disable visitor mode, verify password, or update CloudFlare settings
|
||||
if (req.method === "POST") {
|
||||
// Allow verify-password requests
|
||||
if (req.path.includes("/verify-password") || req.url.includes("/verify-password")) {
|
||||
next();
|
||||
return;
|
||||
if (
|
||||
req.path.includes("/verify-password") ||
|
||||
req.url.includes("/verify-password")
|
||||
) {
|
||||
next();
|
||||
return;
|
||||
}
|
||||
|
||||
const body = req.body || {};
|
||||
@@ -41,10 +44,29 @@ export const visitorModeSettingsMiddleware = (
|
||||
next();
|
||||
return;
|
||||
}
|
||||
|
||||
// Allow CloudFlare tunnel settings updates (read-only access mechanism, doesn't violate visitor mode)
|
||||
const isOnlyCloudflareUpdate =
|
||||
(body.cloudflaredTunnelEnabled !== undefined ||
|
||||
body.cloudflaredToken !== undefined) &&
|
||||
Object.keys(body).every(
|
||||
(key) =>
|
||||
key === "cloudflaredTunnelEnabled" ||
|
||||
key === "cloudflaredToken" ||
|
||||
key === "visitorMode"
|
||||
);
|
||||
|
||||
if (isOnlyCloudflareUpdate) {
|
||||
// Allow CloudFlare settings updates even in visitor mode
|
||||
next();
|
||||
return;
|
||||
}
|
||||
|
||||
// Block all other settings updates
|
||||
res.status(403).json({
|
||||
success: false,
|
||||
error: "Visitor mode is enabled. Only disabling visitor mode is allowed.",
|
||||
error:
|
||||
"Visitor mode is enabled. Only disabling visitor mode or updating CloudFlare settings is allowed.",
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -7,10 +7,11 @@ import { useCloudflareStatus } from '../../hooks/useCloudflareStatus';
|
||||
interface CloudflareSettingsProps {
|
||||
enabled?: boolean;
|
||||
token?: string;
|
||||
visitorMode?: boolean;
|
||||
onChange: (field: string, value: string | number | boolean) => void;
|
||||
}
|
||||
|
||||
const CloudflareSettings: React.FC<CloudflareSettingsProps> = ({ enabled, token, onChange }) => {
|
||||
const CloudflareSettings: React.FC<CloudflareSettingsProps> = ({ enabled, token, visitorMode, onChange }) => {
|
||||
const { t } = useLanguage();
|
||||
const { showSnackbar } = useSnackbar();
|
||||
const [showCopied, setShowCopied] = useState(false);
|
||||
@@ -64,6 +65,7 @@ const CloudflareSettings: React.FC<CloudflareSettingsProps> = ({ enabled, token,
|
||||
<Switch
|
||||
checked={enabled ?? false}
|
||||
onChange={(e) => onChange('cloudflaredTunnelEnabled', e.target.checked)}
|
||||
disabled={visitorMode ?? false}
|
||||
/>
|
||||
}
|
||||
label={t('enableCloudflaredTunnel')}
|
||||
@@ -77,6 +79,7 @@ const CloudflareSettings: React.FC<CloudflareSettingsProps> = ({ enabled, token,
|
||||
value={token || ''}
|
||||
onChange={(e) => onChange('cloudflaredToken', e.target.value)}
|
||||
margin="normal"
|
||||
disabled={visitorMode ?? false}
|
||||
helperText={t('cloudflaredTokenHelper') || "Paste your tunnel token here, or leave empty to use a random Quick Tunnel."}
|
||||
/>
|
||||
)}
|
||||
|
||||
@@ -496,6 +496,7 @@ const SettingsPage: React.FC = () => {
|
||||
<CloudflareSettings
|
||||
enabled={settings.cloudflaredTunnelEnabled}
|
||||
token={settings.cloudflaredToken}
|
||||
visitorMode={visitorMode}
|
||||
onChange={(field, value) => handleChange(field as keyof Settings, value)}
|
||||
/>
|
||||
</Grid>
|
||||
|
||||
Reference in New Issue
Block a user