Skip to content

Commit 43ccb51

Browse files
authored
Added -form-check option for restrict form values (#91)
1 parent 5fe9f2d commit 43ccb51

File tree

4 files changed

+61
-26
lines changed

4 files changed

+61
-26
lines changed

README.md

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@ shell2http
1111

1212
HTTP-server to execute shell commands. Designed for development, prototyping or remote control.
1313
Settings through two command line arguments, path and shell command.
14-
By default bind to :8080.
1514

1615
Usage
1716
-----
@@ -21,6 +20,7 @@ Usage
2120
-host="host" : host IP for http server (default bind to all interfaces)
2221
-port=NNNN : port for http server, 0 - to receive a random port (default 8080)
2322
-form : parse query into environment vars, handle uploaded files
23+
-form-check : regexp for check form fields (pass only vars that match the regexp)
2424
-cgi : run scripts in CGI-mode:
2525
- set environment variables with HTTP-request information
2626
- write POST|PUT|PATCH-data to script STDIN (if is not set -form)
@@ -50,6 +50,11 @@ In the `-form` mode, variables are available for shell scripts:
5050
* $filepath_ID -- uploaded file path, ID - id from `<input type=file name=ID>`, temporary uploaded file will be automatically deleted
5151
* $filename_ID -- uploaded file name from browser
5252

53+
With `-form-check` option you can specify the regular expression for checking the form fields.
54+
For example, if you want to allow only variables that contain the only digits,
55+
you can specify the following option: `-form-check='^[0-9]+$'`.
56+
Then only requests like `http://localhost:8080/path?NNN=123` will be produce variable `$v_NNN`.
57+
5358
To setup multiple auth users, you can specify the `-basic-auth` option multiple times.
5459
The credentials for basic authentication may also be provided via the `SH_BASIC_AUTH` environment variable.
5560
You can specify the preferred HTTP-method (via `METHOD:` prefix for path): `shell2http GET:/date date`

config.go

Lines changed: 31 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import (
77
"net"
88
"os"
99
"os/exec"
10+
"regexp"
1011
"runtime"
1112
"strconv"
1213
"strings"
@@ -47,25 +48,26 @@ func (au authUsers) isAllow(user, pass string) bool {
4748

4849
// Config - config struct
4950
type Config struct {
50-
port int // server port
51-
cache int // caching command out (in seconds)
52-
timeout int // timeout for shell command (in seconds)
53-
host string // server host
54-
exportVars string // list of environment vars for export to script
55-
shell string // custom shell
56-
defaultShell string // shell by default
57-
defaultShOpt string // shell option for one-liner (-c or /C)
58-
cert string // SSL certificate
59-
key string // SSL private key path
60-
auth authUsers // basic authentication
61-
exportAllVars bool // export all current environment vars
62-
setCGI bool // set CGI variables
63-
setForm bool // parse form from URL
64-
noIndex bool // don't generate index page
65-
addExit bool // add /exit command
66-
oneThread bool // run each shell commands in one thread
67-
showErrors bool // returns the standard output even if the command exits with a non-zero exit code
68-
includeStderr bool // also returns output written to stderr (default is stdout only)
51+
port int // server port
52+
cache int // caching command out (in seconds)
53+
timeout int // timeout for shell command (in seconds)
54+
host string // server host
55+
exportVars string // list of environment vars for export to script
56+
shell string // custom shell
57+
defaultShell string // shell by default
58+
defaultShOpt string // shell option for one-liner (-c or /C)
59+
cert string // SSL certificate
60+
key string // SSL private key path
61+
auth authUsers // basic authentication
62+
exportAllVars bool // export all current environment vars
63+
setCGI bool // set CGI variables
64+
setForm bool // parse form from URL
65+
noIndex bool // don't generate index page
66+
addExit bool // add /exit command
67+
oneThread bool // run each shell commands in one thread
68+
showErrors bool // returns the standard output even if the command exits with a non-zero exit code
69+
includeStderr bool // also returns output written to stderr (default is stdout only)
70+
formCheckRe *regexp.Regexp // regexp for check form fields
6971
}
7072

7173
// getConfig - parse arguments
@@ -105,6 +107,8 @@ func getConfig() (*Config, error) {
105107
flag.Var(&cfg.auth, "basic-auth", "setup HTTP Basic Authentication (\"user_name:password\"), can be used several times")
106108
flag.IntVar(&cfg.timeout, "timeout", 0, "set `timeout` for execute shell command (in seconds)")
107109

110+
formCheck := flag.String("form-check", "", "regexp for check form fields (pass only vars that match the regexp)")
111+
108112
flag.Usage = func() {
109113
fmt.Printf("usage: %s [options] /path \"shell command\" /path2 \"shell command2\"\n", os.Args[0])
110114
flag.PrintDefaults()
@@ -149,6 +153,14 @@ func getConfig() (*Config, error) {
149153
}
150154
}
151155

156+
if formCheck != nil && len(*formCheck) > 0 {
157+
re, err := regexp.Compile(*formCheck)
158+
if err != nil {
159+
return nil, fmt.Errorf("an error has occurred while compiling regexp %s: %s", *formCheck, err)
160+
}
161+
cfg.formCheckRe = re
162+
}
163+
152164
return &cfg, nil
153165
}
154166

shell2http.1

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
.\" generated with Ronn/v0.7.3
22
.\" http://github.com/rtomayko/ronn/tree/0.7.3
33
.
4-
.TH "SHELL2HTTP" "" "October 2021" "" ""
5-
HTTP\-server to execute shell commands\. Designed for development, prototyping or remote control\. Settings through two command line arguments, path and shell command\. By default bind to :8080\.
4+
.TH "SHELL2HTTP" "" "February 2023" "" ""
5+
HTTP\-server to execute shell commands\. Designed for development, prototyping or remote control\. Settings through two command line arguments, path and shell command\.
66
.
77
.SH "Usage"
88
.
@@ -13,6 +13,7 @@ options:
1313
\-host="host" : host IP for http server (default bind to all interfaces)
1414
\-port=NNNN : port for http server, 0 \- to receive a random port (default 8080)
1515
\-form : parse query into environment vars, handle uploaded files
16+
\-form\-check : regexp for check form fields (pass only vars that match the regexp)
1617
\-cgi : run scripts in CGI\-mode:
1718
\- set environment variables with HTTP\-request information
1819
\- write POST|PUT|PATCH\-data to script STDIN (if is not set \-form)
@@ -53,6 +54,9 @@ $filename_ID \-\- uploaded file name from browser
5354
.IP "" 0
5455
.
5556
.P
57+
With \fB\-form\-check\fR option you can specify the regular expression for checking the form fields\. For example, if you want to allow only variables that contain the only digits, you can specify the following option: \fB\-form\-check=\'^[0\-9]+$\'\fR\. Then only requests like \fBhttp://localhost:8080/path?NNN=123\fR will be produce variable \fB$v_NNN\fR\.
58+
.
59+
.P
5660
To setup multiple auth users, you can specify the \fB\-basic\-auth\fR option multiple times\. The credentials for basic authentication may also be provided via the \fBSH_BASIC_AUTH\fR environment variable\. You can specify the preferred HTTP\-method (via \fBMETHOD:\fR prefix for path): \fBshell2http GET:/date date\fR
5761
.
5862
.SH "Install"

shell2http.go

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -205,7 +205,7 @@ func execShellCommand(appConfig Config, shell string, params []string, req *http
205205
finalizer := func() {}
206206
if appConfig.setForm {
207207
var err error
208-
if finalizer, err = getForm(osExecCommand, req); err != nil {
208+
if finalizer, err = getForm(osExecCommand, req, appConfig.formCheckRe); err != nil {
209209
log.Printf("parse form failed: %s", err)
210210
}
211211
}
@@ -420,7 +420,7 @@ func parseCGIHeaders(shellOut string) (string, map[string]string) {
420420
}
421421

422422
// getForm - parse form into environment vars, also handle uploaded files
423-
func getForm(cmd *exec.Cmd, req *http.Request) (func(), error) {
423+
func getForm(cmd *exec.Cmd, req *http.Request, checkFormRe *regexp.Regexp) (func(), error) {
424424
tempDir := ""
425425
safeFileNameRe := regexp.MustCompile(`[^\.\w\-]+`)
426426
finalizer := func() {
@@ -441,8 +441,22 @@ func getForm(cmd *exec.Cmd, req *http.Request) (func(), error) {
441441
}
442442
}
443443

444-
for key, value := range req.Form {
445-
cmd.Env = append(cmd.Env, fmt.Sprintf("%s=%s", "v_"+key, strings.Join(value, ",")))
444+
for key, values := range req.Form {
445+
if checkFormRe != nil {
446+
checkedValues := []string{}
447+
for _, v := range values {
448+
if checkFormRe.MatchString(v) {
449+
checkedValues = append(checkedValues, v)
450+
}
451+
}
452+
values = checkedValues
453+
}
454+
if len(values) == 0 {
455+
continue
456+
}
457+
458+
value := strings.Join(values, ",")
459+
cmd.Env = append(cmd.Env, fmt.Sprintf("%s=%s", "v_"+key, value))
446460
}
447461

448462
// handle uploaded files, save all to temporary files and set variables filename_XXX, filepath_XXX

0 commit comments

Comments
 (0)