Compare commits
5 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
da14d204a6 | ||
|
|
2a87002e1f | ||
|
|
4b83facc97 | ||
|
|
3e473d57b4 | ||
|
|
f2ce43f18f |
21
CHANGELOG.md
21
CHANGELOG.md
@@ -1,5 +1,26 @@
|
|||||||
# Changelog
|
# Changelog
|
||||||
|
|
||||||
|
## Changes 11/30/2025 (v2.2.4)
|
||||||
|
|
||||||
|
release(v2.2.4): fix(admin): ONLYOFFICE JWT save crash and respect replace/locked flags
|
||||||
|
|
||||||
|
- Prevented a JS crash when the ONLYOFFICE JWT field isn’t present by always initializing payload.onlyoffice before touching jwtSecret.
|
||||||
|
- Tightened ONLYOFFICE JWT handling so the secret is only sent when config isn’t locked by PHP and the admin explicitly chooses Replace (or is setting it for the first time), instead of always pushing whatever is in the field.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Changes 11/29/2025 (v2.2.3)
|
||||||
|
|
||||||
|
fix(preview): harden SVG handling and normalize mime type
|
||||||
|
release(v2.2.3): round gallery card corners in file grid
|
||||||
|
|
||||||
|
- Stop treating SVGs as inline-previewable images in file list and preview modal
|
||||||
|
- Show a clear “SVG preview disabled for security reasons” message instead
|
||||||
|
- Keep SVGs downloadable via /api/file/download.php with proper image/svg+xml MIME
|
||||||
|
- Add i18n key for svg_preview_disabled
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
## Changes 11/29/2025 (v2.2.2)
|
## Changes 11/29/2025 (v2.2.2)
|
||||||
|
|
||||||
release(v2.2.2): feat(folders): show inline folder stats & dates
|
release(v2.2.2): feat(folders): show inline folder stats & dates
|
||||||
|
|||||||
@@ -1942,7 +1942,7 @@ function handleSave() {
|
|||||||
oidc: {
|
oidc: {
|
||||||
providerUrl: document.getElementById("oidcProviderUrl").value.trim(),
|
providerUrl: document.getElementById("oidcProviderUrl").value.trim(),
|
||||||
redirectUri: document.getElementById("oidcRedirectUri").value.trim(),
|
redirectUri: document.getElementById("oidcRedirectUri").value.trim(),
|
||||||
// clientId/clientSecret: only include when replacing
|
// clientId/clientSecret added conditionally below
|
||||||
},
|
},
|
||||||
globalOtpauthUrl: document.getElementById("globalOtpauthUrl").value.trim(),
|
globalOtpauthUrl: document.getElementById("globalOtpauthUrl").value.trim(),
|
||||||
branding: {
|
branding: {
|
||||||
@@ -1952,13 +1952,15 @@ function handleSave() {
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// --- OIDC extras (unchanged) ---
|
||||||
const idEl = document.getElementById("oidcClientId");
|
const idEl = document.getElementById("oidcClientId");
|
||||||
const scEl = document.getElementById("oidcClientSecret");
|
const scEl = document.getElementById("oidcClientSecret");
|
||||||
|
|
||||||
const idVal = idEl?.value.trim() || '';
|
const idVal = idEl?.value.trim() || '';
|
||||||
const secVal = scEl?.value.trim() || '';
|
const secVal = scEl?.value.trim() || '';
|
||||||
const idFirstTime = idEl && !idEl.hasAttribute('data-replace'); // no saved value yet
|
const idFirstTime = idEl && !idEl.hasAttribute('data-replace');
|
||||||
const secFirstTime = scEl && !scEl.hasAttribute('data-replace'); // no saved value yet
|
const secFirstTime = scEl && !scEl.hasAttribute('data-replace');
|
||||||
|
|
||||||
if ((idEl?.dataset.replace === '1' || idFirstTime) && idVal !== '') {
|
if ((idEl?.dataset.replace === '1' || idFirstTime) && idVal !== '') {
|
||||||
payload.oidc.clientId = idVal;
|
payload.oidc.clientId = idVal;
|
||||||
}
|
}
|
||||||
@@ -1966,26 +1968,26 @@ function handleSave() {
|
|||||||
payload.oidc.clientSecret = secVal;
|
payload.oidc.clientSecret = secVal;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ---- ONLYOFFICE payload ----
|
||||||
const ooSecretEl = document.getElementById("ooJwtSecret");
|
const ooSecretEl = document.getElementById("ooJwtSecret");
|
||||||
|
|
||||||
|
|
||||||
if (ooSecretEl?.dataset.replace === '1' && ooSecretEl.value.trim() !== '') {
|
|
||||||
payload.onlyoffice.jwtSecret = ooSecretEl.value.trim();
|
|
||||||
}
|
|
||||||
|
|
||||||
// ---- ONLYOFFICE payload ----
|
|
||||||
payload.onlyoffice = {
|
payload.onlyoffice = {
|
||||||
enabled: document.getElementById("ooEnabled").checked,
|
enabled: document.getElementById("ooEnabled").checked,
|
||||||
docsOrigin: document.getElementById("ooDocsOrigin").value.trim()
|
docsOrigin: document.getElementById("ooDocsOrigin").value.trim()
|
||||||
};
|
};
|
||||||
|
|
||||||
if (!window.__OO_LOCKED) {
|
// Only send JWT secret if NOT locked by PHP and user chose Replace / first-time set
|
||||||
const ooSecretVal = (document.getElementById("ooJwtSecret")?.value || "").trim();
|
if (!window.__OO_LOCKED && ooSecretEl) {
|
||||||
if (ooSecretVal !== "") {
|
const val = ooSecretEl.value.trim();
|
||||||
payload.onlyoffice.jwtSecret = ooSecretVal;
|
const hasSaved = !!window.__HAS_OO_SECRET; // set in openAdminPanel
|
||||||
|
const shouldReplace = ooSecretEl.dataset.replace === '1' || !hasSaved;
|
||||||
|
|
||||||
|
if (shouldReplace && val !== "") {
|
||||||
|
payload.onlyoffice.jwtSecret = val;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// --- save call (unchanged) ---
|
||||||
fetch('/api/admin/updateConfig.php', {
|
fetch('/api/admin/updateConfig.php', {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
credentials: 'include',
|
credentials: 'include',
|
||||||
|
|||||||
@@ -179,9 +179,22 @@ export function buildFileTableRow(file, folderPath) {
|
|||||||
const safeUploader = escapeHTML(file.uploader || "Unknown");
|
const safeUploader = escapeHTML(file.uploader || "Unknown");
|
||||||
|
|
||||||
let previewButton = "";
|
let previewButton = "";
|
||||||
if (/\.(jpg|jpeg|png|gif|bmp|webp|svg|ico|tif|tiff|eps|heic|pdf|mp4|webm|mov|mp3|wav|m4a|ogg|flac|aac|wma|opus|mkv|ogv)$/i.test(file.name)) {
|
|
||||||
|
const isSvg = /\.svg$/i.test(file.name);
|
||||||
|
|
||||||
|
// IMPORTANT: do NOT treat SVG as previewable
|
||||||
|
if (
|
||||||
|
!isSvg &&
|
||||||
|
/\.(jpg|jpeg|png|gif|bmp|webp|ico|tif|tiff|eps|heic|pdf|mp4|webm|mov|mp3|wav|m4a|ogg|flac|aac|wma|opus|mkv|ogv)$/i
|
||||||
|
.test(file.name)
|
||||||
|
) {
|
||||||
let previewIcon = "";
|
let previewIcon = "";
|
||||||
if (/\.(jpg|jpeg|png|gif|bmp|webp|svg|ico|tif|tiff|eps|heic)$/i.test(file.name)) {
|
|
||||||
|
// images (SVG explicitly excluded)
|
||||||
|
if (
|
||||||
|
/\.(jpg|jpeg|png|gif|bmp|webp|ico|tif|tiff|eps|heic)$/i
|
||||||
|
.test(file.name)
|
||||||
|
) {
|
||||||
previewIcon = `<i class="material-icons">image</i>`;
|
previewIcon = `<i class="material-icons">image</i>`;
|
||||||
} else if (/\.(mp4|mkv|webm|mov|ogv)$/i.test(file.name)) {
|
} else if (/\.(mp4|mkv|webm|mov|ogv)$/i.test(file.name)) {
|
||||||
previewIcon = `<i class="material-icons">videocam</i>`;
|
previewIcon = `<i class="material-icons">videocam</i>`;
|
||||||
@@ -190,7 +203,9 @@ export function buildFileTableRow(file, folderPath) {
|
|||||||
} else if (/\.(mp3|wav|m4a|ogg|flac|aac|wma|opus)$/i.test(file.name)) {
|
} else if (/\.(mp3|wav|m4a|ogg|flac|aac|wma|opus)$/i.test(file.name)) {
|
||||||
previewIcon = `<i class="material-icons">audiotrack</i>`;
|
previewIcon = `<i class="material-icons">audiotrack</i>`;
|
||||||
}
|
}
|
||||||
previewButton = `<button
|
|
||||||
|
previewButton = `
|
||||||
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
class="btn btn-sm btn-info preview-btn"
|
class="btn btn-sm btn-info preview-btn"
|
||||||
data-preview-url="${folderPath + encodeURIComponent(file.name)}?t=${Date.now()}"
|
data-preview-url="${folderPath + encodeURIComponent(file.name)}?t=${Date.now()}"
|
||||||
|
|||||||
@@ -1954,7 +1954,7 @@ export function renderGalleryView(folder, container) {
|
|||||||
|
|
||||||
// thumbnail
|
// thumbnail
|
||||||
let thumbnail;
|
let thumbnail;
|
||||||
if (/\.(jpe?g|png|gif|bmp|webp|svg|ico)$/i.test(file.name)) {
|
if (/\.(jpe?g|png|gif|bmp|webp|ico)$/i.test(file.name)) {
|
||||||
const cacheKey = previewURL; // include folder & file
|
const cacheKey = previewURL; // include folder & file
|
||||||
if (window.imageCache && window.imageCache[cacheKey]) {
|
if (window.imageCache && window.imageCache[cacheKey]) {
|
||||||
thumbnail = `<img
|
thumbnail = `<img
|
||||||
@@ -1998,7 +1998,7 @@ export function renderGalleryView(folder, container) {
|
|||||||
galleryHTML += `
|
galleryHTML += `
|
||||||
<div class="gallery-card"
|
<div class="gallery-card"
|
||||||
data-file-name="${escapeHTML(file.name)}"
|
data-file-name="${escapeHTML(file.name)}"
|
||||||
style="position:relative; border:1px solid #ccc; padding:5px; text-align:center;">
|
style="position:relative; border-radius: 12px; border:1px solid #ccc; padding:5px; text-align:center;">
|
||||||
<input type="checkbox"
|
<input type="checkbox"
|
||||||
class="file-checkbox"
|
class="file-checkbox"
|
||||||
id="cb-${idSafe}"
|
id="cb-${idSafe}"
|
||||||
|
|||||||
@@ -120,7 +120,12 @@ export function openShareModal(file, folder) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* -------------------------------- Media modal viewer -------------------------------- */
|
/* -------------------------------- Media modal viewer -------------------------------- */
|
||||||
const IMG_RE = /\.(jpg|jpeg|png|gif|bmp|webp|svg|ico)$/i;
|
// Images that are safe to inline in <img> tags:
|
||||||
|
const IMG_RE = /\.(jpg|jpeg|png|gif|bmp|webp|ico)$/i;
|
||||||
|
|
||||||
|
// SVG handled separately so we *don’t* inline it
|
||||||
|
const SVG_RE = /\.svg$/i;
|
||||||
|
|
||||||
const VID_RE = /\.(mp4|mkv|webm|mov|ogv)$/i;
|
const VID_RE = /\.(mp4|mkv|webm|mov|ogv)$/i;
|
||||||
const AUD_RE = /\.(mp3|wav|m4a|ogg|flac|aac|wma|opus)$/i;
|
const AUD_RE = /\.(mp3|wav|m4a|ogg|flac|aac|wma|opus)$/i;
|
||||||
const ARCH_RE = /\.(zip|rar|7z|gz|bz2|xz|tar)$/i;
|
const ARCH_RE = /\.(zip|rar|7z|gz|bz2|xz|tar)$/i;
|
||||||
@@ -422,11 +427,19 @@ export function previewFile(fileUrl, fileName) {
|
|||||||
const folder = window.currentFolder || 'root';
|
const folder = window.currentFolder || 'root';
|
||||||
const name = fileName;
|
const name = fileName;
|
||||||
const lower = (name || '').toLowerCase();
|
const lower = (name || '').toLowerCase();
|
||||||
|
const isSvg = SVG_RE.test(lower);
|
||||||
const isImage = IMG_RE.test(lower);
|
const isImage = IMG_RE.test(lower);
|
||||||
const isVideo = VID_RE.test(lower);
|
const isVideo = VID_RE.test(lower);
|
||||||
const isAudio = AUD_RE.test(lower);
|
const isAudio = AUD_RE.test(lower);
|
||||||
|
|
||||||
setTitle(overlay, name);
|
setTitle(overlay, name);
|
||||||
|
if (isSvg) {
|
||||||
|
container.textContent =
|
||||||
|
t("svg_preview_disabled") ||
|
||||||
|
"SVG preview is disabled for security. Use Download to view this file.";
|
||||||
|
overlay.style.display = "flex";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
/* -------------------- IMAGES -------------------- */
|
/* -------------------- IMAGES -------------------- */
|
||||||
if (isImage) {
|
if (isImage) {
|
||||||
|
|||||||
@@ -342,7 +342,8 @@ const translations = {
|
|||||||
"owner": "Owner",
|
"owner": "Owner",
|
||||||
"hide_header_zoom_controls": "Hide header zoom controls",
|
"hide_header_zoom_controls": "Hide header zoom controls",
|
||||||
"preview_not_available": "Preview is not available for this file type.",
|
"preview_not_available": "Preview is not available for this file type.",
|
||||||
"storage_pro_bundle_outdated": "Please upgrade to the latest FileRise Pro bundle to use the Storage explorer."
|
"storage_pro_bundle_outdated": "Please upgrade to the latest FileRise Pro bundle to use the Storage explorer.",
|
||||||
|
"svg_preview_disabled": "SVG preview is disabled for now for security reasons."
|
||||||
},
|
},
|
||||||
es: {
|
es: {
|
||||||
"please_log_in_to_continue": "Por favor, inicie sesión para continuar.",
|
"please_log_in_to_continue": "Por favor, inicie sesión para continuar.",
|
||||||
|
|||||||
@@ -1,2 +1,2 @@
|
|||||||
// generated by CI
|
// generated by CI
|
||||||
window.APP_VERSION = 'v2.2.2';
|
window.APP_VERSION = 'v2.2.4';
|
||||||
|
|||||||
@@ -543,6 +543,12 @@ class FileModel {
|
|||||||
$mimeType = 'application/octet-stream';
|
$mimeType = 'application/octet-stream';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// OPTIONAL: normalize SVG MIME
|
||||||
|
$ext = strtolower(pathinfo($realFilePath, PATHINFO_EXTENSION));
|
||||||
|
if ($ext === 'svg') {
|
||||||
|
$mimeType = 'image/svg+xml';
|
||||||
|
}
|
||||||
|
|
||||||
return [
|
return [
|
||||||
"filePath" => $realFilePath,
|
"filePath" => $realFilePath,
|
||||||
"mimeType" => $mimeType
|
"mimeType" => $mimeType
|
||||||
|
|||||||
Reference in New Issue
Block a user