Compare commits

..

8 Commits

Author SHA1 Message Date
Henrique Dias
e735491c57
fix: ignore linting error 2025-06-26 21:12:24 +02:00
Henrique Dias
4d830f707f
fix: correctly check if command is allowed when using shell 2025-06-26 21:09:16 +02:00
Henrique Dias
f84a6db680
fix: correctly split shell 2025-06-26 21:07:45 +02:00
Henrique Dias
a430eb2e60
chore(release): 2.33.9 2025-06-26 19:45:36 +02:00
Henrique Dias
c232d41f90
fix: remove unused import 2025-06-26 19:43:20 +02:00
Henrique Dias
c1e4fd648b
docs: add warning regarding the custom commands feature 2025-06-26 19:42:13 +02:00
Henrique Dias
d5b39a14fd
fix: remove auth token from /api/command 2025-06-26 19:42:13 +02:00
Henrique Dias
e2e1e49130
fix: check exact match on command allow list 2025-06-26 19:42:12 +02:00
8 changed files with 39 additions and 42 deletions

View File

@ -2,6 +2,15 @@
All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines.
### [2.33.9](https://github.com/filebrowser/filebrowser/compare/v2.33.8...v2.33.9) (2025-06-26)
### Bug Fixes
* check exact match on command allow list ([e2e1e49](https://github.com/filebrowser/filebrowser/commit/e2e1e4913085cca8917e0f69171dc28d3c6af1b6))
* remove auth token from /api/command ([d5b39a1](https://github.com/filebrowser/filebrowser/commit/d5b39a14fd3fc0d1c364116b41289484df7c27b2))
* remove unused import ([c232d41](https://github.com/filebrowser/filebrowser/commit/c232d41f903d3026ec290bbe819b6c59a933048e))
### [2.33.8](https://github.com/filebrowser/filebrowser/compare/v2.33.7...v2.33.8) (2025-06-25)
### [2.33.7](https://github.com/filebrowser/filebrowser/compare/v2.33.6...v2.33.7) (2025-06-25)

View File

@ -38,6 +38,9 @@ File Browser is a **create-your-own-cloud-kind** of software where you can insta
| :----------------------: | :----------------------: | :----------------------: |
| ![](./docs/assets/4.jpg) | ![](./docs/assets/5.jpg) | ![](./docs/assets/6.jpg) |
> [!CAUTION]
>
> The **command execution** functionality has been disabled for all existent and new installations by default from version v2.33.8 and onwards, due to continuous and known security vulnerabilities. You should only use this feature if you are aware of all of the security risks involved. For more up to date information, consult issue [#5199](https://github.com/filebrowser/filebrowser/issues/5199).
## Install

View File

@ -1,6 +1,5 @@
import { removePrefix } from "./utils";
import { baseURL } from "@/utils/constants";
import { useAuthStore } from "@/stores/auth";
import { removePrefix } from "./utils";
const ssl = window.location.protocol === "https:";
const protocol = ssl ? "wss:" : "ws:";
@ -11,10 +10,8 @@ export default function command(
onmessage: WebSocket["onmessage"],
onclose: WebSocket["onclose"]
) {
const authStore = useAuthStore();
url = removePrefix(url);
url = `${protocol}//${window.location.host}${baseURL}/api/command${url}?auth=${authStore.jwt}`;
url = `${protocol}//${window.location.host}${baseURL}/api/command${url}`;
const conn = new window.WebSocket(url);
conn.onopen = () => conn.send(command);

View File

@ -321,7 +321,10 @@ const save = async () => {
.filter((cmd: string) => cmd !== "");
}
}
newSettings.shell = shellValue.value.split("\n");
newSettings.shell = shellValue.value
.trim()
.split(" ")
.filter((s) => s !== "");
if (newSettings.branding.theme !== getTheme()) {
setTheme(newSettings.branding.theme);

View File

@ -6,6 +6,7 @@ import (
"log"
"net/http"
"os/exec"
"slices"
"strings"
"time"
@ -60,7 +61,16 @@ var commandsHandler = withUser(func(w http.ResponseWriter, r *http.Request, d *d
}
}
command, err := runner.ParseCommand(d.settings, raw)
// Fail fast
if !d.server.EnableExec || !d.user.Perm.Execute {
if err := conn.WriteMessage(websocket.TextMessage, cmdNotAllowed); err != nil { //nolint:govet
wsErr(conn, r, http.StatusInternalServerError, err)
}
return 0, nil
}
command, name, err := runner.ParseCommand(d.settings, raw)
if err != nil {
if err := conn.WriteMessage(websocket.TextMessage, []byte(err.Error())); err != nil { //nolint:govet
wsErr(conn, r, http.StatusInternalServerError, err)
@ -68,7 +78,7 @@ var commandsHandler = withUser(func(w http.ResponseWriter, r *http.Request, d *d
return 0, nil
}
if !d.server.EnableExec || !d.user.CanExecute(command[0]) {
if !slices.Contains(d.user.Commands, name) {
if err := conn.WriteMessage(websocket.TextMessage, cmdNotAllowed); err != nil { //nolint:govet
wsErr(conn, r, http.StatusInternalServerError, err)
}

View File

@ -1,33 +1,24 @@
package runner
import (
"os/exec"
"github.com/filebrowser/filebrowser/v2/settings"
)
// ParseCommand parses the command taking in account if the current
// instance uses a shell to run the commands or just calls the binary
// directyly.
func ParseCommand(s *settings.Settings, raw string) ([]string, error) {
var command []string
// directly.
func ParseCommand(s *settings.Settings, raw string) (command []string, name string, err error) {
name, args, err := SplitCommandAndArgs(raw)
if err != nil {
return
}
if len(s.Shell) == 0 || s.Shell[0] == "" {
cmd, args, err := SplitCommandAndArgs(raw)
if err != nil {
return nil, err
}
_, err = exec.LookPath(cmd)
if err != nil {
return nil, err
}
command = append(command, cmd)
command = append(command, name)
command = append(command, args...)
} else {
command = append(s.Shell, raw) //nolint:gocritic
}
return command, nil
return command, name, nil
}

View File

@ -60,7 +60,7 @@ func (r *Runner) exec(raw, evt, path, dst string, user *users.User) error {
raw = strings.TrimSpace(strings.TrimSuffix(raw, "&"))
}
command, err := ParseCommand(r.Settings, raw)
command, _, err := ParseCommand(r.Settings, raw)
if err != nil {
return err
}

View File

@ -2,7 +2,6 @@ package users
import (
"path/filepath"
"regexp"
"github.com/spf13/afero"
@ -104,18 +103,3 @@ func (u *User) Clean(baseScope string, fields ...string) error {
func (u *User) FullPath(path string) string {
return afero.FullBaseFsPath(u.Fs.(*afero.BasePathFs), path)
}
// CanExecute checks if an user can execute a specific command.
func (u *User) CanExecute(command string) bool {
if !u.Perm.Execute {
return false
}
for _, cmd := range u.Commands {
if regexp.MustCompile(cmd).MatchString(command) {
return true
}
}
return false
}