mirror of
https://github.com/lordmathis/lemma.git
synced 2025-11-05 23:44:22 +00:00
Add URL decoding for workspace and file paths in handlers
This commit is contained in:
@@ -3,6 +3,7 @@ package context
|
|||||||
import (
|
import (
|
||||||
"lemma/internal/db"
|
"lemma/internal/db"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
"net/url"
|
||||||
|
|
||||||
"github.com/go-chi/chi/v5"
|
"github.com/go-chi/chi/v5"
|
||||||
)
|
)
|
||||||
@@ -42,12 +43,25 @@ func WithWorkspaceContextMiddleware(db db.WorkspaceReader) func(http.Handler) ht
|
|||||||
}
|
}
|
||||||
|
|
||||||
workspaceName := chi.URLParam(r, "workspaceName")
|
workspaceName := chi.URLParam(r, "workspaceName")
|
||||||
workspace, err := db.GetWorkspaceByName(ctx.UserID, workspaceName)
|
// URL-decode the workspace name
|
||||||
|
decodedWorkspaceName, err := url.PathUnescape(workspaceName)
|
||||||
|
if err != nil {
|
||||||
|
log.Error("failed to decode workspace name",
|
||||||
|
"error", err,
|
||||||
|
"userID", ctx.UserID,
|
||||||
|
"workspace", workspaceName,
|
||||||
|
"path", r.URL.Path)
|
||||||
|
http.Error(w, "Invalid workspace name", http.StatusBadRequest)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
workspace, err := db.GetWorkspaceByName(ctx.UserID, decodedWorkspaceName)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error("failed to get workspace",
|
log.Error("failed to get workspace",
|
||||||
"error", err,
|
"error", err,
|
||||||
"userID", ctx.UserID,
|
"userID", ctx.UserID,
|
||||||
"workspace", workspaceName,
|
"workspace", decodedWorkspaceName,
|
||||||
|
"encodedWorkspace", workspaceName,
|
||||||
"path", r.URL.Path)
|
"path", r.URL.Path)
|
||||||
http.Error(w, "Failed to get workspace", http.StatusNotFound)
|
http.Error(w, "Failed to get workspace", http.StatusNotFound)
|
||||||
return
|
return
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import (
|
|||||||
"encoding/json"
|
"encoding/json"
|
||||||
"io"
|
"io"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
"net/url"
|
||||||
"os"
|
"os"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
@@ -110,7 +111,18 @@ func (h *Handler) LookupFileByName() http.HandlerFunc {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
filePaths, err := h.Storage.FindFileByName(ctx.UserID, ctx.Workspace.ID, filename)
|
// URL-decode the filename
|
||||||
|
decodedFilename, err := url.PathUnescape(filename)
|
||||||
|
if err != nil {
|
||||||
|
log.Error("failed to decode filename",
|
||||||
|
"filename", filename,
|
||||||
|
"error", err.Error(),
|
||||||
|
)
|
||||||
|
respondError(w, "Invalid filename", http.StatusBadRequest)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
filePaths, err := h.Storage.FindFileByName(ctx.UserID, ctx.Workspace.ID, decodedFilename)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if !os.IsNotExist(err) {
|
if !os.IsNotExist(err) {
|
||||||
log.Error("failed to lookup file",
|
log.Error("failed to lookup file",
|
||||||
@@ -159,11 +171,22 @@ func (h *Handler) GetFileContent() http.HandlerFunc {
|
|||||||
)
|
)
|
||||||
|
|
||||||
filePath := chi.URLParam(r, "*")
|
filePath := chi.URLParam(r, "*")
|
||||||
content, err := h.Storage.GetFileContent(ctx.UserID, ctx.Workspace.ID, filePath)
|
// URL-decode the file path
|
||||||
|
decodedPath, err := url.PathUnescape(filePath)
|
||||||
|
if err != nil {
|
||||||
|
log.Error("failed to decode file path",
|
||||||
|
"filePath", filePath,
|
||||||
|
"error", err.Error(),
|
||||||
|
)
|
||||||
|
respondError(w, "Invalid file path", http.StatusBadRequest)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
content, err := h.Storage.GetFileContent(ctx.UserID, ctx.Workspace.ID, decodedPath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if storage.IsPathValidationError(err) {
|
if storage.IsPathValidationError(err) {
|
||||||
log.Error("invalid file path attempted",
|
log.Error("invalid file path attempted",
|
||||||
"filePath", filePath,
|
"filePath", decodedPath,
|
||||||
"error", err.Error(),
|
"error", err.Error(),
|
||||||
)
|
)
|
||||||
respondError(w, "Invalid file path", http.StatusBadRequest)
|
respondError(w, "Invalid file path", http.StatusBadRequest)
|
||||||
@@ -172,7 +195,7 @@ func (h *Handler) GetFileContent() http.HandlerFunc {
|
|||||||
|
|
||||||
if os.IsNotExist(err) {
|
if os.IsNotExist(err) {
|
||||||
log.Debug("file not found",
|
log.Debug("file not found",
|
||||||
"filePath", filePath,
|
"filePath", decodedPath,
|
||||||
)
|
)
|
||||||
respondError(w, "File not found", http.StatusNotFound)
|
respondError(w, "File not found", http.StatusNotFound)
|
||||||
return
|
return
|
||||||
@@ -228,21 +251,32 @@ func (h *Handler) SaveFile() http.HandlerFunc {
|
|||||||
)
|
)
|
||||||
|
|
||||||
filePath := chi.URLParam(r, "*")
|
filePath := chi.URLParam(r, "*")
|
||||||
|
// URL-decode the file path
|
||||||
|
decodedPath, err := url.PathUnescape(filePath)
|
||||||
|
if err != nil {
|
||||||
|
log.Error("failed to decode file path",
|
||||||
|
"filePath", filePath,
|
||||||
|
"error", err.Error(),
|
||||||
|
)
|
||||||
|
respondError(w, "Invalid file path", http.StatusBadRequest)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
content, err := io.ReadAll(r.Body)
|
content, err := io.ReadAll(r.Body)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error("failed to read request body",
|
log.Error("failed to read request body",
|
||||||
"filePath", filePath,
|
"filePath", decodedPath,
|
||||||
"error", err.Error(),
|
"error", err.Error(),
|
||||||
)
|
)
|
||||||
respondError(w, "Failed to read request body", http.StatusBadRequest)
|
respondError(w, "Failed to read request body", http.StatusBadRequest)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
err = h.Storage.SaveFile(ctx.UserID, ctx.Workspace.ID, filePath, content)
|
err = h.Storage.SaveFile(ctx.UserID, ctx.Workspace.ID, decodedPath, content)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if storage.IsPathValidationError(err) {
|
if storage.IsPathValidationError(err) {
|
||||||
log.Error("invalid file path attempted",
|
log.Error("invalid file path attempted",
|
||||||
"filePath", filePath,
|
"filePath", decodedPath,
|
||||||
"error", err.Error(),
|
"error", err.Error(),
|
||||||
)
|
)
|
||||||
respondError(w, "Invalid file path", http.StatusBadRequest)
|
respondError(w, "Invalid file path", http.StatusBadRequest)
|
||||||
@@ -295,11 +329,22 @@ func (h *Handler) DeleteFile() http.HandlerFunc {
|
|||||||
)
|
)
|
||||||
|
|
||||||
filePath := chi.URLParam(r, "*")
|
filePath := chi.URLParam(r, "*")
|
||||||
err := h.Storage.DeleteFile(ctx.UserID, ctx.Workspace.ID, filePath)
|
// URL-decode the file path
|
||||||
|
decodedPath, err := url.PathUnescape(filePath)
|
||||||
|
if err != nil {
|
||||||
|
log.Error("failed to decode file path",
|
||||||
|
"filePath", filePath,
|
||||||
|
"error", err.Error(),
|
||||||
|
)
|
||||||
|
respondError(w, "Invalid file path", http.StatusBadRequest)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
err = h.Storage.DeleteFile(ctx.UserID, ctx.Workspace.ID, decodedPath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if storage.IsPathValidationError(err) {
|
if storage.IsPathValidationError(err) {
|
||||||
log.Error("invalid file path attempted",
|
log.Error("invalid file path attempted",
|
||||||
"filePath", filePath,
|
"filePath", decodedPath,
|
||||||
"error", err.Error(),
|
"error", err.Error(),
|
||||||
)
|
)
|
||||||
respondError(w, "Invalid file path", http.StatusBadRequest)
|
respondError(w, "Invalid file path", http.StatusBadRequest)
|
||||||
@@ -308,7 +353,7 @@ func (h *Handler) DeleteFile() http.HandlerFunc {
|
|||||||
|
|
||||||
if os.IsNotExist(err) {
|
if os.IsNotExist(err) {
|
||||||
log.Debug("file not found",
|
log.Debug("file not found",
|
||||||
"filePath", filePath,
|
"filePath", decodedPath,
|
||||||
)
|
)
|
||||||
respondError(w, "File not found", http.StatusNotFound)
|
respondError(w, "File not found", http.StatusNotFound)
|
||||||
return
|
return
|
||||||
@@ -413,7 +458,19 @@ func (h *Handler) UpdateLastOpenedFile() http.HandlerFunc {
|
|||||||
|
|
||||||
// Validate the file path in the workspace
|
// Validate the file path in the workspace
|
||||||
if requestBody.FilePath != "" {
|
if requestBody.FilePath != "" {
|
||||||
_, err := h.Storage.GetFileContent(ctx.UserID, ctx.Workspace.ID, requestBody.FilePath)
|
// URL-decode the file path
|
||||||
|
decodedPath, err := url.PathUnescape(requestBody.FilePath)
|
||||||
|
if err != nil {
|
||||||
|
log.Error("failed to decode file path",
|
||||||
|
"filePath", requestBody.FilePath,
|
||||||
|
"error", err.Error(),
|
||||||
|
)
|
||||||
|
respondError(w, "Invalid file path", http.StatusBadRequest)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
requestBody.FilePath = decodedPath
|
||||||
|
|
||||||
|
_, err = h.Storage.GetFileContent(ctx.UserID, ctx.Workspace.ID, requestBody.FilePath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if storage.IsPathValidationError(err) {
|
if storage.IsPathValidationError(err) {
|
||||||
log.Error("invalid file path attempted",
|
log.Error("invalid file path attempted",
|
||||||
|
|||||||
@@ -173,19 +173,19 @@ func (h *Handler) GetWorkspace() http.HandlerFunc {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func gitSettingsChanged(new, old *models.Workspace) bool {
|
func gitSettingsChanged(newWorkspace, old *models.Workspace) bool {
|
||||||
// Check if Git was enabled/disabled
|
// Check if Git was enabled/disabled
|
||||||
if new.GitEnabled != old.GitEnabled {
|
if newWorkspace.GitEnabled != old.GitEnabled {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
// If Git is enabled, check if any settings changed
|
// If Git is enabled, check if any settings changed
|
||||||
if new.GitEnabled {
|
if newWorkspace.GitEnabled {
|
||||||
return new.GitURL != old.GitURL ||
|
return newWorkspace.GitURL != old.GitURL ||
|
||||||
new.GitUser != old.GitUser ||
|
newWorkspace.GitUser != old.GitUser ||
|
||||||
new.GitToken != old.GitToken ||
|
newWorkspace.GitToken != old.GitToken ||
|
||||||
new.GitCommitName != old.GitCommitName ||
|
newWorkspace.GitCommitName != old.GitCommitName ||
|
||||||
new.GitCommitEmail != old.GitCommitEmail
|
newWorkspace.GitCommitEmail != old.GitCommitEmail
|
||||||
}
|
}
|
||||||
|
|
||||||
return false
|
return false
|
||||||
|
|||||||
Reference in New Issue
Block a user