Revert last 4 commits
All checks were successful
Automated Container Build / build-and-push (push) Successful in 46s
All checks were successful
Automated Container Build / build-and-push (push) Successful in 46s
This commit is contained in:
parent
e7a649d0d4
commit
c7d39144cd
5 changed files with 14 additions and 100 deletions
|
|
@ -335,20 +335,16 @@ func (h *OnlyOfficeHandler) ListOfficeFiles(c *fiber.Ctx) error {
|
||||||
var results []OfficeFile
|
var results []OfficeFile
|
||||||
|
|
||||||
checksums := make(map[string]string)
|
checksums := make(map[string]string)
|
||||||
dbPaths := []string{}
|
rows, err := h.DB.Query("SELECT path, checksum FROM files WHERE checksum != '' AND is_trashed = 0")
|
||||||
rows, err := h.DB.Query("SELECT path, checksum FROM files WHERE checksum IS NOT NULL AND checksum != ''")
|
|
||||||
if err == nil {
|
if err == nil {
|
||||||
defer rows.Close()
|
defer rows.Close()
|
||||||
for rows.Next() {
|
for rows.Next() {
|
||||||
var p, c string
|
var p, c string
|
||||||
if rows.Scan(&p, &c) == nil {
|
if rows.Scan(&p, &c) == nil {
|
||||||
checksums[p] = c
|
checksums[p] = c
|
||||||
dbPaths = append(dbPaths, p)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
walkPaths := []string{}
|
|
||||||
|
|
||||||
filepath.Walk(h.Config.StorageDir, func(path string, info os.FileInfo, err error) error {
|
filepath.Walk(h.Config.StorageDir, func(path string, info os.FileInfo, err error) error {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
@ -366,16 +362,12 @@ func (h *OnlyOfficeHandler) ListOfficeFiles(c *fiber.Ctx) error {
|
||||||
if strings.HasSuffix(strings.ToLower(info.Name()), ext) {
|
if strings.HasSuffix(strings.ToLower(info.Name()), ext) {
|
||||||
relPath, _ := filepath.Rel(h.Config.StorageDir, path)
|
relPath, _ := filepath.Rel(h.Config.StorageDir, path)
|
||||||
relPathSlash := filepath.ToSlash(relPath)
|
relPathSlash := filepath.ToSlash(relPath)
|
||||||
|
|
||||||
chk := checksums[relPathSlash]
|
|
||||||
walkPaths = append(walkPaths, relPathSlash)
|
|
||||||
|
|
||||||
results = append(results, OfficeFile{
|
results = append(results, OfficeFile{
|
||||||
Name: info.Name(),
|
Name: info.Name(),
|
||||||
Path: relPathSlash,
|
Path: relPathSlash,
|
||||||
Size: info.Size(),
|
Size: info.Size(),
|
||||||
ModTime: info.ModTime().UTC().Format("2006-01-02T15:04:05Z"),
|
ModTime: info.ModTime().UTC().Format("2006-01-02T15:04:05Z"),
|
||||||
Checksum: chk,
|
Checksum: checksums[relPathSlash],
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
|
|
@ -388,8 +380,6 @@ func (h *OnlyOfficeHandler) ListOfficeFiles(c *fiber.Ctx) error {
|
||||||
return c.JSON(fiber.Map{
|
return c.JSON(fiber.Map{
|
||||||
"files": results,
|
"files": results,
|
||||||
"count": len(results),
|
"count": len(results),
|
||||||
"debug_db": dbPaths,
|
|
||||||
"debug_walk": walkPaths,
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -103,21 +103,9 @@ func main() {
|
||||||
c.Set("Cache-Control", "no-store, no-cache, must-revalidate")
|
c.Set("Cache-Control", "no-store, no-cache, must-revalidate")
|
||||||
return c.Next()
|
return c.Next()
|
||||||
})
|
})
|
||||||
app.Use(helmet.New(helmet.Config{
|
app.Use(helmet.New())
|
||||||
// Relax cross-origin policies to allow OnlyOffice Document Server
|
|
||||||
// iframe embedding from a different origin (e.g. office.elijahkuntz.com)
|
|
||||||
CrossOriginEmbedderPolicy: "unsafe-none",
|
|
||||||
CrossOriginResourcePolicy: "cross-origin",
|
|
||||||
}))
|
|
||||||
|
|
||||||
// Build CSP with dynamic frame-src for the OnlyOffice Document Server
|
|
||||||
onlyOfficeFrameSrc := "https://" + cfg.OnlyOfficeHost
|
|
||||||
cspHeader := fmt.Sprintf(
|
|
||||||
"default-src 'self'; script-src 'self' 'unsafe-inline' 'unsafe-eval'; style-src 'self' 'unsafe-inline'; img-src 'self' data: blob:; connect-src 'self' wss: https: http:; frame-src 'self' %s;",
|
|
||||||
onlyOfficeFrameSrc,
|
|
||||||
)
|
|
||||||
app.Use(func(c *fiber.Ctx) error {
|
app.Use(func(c *fiber.Ctx) error {
|
||||||
c.Set("Content-Security-Policy", cspHeader)
|
c.Set("Content-Security-Policy", "default-src 'self'; script-src 'self' 'unsafe-inline' 'unsafe-eval'; style-src 'self' 'unsafe-inline'; img-src 'self' data: blob:; connect-src 'self' wss: https: http:;")
|
||||||
return c.Next()
|
return c.Next()
|
||||||
})
|
})
|
||||||
allowedOrigins := os.Getenv("ALLOWED_ORIGINS")
|
allowedOrigins := os.Getenv("ALLOWED_ORIGINS")
|
||||||
|
|
|
||||||
|
|
@ -92,8 +92,6 @@ export default function OfficeHome({ type, onFileSelect, onCreateBlank, onPinCha
|
||||||
// Fetch ALL office files recursively
|
// Fetch ALL office files recursively
|
||||||
api.listOfficeFiles(fileTypeParam)
|
api.listOfficeFiles(fileTypeParam)
|
||||||
.then(data => {
|
.then(data => {
|
||||||
console.log("ListOfficeFiles Debug DB:", data.debug_db);
|
|
||||||
console.log("ListOfficeFiles Debug Walk:", data.debug_walk);
|
|
||||||
const files = (data.files || []).map((f: any) => ({
|
const files = (data.files || []).map((f: any) => ({
|
||||||
...f,
|
...f,
|
||||||
is_dir: false,
|
is_dir: false,
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
import React, { useEffect, useState, useRef, useCallback } from 'react';
|
import React, { useEffect, useState, useRef } from 'react';
|
||||||
import { DocumentEditor } from '@onlyoffice/document-editor-react';
|
import { DocumentEditor } from '@onlyoffice/document-editor-react';
|
||||||
import { Sun, Moon, Loader2, ArrowLeft, RefreshCw, Download, ShieldAlert, X } from 'lucide-react';
|
import { Sun, Moon, Loader2, ArrowLeft, RefreshCw, Download } from 'lucide-react';
|
||||||
import api from '@/lib/api';
|
import api from '@/lib/api';
|
||||||
import { FileItem } from '@/types/files';
|
import { FileItem } from '@/types/files';
|
||||||
|
|
||||||
|
|
@ -18,10 +18,6 @@ export default function OnlyOfficeEditor({ file, type, onClose, onRename, theme,
|
||||||
const [loadError, setLoadError] = useState<string | null>(null);
|
const [loadError, setLoadError] = useState<string | null>(null);
|
||||||
const [config, setConfig] = useState<any>(null);
|
const [config, setConfig] = useState<any>(null);
|
||||||
const [isRenaming, setIsRenaming] = useState(false);
|
const [isRenaming, setIsRenaming] = useState(false);
|
||||||
const [adblockWarning, setAdblockWarning] = useState(false);
|
|
||||||
const [documentReady, setDocumentReady] = useState(false);
|
|
||||||
const documentReadyRef = useRef(false);
|
|
||||||
const loadTimeoutRef = useRef<NodeJS.Timeout | null>(null);
|
|
||||||
|
|
||||||
const extMatch = file.name.match(/\.[^.]+$/);
|
const extMatch = file.name.match(/\.[^.]+$/);
|
||||||
const ext = extMatch ? extMatch[0] : '';
|
const ext = extMatch ? extMatch[0] : '';
|
||||||
|
|
@ -134,39 +130,9 @@ export default function OnlyOfficeEditor({ file, type, onClose, onRename, theme,
|
||||||
|
|
||||||
const docServerUrl = process.env.NEXT_PUBLIC_ONLYOFFICE_URL || 'https://office.elijahkuntz.com/';
|
const docServerUrl = process.env.NEXT_PUBLIC_ONLYOFFICE_URL || 'https://office.elijahkuntz.com/';
|
||||||
|
|
||||||
// Proactively detect if an adblocker is blocking OnlyOffice resources
|
const onDocumentReady = function (event: any) {
|
||||||
useEffect(() => {
|
|
||||||
if (!config) return;
|
|
||||||
|
|
||||||
// Test fetch for a resource commonly blocked by adblockers (Brave Shields, uBlock, etc.)
|
|
||||||
const testUrl = `${docServerUrl}web-apps/apps/common/Analytics.js`;
|
|
||||||
fetch(testUrl, { method: 'HEAD', mode: 'no-cors' })
|
|
||||||
.then(() => {
|
|
||||||
// mode: 'no-cors' always resolves — check with a timeout fallback instead
|
|
||||||
})
|
|
||||||
.catch(() => {
|
|
||||||
setAdblockWarning(true);
|
|
||||||
});
|
|
||||||
|
|
||||||
// Fallback: if onDocumentReady hasn't fired in 8s, show the warning
|
|
||||||
loadTimeoutRef.current = setTimeout(() => {
|
|
||||||
if (!documentReadyRef.current) {
|
|
||||||
setAdblockWarning(true);
|
|
||||||
}
|
|
||||||
}, 8000);
|
|
||||||
|
|
||||||
return () => {
|
|
||||||
if (loadTimeoutRef.current) clearTimeout(loadTimeoutRef.current);
|
|
||||||
};
|
|
||||||
}, [config, docServerUrl]);
|
|
||||||
|
|
||||||
const onDocumentReady = useCallback(function (event: any) {
|
|
||||||
console.log("Document is loaded");
|
console.log("Document is loaded");
|
||||||
documentReadyRef.current = true;
|
};
|
||||||
setDocumentReady(true);
|
|
||||||
setAdblockWarning(false);
|
|
||||||
if (loadTimeoutRef.current) clearTimeout(loadTimeoutRef.current);
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
const onLoadComponentError = function (errorCode: number, errorDescription: string) {
|
const onLoadComponentError = function (errorCode: number, errorDescription: string) {
|
||||||
setLoadError(`${errorCode}: ${errorDescription}`);
|
setLoadError(`${errorCode}: ${errorDescription}`);
|
||||||
|
|
@ -226,44 +192,16 @@ export default function OnlyOfficeEditor({ file, type, onClose, onRename, theme,
|
||||||
</div>
|
</div>
|
||||||
<div className="flex-1 relative">
|
<div className="flex-1 relative">
|
||||||
{loadError ? (
|
{loadError ? (
|
||||||
<div className="absolute inset-0 flex items-center justify-center bg-gray-50 dark:bg-[#1a1a1a] p-8 text-center flex-col">
|
<div className="absolute inset-0 flex items-center justify-center bg-gray-50 text-red-600 p-8 text-center flex-col">
|
||||||
<svg className="w-12 h-12 mb-4 text-red-500" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
<svg className="w-12 h-12 mb-4 text-red-500" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M12 8v4m0 4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z" />
|
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M12 8v4m0 4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z" />
|
||||||
</svg>
|
</svg>
|
||||||
<h3 className="font-bold text-lg mb-2 text-red-600 dark:text-red-400">Failed to load OnlyOffice Editor</h3>
|
<h3 className="font-bold text-lg mb-2">Failed to load OnlyOffice Editor</h3>
|
||||||
<p className="text-sm text-red-600 dark:text-red-400">{loadError}</p>
|
<p className="text-sm">{loadError}</p>
|
||||||
<p className="mt-4 text-xs text-gray-500 dark:text-gray-400">Check if your OnlyOffice server is running and accessible at the configured URL.</p>
|
<p className="mt-4 text-xs text-gray-500">Check if your OnlyOffice server is running and accessible at the configured URL.</p>
|
||||||
</div>
|
</div>
|
||||||
) : (
|
) : (
|
||||||
<div className="absolute inset-0">
|
<div className="absolute inset-0">
|
||||||
{/* Adblocker / Brave Shields warning banner */}
|
|
||||||
{adblockWarning && !documentReady && (
|
|
||||||
<div className="absolute top-0 left-0 right-0 z-50 flex items-start gap-3 px-5 py-4 bg-amber-50 dark:bg-amber-950/80 border-b border-amber-200 dark:border-amber-800 shadow-lg animate-in slide-in-from-top">
|
|
||||||
<ShieldAlert className="w-6 h-6 text-amber-600 dark:text-amber-400 flex-shrink-0 mt-0.5" />
|
|
||||||
<div className="flex-1 min-w-0">
|
|
||||||
<h4 className="font-semibold text-sm text-amber-800 dark:text-amber-200">Ad Blocker Detected</h4>
|
|
||||||
<p className="text-xs text-amber-700 dark:text-amber-300 mt-1 leading-relaxed">
|
|
||||||
Your ad blocker or browser shield is blocking resources required by the document editor.
|
|
||||||
The editor may not load or function correctly.
|
|
||||||
</p>
|
|
||||||
<div className="mt-2 text-xs text-amber-600 dark:text-amber-400 space-y-1">
|
|
||||||
<p className="font-medium">To fix this:</p>
|
|
||||||
<ul className="list-disc list-inside space-y-0.5 ml-1">
|
|
||||||
<li><strong>Brave:</strong> Click the Shields icon (lion) in the address bar → set Shields to <em>Down</em> for this site</li>
|
|
||||||
<li><strong>uBlock / AdBlock:</strong> Click the extension icon → disable for this site</li>
|
|
||||||
</ul>
|
|
||||||
<p className="mt-1.5">Then refresh the page.</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<button
|
|
||||||
onClick={() => setAdblockWarning(false)}
|
|
||||||
className="p-1 rounded-md hover:bg-amber-200/50 dark:hover:bg-amber-800/50 transition-colors flex-shrink-0"
|
|
||||||
title="Dismiss"
|
|
||||||
>
|
|
||||||
<X className="w-4 h-4 text-amber-600 dark:text-amber-400" />
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
<DocumentEditor
|
<DocumentEditor
|
||||||
id="docxEditor"
|
id="docxEditor"
|
||||||
documentServerUrl={docServerUrl}
|
documentServerUrl={docServerUrl}
|
||||||
|
|
|
||||||
|
|
@ -20,7 +20,7 @@ export default function ThumbnailImage({ checksum, fallbackIcon, downloadToken,
|
||||||
}, [checksum]);
|
}, [checksum]);
|
||||||
|
|
||||||
const docStyle = docType === 'docs'
|
const docStyle = docType === 'docs'
|
||||||
? `h-[85%] max-w-[85%] ${showFallback ? 'aspect-[1/1.4]' : 'aspect-auto'} bg-white border border-gray-300 dark:border-gray-600 shadow-md`
|
? 'h-[85%] max-w-[85%] aspect-[1/1.4] bg-white border border-gray-300 dark:border-gray-600 shadow-md'
|
||||||
: docType === 'slides'
|
: docType === 'slides'
|
||||||
? 'w-[85%] max-h-[85%] aspect-[16/9] bg-white border border-gray-300 dark:border-gray-600 shadow-md'
|
? 'w-[85%] max-h-[85%] aspect-[16/9] bg-white border border-gray-300 dark:border-gray-600 shadow-md'
|
||||||
: docType === 'sheets'
|
: docType === 'sheets'
|
||||||
|
|
@ -32,7 +32,7 @@ export default function ThumbnailImage({ checksum, fallbackIcon, downloadToken,
|
||||||
key={key}
|
key={key}
|
||||||
src={downloadToken ? `${api.getThumbnailUrl(checksum, downloadToken)}${errorCount > 0 ? `&t=${key}` : ''}` : ''}
|
src={downloadToken ? `${api.getThumbnailUrl(checksum, downloadToken)}${errorCount > 0 ? `&t=${key}` : ''}` : ''}
|
||||||
alt=""
|
alt=""
|
||||||
className={`object-contain ${docType ? 'w-full h-full mix-blend-multiply' : 'w-full h-full'}`}
|
className={`object-contain ${docType ? 'w-full h-full object-cover mix-blend-multiply' : 'w-full h-full'}`}
|
||||||
style={{ display: showFallback ? 'none' : 'block' }}
|
style={{ display: showFallback ? 'none' : 'block' }}
|
||||||
onError={(e) => {
|
onError={(e) => {
|
||||||
if (errorCount < 20) {
|
if (errorCount < 20) {
|
||||||
|
|
|
||||||
Reference in a new issue