Refactor WOPI access checks to prioritize organization membership over user ownership
This commit is contained in:
@@ -259,11 +259,8 @@ func wopiCheckFileInfoHandler(w http.ResponseWriter, r *http.Request, db *databa
|
|||||||
canAccess := false
|
canAccess := false
|
||||||
var ownerID string
|
var ownerID string
|
||||||
|
|
||||||
if file.UserID != nil && *file.UserID == userID {
|
// Prefer org ownership when file belongs to an org and the user is a member
|
||||||
canAccess = true
|
if file.OrgID != nil {
|
||||||
ownerID = userID.String()
|
|
||||||
} else if file.OrgID != nil {
|
|
||||||
// Check if user is member of the org
|
|
||||||
member, err := db.GetOrgMember(r.Context(), *file.OrgID, userID)
|
member, err := db.GetOrgMember(r.Context(), *file.OrgID, userID)
|
||||||
if err == nil && member != nil {
|
if err == nil && member != nil {
|
||||||
canAccess = true
|
canAccess = true
|
||||||
@@ -271,6 +268,12 @@ func wopiCheckFileInfoHandler(w http.ResponseWriter, r *http.Request, db *databa
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Fallback to per-user file ownership
|
||||||
|
if !canAccess && file.UserID != nil && *file.UserID == userID {
|
||||||
|
canAccess = true
|
||||||
|
ownerID = userID.String()
|
||||||
|
}
|
||||||
|
|
||||||
if !canAccess {
|
if !canAccess {
|
||||||
fmt.Printf("[WOPI-REQUEST] Access denied: file=%s user=%s\n", fileID, userID.String())
|
fmt.Printf("[WOPI-REQUEST] Access denied: file=%s user=%s\n", fileID, userID.String())
|
||||||
errors.WriteError(w, errors.CodePermissionDenied, "Access denied", http.StatusForbidden)
|
errors.WriteError(w, errors.CodePermissionDenied, "Access denied", http.StatusForbidden)
|
||||||
@@ -369,19 +372,8 @@ func wopiGetFileHandler(w http.ResponseWriter, r *http.Request, db *database.DB,
|
|||||||
var webDAVClient *storage.WebDAVClient
|
var webDAVClient *storage.WebDAVClient
|
||||||
var remotePath string
|
var remotePath string
|
||||||
|
|
||||||
if file.UserID != nil && *file.UserID == userID {
|
// Prefer org storage when present and the user is a member
|
||||||
canAccess = true
|
if file.OrgID != nil {
|
||||||
// Get user's WebDAV client - use config
|
|
||||||
webDAVClient, err = getUserWebDAVClient(r.Context(), db, userID, cfg.NextcloudURL, cfg.NextcloudUser, cfg.NextcloudPass)
|
|
||||||
if err != nil {
|
|
||||||
fmt.Printf("[WOPI-STORAGE] Failed to get user WebDAV client: %v\n", err)
|
|
||||||
errors.WriteError(w, errors.CodeInternal, "Storage error", http.StatusInternalServerError)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
// User files: path is relative to user's WebDAV root
|
|
||||||
remotePath = file.Path
|
|
||||||
} else if file.OrgID != nil {
|
|
||||||
// Check if user is member of the org
|
|
||||||
member, err := db.GetOrgMember(r.Context(), *file.OrgID, userID)
|
member, err := db.GetOrgMember(r.Context(), *file.OrgID, userID)
|
||||||
if err == nil && member != nil {
|
if err == nil && member != nil {
|
||||||
canAccess = true
|
canAccess = true
|
||||||
@@ -398,6 +390,19 @@ func wopiGetFileHandler(w http.ResponseWriter, r *http.Request, db *database.DB,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Fallback to per-user files
|
||||||
|
if !canAccess && file.UserID != nil && *file.UserID == userID {
|
||||||
|
canAccess = true
|
||||||
|
webDAVClient, err = getUserWebDAVClient(r.Context(), db, userID, cfg.NextcloudURL, cfg.NextcloudUser, cfg.NextcloudPass)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Printf("[WOPI-STORAGE] Failed to get user WebDAV client: %v\n", err)
|
||||||
|
errors.WriteError(w, errors.CodeInternal, "Storage error", http.StatusInternalServerError)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// User files: path is relative to user's WebDAV root
|
||||||
|
remotePath = file.Path
|
||||||
|
}
|
||||||
|
|
||||||
if !canAccess {
|
if !canAccess {
|
||||||
fmt.Printf("[WOPI-REQUEST] GetFile - Access denied: file=%s user=%s\n", fileID, userID.String())
|
fmt.Printf("[WOPI-REQUEST] GetFile - Access denied: file=%s user=%s\n", fileID, userID.String())
|
||||||
errors.WriteError(w, errors.CodePermissionDenied, "Access denied", http.StatusForbidden)
|
errors.WriteError(w, errors.CodePermissionDenied, "Access denied", http.StatusForbidden)
|
||||||
@@ -474,17 +479,8 @@ func wopiPutFileHandler(w http.ResponseWriter, r *http.Request, db *database.DB,
|
|||||||
var webDAVClient *storage.WebDAVClient
|
var webDAVClient *storage.WebDAVClient
|
||||||
var remotePath string
|
var remotePath string
|
||||||
|
|
||||||
if file.UserID != nil && *file.UserID == userID {
|
// Prefer org storage when present and the user is a member
|
||||||
canAccess = true
|
if file.OrgID != nil {
|
||||||
webDAVClient, err = getUserWebDAVClient(r.Context(), db, userID, cfg.NextcloudURL, cfg.NextcloudUser, cfg.NextcloudPass)
|
|
||||||
if err != nil {
|
|
||||||
fmt.Printf("[WOPI-STORAGE] Failed to get user WebDAV client: %v\n", err)
|
|
||||||
errors.WriteError(w, errors.CodeInternal, "Storage error", http.StatusInternalServerError)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
// User files: path is relative to user's WebDAV root
|
|
||||||
remotePath = file.Path
|
|
||||||
} else if file.OrgID != nil {
|
|
||||||
member, err := db.GetOrgMember(r.Context(), *file.OrgID, userID)
|
member, err := db.GetOrgMember(r.Context(), *file.OrgID, userID)
|
||||||
if err == nil && member != nil {
|
if err == nil && member != nil {
|
||||||
canAccess = true
|
canAccess = true
|
||||||
@@ -501,6 +497,19 @@ func wopiPutFileHandler(w http.ResponseWriter, r *http.Request, db *database.DB,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Fallback to per-user files
|
||||||
|
if !canAccess && file.UserID != nil && *file.UserID == userID {
|
||||||
|
canAccess = true
|
||||||
|
webDAVClient, err = getUserWebDAVClient(r.Context(), db, userID, cfg.NextcloudURL, cfg.NextcloudUser, cfg.NextcloudPass)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Printf("[WOPI-STORAGE] Failed to get user WebDAV client: %v\n", err)
|
||||||
|
errors.WriteError(w, errors.CodeInternal, "Storage error", http.StatusInternalServerError)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// User files: path is relative to user's WebDAV root
|
||||||
|
remotePath = file.Path
|
||||||
|
}
|
||||||
|
|
||||||
if !canAccess {
|
if !canAccess {
|
||||||
fmt.Printf("[WOPI-REQUEST] PutFile - Access denied: file=%s user=%s\n", fileID, userID.String())
|
fmt.Printf("[WOPI-REQUEST] PutFile - Access denied: file=%s user=%s\n", fileID, userID.String())
|
||||||
errors.WriteError(w, errors.CodePermissionDenied, "Access denied", http.StatusForbidden)
|
errors.WriteError(w, errors.CodePermissionDenied, "Access denied", http.StatusForbidden)
|
||||||
|
|||||||
Reference in New Issue
Block a user