From 9b03695d6148ab9ae3befa6eaeb66867dd2d59e9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leon=20B=C3=B6sche?= Date: Sun, 11 Jan 2026 00:45:58 +0100 Subject: [PATCH] Fix Nextcloud user creation and WebDAV URL construction - Fix CreateNextcloudUser to use form-encoded POST (OCS API requirement) - Fix WebDAV URL construction to avoid double slashes - Apply fix to Upload, Download, and Delete methods --- go_cloud/internal/storage/nextcloud.go | 19 ++++++--------- go_cloud/internal/storage/webdav.go | 33 +++++++++++++++++++++----- 2 files changed, 34 insertions(+), 18 deletions(-) diff --git a/go_cloud/internal/storage/nextcloud.go b/go_cloud/internal/storage/nextcloud.go index c94600a..154aee5 100644 --- a/go_cloud/internal/storage/nextcloud.go +++ b/go_cloud/internal/storage/nextcloud.go @@ -17,24 +17,19 @@ func CreateNextcloudUser(nextcloudBaseURL, adminUser, adminPass, username, passw baseURL := strings.Split(nextcloudBaseURL, "/remote.php")[0] url := fmt.Sprintf("%s/ocs/v1.php/cloud/users", baseURL) - payload := map[string]string{ - "userid": username, - "password": password, - } + // OCS API expects form-encoded data, not JSON + formData := fmt.Sprintf("userid=%s&password=%s", + strings.ReplaceAll(username, " ", "+"), + strings.ReplaceAll(password, " ", "+")) - jsonData, err := json.Marshal(payload) - if err != nil { - return fmt.Errorf("failed to marshal payload: %w", err) - } - - req, err := http.NewRequest("POST", url, bytes.NewBuffer(jsonData)) + req, err := http.NewRequest("POST", url, bytes.NewBufferString(formData)) if err != nil { return fmt.Errorf("failed to create request: %w", err) } req.SetBasicAuth(adminUser, adminPass) req.Header.Set("OCS-APIRequest", "true") - req.Header.Set("Content-Type", "application/json") + req.Header.Set("Content-Type", "application/x-www-form-urlencoded") client := &http.Client{} resp, err := client.Do(req) @@ -50,7 +45,7 @@ func CreateNextcloudUser(nextcloudBaseURL, adminUser, adminPass, username, passw return fmt.Errorf("failed to create Nextcloud user (status %d): %s", resp.StatusCode, string(body)) } - fmt.Printf("[NEXTCLOUD] Created user account: %s\n", username) + fmt.Printf("[NEXTCLOUD] Created user account: %s with generated password\n", username) return nil } diff --git a/go_cloud/internal/storage/webdav.go b/go_cloud/internal/storage/webdav.go index 755d1aa..39801e0 100644 --- a/go_cloud/internal/storage/webdav.go +++ b/go_cloud/internal/storage/webdav.go @@ -85,9 +85,16 @@ func (c *WebDAVClient) Upload(ctx context.Context, remotePath string, r io.Reade rel := strings.TrimLeft(remotePath, "/") u := c.basePrefix if u == "/" || u == "" { - u = "/" + u = "" + } + u = strings.TrimRight(u, "/") + + var full string + if u == "" { + full = fmt.Sprintf("%s/%s", c.baseURL, url.PathEscape(rel)) + } else { + full = fmt.Sprintf("%s%s/%s", c.baseURL, u, url.PathEscape(rel)) } - full := fmt.Sprintf("%s%s/%s", c.baseURL, u, url.PathEscape(rel)) full = strings.ReplaceAll(full, "%2F", "/") fmt.Printf("[WEBDAV-UPLOAD] BaseURL: %s, BasePrefix: %s, RemotePath: %s, Full URL: %s\n", c.baseURL, c.basePrefix, remotePath, full) @@ -125,9 +132,16 @@ func (c *WebDAVClient) Download(ctx context.Context, remotePath string) (io.Read rel := strings.TrimLeft(remotePath, "/") u := c.basePrefix if u == "/" || u == "" { - u = "/" + u = "" + } + u = strings.TrimRight(u, "/") + + var full string + if u == "" { + full = fmt.Sprintf("%s/%s", c.baseURL, url.PathEscape(rel)) + } else { + full = fmt.Sprintf("%s%s/%s", c.baseURL, u, url.PathEscape(rel)) } - full := fmt.Sprintf("%s%s/%s", c.baseURL, u, url.PathEscape(rel)) full = strings.ReplaceAll(full, "%2F", "/") req, err := http.NewRequestWithContext(ctx, "GET", full, nil) @@ -161,9 +175,16 @@ func (c *WebDAVClient) Delete(ctx context.Context, remotePath string) error { rel := strings.TrimLeft(remotePath, "/") u := c.basePrefix if u == "/" || u == "" { - u = "/" + u = "" + } + u = strings.TrimRight(u, "/") + + var full string + if u == "" { + full = fmt.Sprintf("%s/%s", c.baseURL, url.PathEscape(rel)) + } else { + full = fmt.Sprintf("%s%s/%s", c.baseURL, u, url.PathEscape(rel)) } - full := fmt.Sprintf("%s%s/%s", c.baseURL, u, url.PathEscape(rel)) full = strings.ReplaceAll(full, "%2F", "/") req, err := http.NewRequestWithContext(ctx, "DELETE", full, nil)