mirror of
https://github.com/portainer/portainer.git
synced 2026-08-07 07:54:48 +00:00
fix(nodeShell): detect bash shell [C9S-298] (#3328)
This commit is contained in:
committed by
GitHub
parent
df4c700667
commit
6af854dfbc
@@ -4,7 +4,6 @@ import (
|
||||
"errors"
|
||||
"io"
|
||||
"net/http"
|
||||
"strings"
|
||||
|
||||
portainer "github.com/portainer/portainer/api"
|
||||
"github.com/portainer/portainer/api/http/proxy/factory/kubernetes"
|
||||
@@ -123,7 +122,7 @@ func (handler *Handler) hijackPodExecStartOperation(
|
||||
endpoint *portainer.Endpoint,
|
||||
namespace, podName, containerName, command string,
|
||||
) *httperror.HandlerError {
|
||||
commandArray := strings.Split(command, " ")
|
||||
commandArray := ws.SplitExecCommand(command)
|
||||
|
||||
websocketConn, err := handler.connectionUpgrader.Upgrade(w, r, nil)
|
||||
if err != nil {
|
||||
|
||||
@@ -0,0 +1,41 @@
|
||||
package ws
|
||||
|
||||
import "strings"
|
||||
|
||||
// SplitExecCommand splits a command string into exec argv, treating a
|
||||
// single-quoted segment as one argument even if it contains spaces (e.g.
|
||||
// `sh -c 'echo a b'` stays 3 tokens instead of being shredded on every
|
||||
// space). Single quotes are not escapable, matching POSIX shell semantics for
|
||||
// single-quoted strings; there is no support for double quotes since callers
|
||||
// only ever need one quoted tail argument (a `sh -c` script).
|
||||
func SplitExecCommand(command string) []string {
|
||||
var (
|
||||
args []string
|
||||
current strings.Builder
|
||||
inQuote bool
|
||||
started bool
|
||||
)
|
||||
|
||||
for _, r := range command {
|
||||
switch {
|
||||
case r == '\'':
|
||||
inQuote = !inQuote
|
||||
started = true
|
||||
case r == ' ' && !inQuote:
|
||||
if started {
|
||||
args = append(args, current.String())
|
||||
current.Reset()
|
||||
started = false
|
||||
}
|
||||
default:
|
||||
current.WriteRune(r)
|
||||
started = true
|
||||
}
|
||||
}
|
||||
|
||||
if started {
|
||||
args = append(args, current.String())
|
||||
}
|
||||
|
||||
return args
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
package ws
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestSplitExecCommand(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
f := func(input string, expected []string) {
|
||||
t.Helper()
|
||||
require.Equal(t, expected, SplitExecCommand(input))
|
||||
}
|
||||
|
||||
f("", nil)
|
||||
f("bash", []string{"bash"})
|
||||
f("env TERM=xterm-256color /bin/bash", []string{"env", "TERM=xterm-256color", "/bin/bash"})
|
||||
f("sh -c 'echo a b'", []string{"sh", "-c", "echo a b"})
|
||||
f("sh -c 'command -v bash >/dev/null 2>&1 && exec bash || exec sh'",
|
||||
[]string{"sh", "-c", "command -v bash >/dev/null 2>&1 && exec bash || exec sh"})
|
||||
f("a b", []string{"a", "b"})
|
||||
f("'unterminated", []string{"unterminated"})
|
||||
}
|
||||
@@ -111,6 +111,7 @@ module.exports = {
|
||||
{
|
||||
context: ['/api'],
|
||||
target: 'http://localhost:9000',
|
||||
ws: true,
|
||||
},
|
||||
],
|
||||
open: true,
|
||||
|
||||
Reference in New Issue
Block a user