Files
deploy-felhom-compose/controller/internal/integrations/onlyoffice_nextcloud.go
T
admin d7e5332a11 fix(integrations): fix Nextcloud-OnlyOffice callback URL and trusted_domains
StorageUrl was missing trailing slash — NC's OO connector does string
replacement of server URL (ending with /) with StorageUrl, so without
trailing slash "apps/" merges into hostname producing "nextcloudapps".

Also add "nextcloud" to NC trusted_domains so OO Document Server's
internal callbacks (Host: nextcloud) are not rejected.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-25 21:19:39 +01:00

105 lines
4.0 KiB
Go

package integrations
import (
"context"
"fmt"
"os/exec"
"strings"
"time"
)
// OnlyOfficeNextcloudHandler enables/disables OnlyOffice document editing in Nextcloud via occ.
type OnlyOfficeNextcloudHandler struct{}
func (h *OnlyOfficeNextcloudHandler) Apply(ac *ApplyContext) error {
jwtSecret := ac.ProviderEnv["JWT_SECRET"]
if jwtSecret == "" {
return fmt.Errorf("OnlyOffice JWT_SECRET nincs beállítva")
}
subdomain := ac.ProviderEnv["SUBDOMAIN"]
if subdomain == "" && ac.ProviderMeta != nil {
subdomain = ac.ProviderMeta.Subdomain
}
if subdomain == "" {
return fmt.Errorf("OnlyOffice aldomain nem ismert")
}
publicURL := fmt.Sprintf("https://%s.%s", subdomain, ac.Domain)
internalURL := "http://onlyoffice:80"
// Install and configure OnlyOffice app in Nextcloud
commands := []struct {
args []string
tolerate string // substring in output to tolerate as success
}{
{
args: []string{"docker", "exec", "-u", "www-data", "nextcloud", "php", "occ", "app:install", "onlyoffice"},
tolerate: "already installed",
},
{
args: []string{"docker", "exec", "-u", "www-data", "nextcloud", "php", "occ", "app:enable", "onlyoffice"},
},
{
args: []string{"docker", "exec", "-u", "www-data", "nextcloud", "php", "occ", "config:app:set", "onlyoffice", "DocumentServerUrl", "--value=" + publicURL},
},
{
args: []string{"docker", "exec", "-u", "www-data", "nextcloud", "php", "occ", "config:app:set", "onlyoffice", "DocumentServerInternalUrl", "--value=" + internalURL},
},
{
args: []string{"docker", "exec", "-u", "www-data", "nextcloud", "php", "occ", "config:app:set", "onlyoffice", "jwt_secret", "--value=" + jwtSecret},
},
{
// StorageUrl: tells OO Document Server where to reach Nextcloud internally for file callbacks.
// Trailing slash is critical — NC's OO connector does string replacement of the server URL
// (which ends with /) with StorageUrl. Without trailing slash, "/apps/..." merges into hostname.
args: []string{"docker", "exec", "-u", "www-data", "nextcloud", "php", "occ", "config:app:set", "onlyoffice", "StorageUrl", "--value=http://nextcloud/"},
},
{
// Add internal hostname to trusted_domains so OO Document Server callbacks
// (arriving with Host: nextcloud) are not rejected by Nextcloud.
args: []string{"docker", "exec", "-u", "www-data", "nextcloud", "php", "occ", "config:system:set", "trusted_domains", "10", "--value=nextcloud"},
},
}
for _, cmd := range commands {
ctx, cancel := context.WithTimeout(context.Background(), 60*time.Second)
c := exec.CommandContext(ctx, cmd.args[0], cmd.args[1:]...)
out, err := c.CombinedOutput()
cancel()
if err != nil {
if cmd.tolerate != "" && strings.Contains(string(out), cmd.tolerate) {
ac.Logger.Printf("[DEBUG] Nextcloud occ: tolerated — %s", strings.TrimSpace(string(out)))
continue
}
return fmt.Errorf("occ parancs sikertelen (%s): %v (kimenet: %s)", cmd.args[len(cmd.args)-1], err, strings.TrimSpace(string(out)))
}
ac.Logger.Printf("[DEBUG] Nextcloud occ %s: ok", strings.Join(cmd.args[7:], " "))
}
ac.Logger.Printf("[INFO] OnlyOffice integration applied to Nextcloud")
return nil
}
func (h *OnlyOfficeNextcloudHandler) Revoke(ac *ApplyContext) error {
ctx, cancel := context.WithTimeout(context.Background(), 60*time.Second)
defer cancel()
cmd := exec.CommandContext(ctx, "docker", "exec", "-u", "www-data", "nextcloud", "php", "occ", "app:disable", "onlyoffice")
out, err := cmd.CombinedOutput()
if err != nil {
outStr := string(out)
// Tolerate container not running or app not enabled
if strings.Contains(err.Error(), "No such container") ||
strings.Contains(outStr, "not enabled") ||
strings.Contains(outStr, "not installed") {
ac.Logger.Printf("[DEBUG] Nextcloud occ app:disable skipped — %s", strings.TrimSpace(outStr))
return nil
}
return fmt.Errorf("occ app:disable sikertelen: %v (kimenet: %s)", err, strings.TrimSpace(outStr))
}
ac.Logger.Printf("[INFO] OnlyOffice integration revoked from Nextcloud")
return nil
}