Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added -form-check option for restrict form values #91

Merged
merged 1 commit into from
Feb 11, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 6 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ shell2http

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.

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

With `-form-check` 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: `-form-check='^[0-9]+$'`.
Then only requests like `http://localhost:8080/path?NNN=123` will be produce variable `$v_NNN`.

To setup multiple auth users, you can specify the `-basic-auth` option multiple times.
The credentials for basic authentication may also be provided via the `SH_BASIC_AUTH` environment variable.
You can specify the preferred HTTP-method (via `METHOD:` prefix for path): `shell2http GET:/date date`
Expand Down
50 changes: 31 additions & 19 deletions config.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (
"net"
"os"
"os/exec"
"regexp"
"runtime"
"strconv"
"strings"
Expand Down Expand Up @@ -47,25 +48,26 @@ func (au authUsers) isAllow(user, pass string) bool {

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

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

formCheck := flag.String("form-check", "", "regexp for check form fields (pass only vars that match the regexp)")

flag.Usage = func() {
fmt.Printf("usage: %s [options] /path \"shell command\" /path2 \"shell command2\"\n", os.Args[0])
flag.PrintDefaults()
Expand Down Expand Up @@ -149,6 +153,14 @@ func getConfig() (*Config, error) {
}
}

if formCheck != nil && len(*formCheck) > 0 {
re, err := regexp.Compile(*formCheck)
if err != nil {
return nil, fmt.Errorf("an error has occurred while compiling regexp %s: %s", *formCheck, err)
}
cfg.formCheckRe = re
}

return &cfg, nil
}

Expand Down
8 changes: 6 additions & 2 deletions shell2http.1
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
.\" generated with Ronn/v0.7.3
.\" http://github.com/rtomayko/ronn/tree/0.7.3
.
.TH "SHELL2HTTP" "" "October 2021" "" ""
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\.
.TH "SHELL2HTTP" "" "February 2023" "" ""
HTTP\-server to execute shell commands\. Designed for development, prototyping or remote control\. Settings through two command line arguments, path and shell command\.
.
.SH "Usage"
.
Expand All @@ -13,6 +13,7 @@ options:
\-host="host" : host IP for http server (default bind to all interfaces)
\-port=NNNN : port for http server, 0 \- to receive a random port (default 8080)
\-form : parse query into environment vars, handle uploaded files
\-form\-check : regexp for check form fields (pass only vars that match the regexp)
\-cgi : run scripts in CGI\-mode:
\- set environment variables with HTTP\-request information
\- write POST|PUT|PATCH\-data to script STDIN (if is not set \-form)
Expand Down Expand Up @@ -53,6 +54,9 @@ $filename_ID \-\- uploaded file name from browser
.IP "" 0
.
.P
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\.
.
.P
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
.
.SH "Install"
Expand Down
22 changes: 18 additions & 4 deletions shell2http.go
Original file line number Diff line number Diff line change
Expand Up @@ -205,7 +205,7 @@ func execShellCommand(appConfig Config, shell string, params []string, req *http
finalizer := func() {}
if appConfig.setForm {
var err error
if finalizer, err = getForm(osExecCommand, req); err != nil {
if finalizer, err = getForm(osExecCommand, req, appConfig.formCheckRe); err != nil {
log.Printf("parse form failed: %s", err)
}
}
Expand Down Expand Up @@ -420,7 +420,7 @@ func parseCGIHeaders(shellOut string) (string, map[string]string) {
}

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

for key, value := range req.Form {
cmd.Env = append(cmd.Env, fmt.Sprintf("%s=%s", "v_"+key, strings.Join(value, ",")))
for key, values := range req.Form {
if checkFormRe != nil {
checkedValues := []string{}
for _, v := range values {
if checkFormRe.MatchString(v) {
checkedValues = append(checkedValues, v)
}
}
values = checkedValues
}
if len(values) == 0 {
continue
}

value := strings.Join(values, ",")
cmd.Env = append(cmd.Env, fmt.Sprintf("%s=%s", "v_"+key, value))
}

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