Add public OnlyOffice download endpoint to bypass auth middleware 401 issue
All checks were successful
Automated Container Build / build-and-push (push) Successful in 1m20s

This commit is contained in:
Elijah 2026-05-24 12:48:03 -07:00
parent a0353445d9
commit fd991a1d4b
3 changed files with 39 additions and 1 deletions

View file

@ -78,6 +78,39 @@ func (h *OnlyOfficeHandler) Callback(c *fiber.Ctx) error {
return c.JSON(fiber.Map{"error": 0})
}
// DownloadForEditor serves a file to the OnlyOffice Document Server.
// This is a public endpoint that validates the download token manually,
// bypassing the auth middleware (which can fail when requests are proxied
// through Next.js rewrites).
func (h *OnlyOfficeHandler) DownloadForEditor(c *fiber.Ctx) error {
path := c.Query("path")
token := c.Query("token")
if path == "" {
return c.Status(400).JSON(fiber.Map{"error": "path required"})
}
// Validate the download token
if err := middleware.ValidateDownloadToken(token, h.Config.JWTSecret, ""); err != nil {
return c.Status(401).JSON(fiber.Map{"error": "unauthorized"})
}
// Jail the path to the storage directory
cleaned := filepath.Clean(path)
if filepath.IsAbs(cleaned) || cleaned == ".." || len(cleaned) > 2 && cleaned[:3] == ".." + string(filepath.Separator) {
return c.Status(403).JSON(fiber.Map{"error": "invalid path"})
}
fullPath := filepath.Join(h.Config.StorageDir, cleaned)
info, err := os.Stat(fullPath)
if err != nil || info.IsDir() {
return c.Status(404).JSON(fiber.Map{"error": "file not found"})
}
return c.SendFile(fullPath)
}
// CreateBlank creates an empty document for Docs or Slides mode
func (h *OnlyOfficeHandler) CreateBlank(c *fiber.Ctx) error {
req := new(struct {

View file

@ -138,6 +138,9 @@ func main() {
// OnlyOffice callback (public but validates query token)
public.Post("/onlyoffice/callback", onlyOfficeHandler.Callback)
// OnlyOffice file download (public but validates query token — bypasses auth middleware
// since requests come from the Document Server via Next.js proxy which can drop query params)
public.Get("/onlyoffice/download", onlyOfficeHandler.DownloadForEditor)
// Auth routes (with brute force protection)
auth := app.Group("/api/auth")

View file

@ -41,9 +41,11 @@ export default function OnlyOfficeEditor({ file, type, onClose }: OnlyOfficeEdit
// It's on the default bridge network and can reach the Unraid host IP, but NOT
// the public domain (hairpin NAT) or Docker DNS names (different network).
// Port 5827 is the frontend container (which proxies /api/* to the backend).
// We use dedicated public endpoints that validate tokens manually, bypassing
// the auth middleware which fails when requests come through the Next.js proxy.
const INTERNAL_URL = 'http://192.168.50.81:5827/api';
const fileUrl = `${INTERNAL_URL}/files/download/${encodeURIComponent(file.path)}?token=${downloadToken}`;
const fileUrl = `${INTERNAL_URL}/public/onlyoffice/download?path=${encodeURIComponent(file.path)}&token=${downloadToken}`;
const callbackUrl = `${INTERNAL_URL}/public/onlyoffice/callback?path=${encodeURIComponent(file.path)}&token=${downloadToken}`;
const baseConfig: any = {