Skip to content

Commit

Permalink
Merge pull request #5 from rsteube/break-all-the-things
Browse files Browse the repository at this point in the history
added injection command
  • Loading branch information
rsteube authored Mar 29, 2020
2 parents e7c4a64 + 7a3f622 commit 352a0bf
Show file tree
Hide file tree
Showing 6 changed files with 160 additions and 27 deletions.
9 changes: 8 additions & 1 deletion assert/assert.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package assert
import (
"bytes"
"log"
"strings"
"testing"

"github.com/alecthomas/chroma/quick"
Expand All @@ -23,6 +24,12 @@ func Equal(t *testing.T, expected string, actual string) {
} else {
dmp := diffmatchpatch.New()
diffs := dmp.DiffMain(expected, actual, false)
t.Errorf("\nexpected: %v\nactual : %v", expected, dmp.DiffPrettyText(diffs))

replacer := strings.NewReplacer(
``, ``,
``, ``,
)

t.Errorf("\nexpected: %v\nactual : %v", expected, replacer.Replace(dmp.DiffPrettyText(diffs)))
}
}
23 changes: 19 additions & 4 deletions bash/action.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,21 @@ import (
"strings"
)

var sanitizer = strings.NewReplacer(
`$`, ``,
"`", ``,
`\`, ``,
`"`, `'`,
)

func Sanitize(values ...string) []string {
sanitized := make([]string, len(values))
for index, value := range values {
sanitized[index] = sanitizer.Replace(value)
}
return sanitized
}

func Callback(prefix string, uid string) string {
return fmt.Sprintf(`eval $(_%v_callback '%v')`, prefix, uid)
}
Expand All @@ -18,7 +33,7 @@ func ActionFiles(suffix string) string {
}

func ActionNetInterfaces() string {
return ActionValues(ActionExecute(`ifconfig -a | grep -o '^[^ :]\+' | tr '\n' ' '`))
return `compgen -W "$(ifconfig -a | grep -o '^[^ :]\+' | tr '\n' ' ')" -- $last`
}

func ActionUsers() string {
Expand All @@ -30,7 +45,7 @@ func ActionGroups() string {
}

func ActionHosts() string {
return ActionValues(ActionExecute(`cat ~/.ssh/known_hosts | cut -d ' ' -f1 | cut -d ',' -f1`))
return `compgen -W "$(cat ~/.ssh/known_hosts | cut -d ' ' -f1 | cut -d ',' -f1)" -- $last`
}

func ActionValues(values ...string) string {
Expand All @@ -39,7 +54,7 @@ func ActionValues(values ...string) string {
}

vals := make([]string, len(values))
for index, val := range values {
for index, val := range Sanitize(values...) {
// TODO escape special characters
//vals[index] = strings.Replace(val, " ", `\ `, -1)
vals[index] = val
Expand All @@ -59,7 +74,7 @@ func ActionValuesDescribed(values ...string) string {
}

func ActionMessage(msg string) string {
return ActionValues("ERR", strings.Replace(msg, " ", "_", -1)) // TODO escape characters
return ActionValues("ERR", strings.Replace(Sanitize(msg)[0], " ", "_", -1)) // TODO escape characters
}

func ActionMultiParts(separator rune, values ...string) string {
Expand Down
27 changes: 27 additions & 0 deletions example/cmd/injection.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package cmd

import (
"github.com/rsteube/carapace"
"github.com/spf13/cobra"
)

var injectionCmd = &cobra.Command{
Use: "injection",
Short: "just trying to break things",
}

func init() {
rootCmd.AddCommand(injectionCmd)

carapace.Gen(injectionCmd).PositionalCompletion(
carapace.ActionValues("$(echo fail)"),
carapace.ActionValues(`\$(echo fail)`),
carapace.ActionValues("`echo fail`"),
carapace.ActionValues(`"; echo fail #`),
carapace.ActionValues(`"| echo fail #`),
carapace.ActionValues(`"&& echo fail #`),
carapace.ActionValues(`\$(echo fail)`),
carapace.ActionValues(`\`),
carapace.ActionValues(`LAST POSITIONAL VALUE`),
)
}
49 changes: 42 additions & 7 deletions example/cmd/root_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ _example_completions() {
*)
COMPREPLY=($(compgen -W "action alias callback condition" -- $last))
COMPREPLY=($(compgen -W "action alias callback condition injection" -- $last))
;;
esac
fi
Expand Down Expand Up @@ -127,6 +127,20 @@ _example_completions() {
fi
;;
'_example__injection' )
if [[ $last == -* ]]; then
COMPREPLY=($())
else
case $previous in
*)
COMPREPLY=($(eval $(_example_callback '_')))
;;
esac
fi
;;
esac
}
Expand Down Expand Up @@ -155,31 +169,35 @@ complete -c example -f
complete -c example -f -n '_example_state _example' -l array -s a -d 'multiflag' -r
complete -c example -f -n '_example_state _example' -l persistentFlag -s p -d 'Help message for persistentFlag'
complete -c example -f -n '_example_state _example' -l toggle -s t -d 'Help message for toggle' -a '(echo -e true\nfalse)' -r
complete -c example -f -n '_example_state _example' -l toggle -s t -d 'Help message for toggle' -a '(echo -e "true\nfalse")' -r
complete -c example -f -n '_example_state _example ' -a 'action alias' -d 'action example'
complete -c example -f -n '_example_state _example ' -a 'callback ' -d 'callback example'
complete -c example -f -n '_example_state _example ' -a 'condition ' -d 'condition example'
complete -c example -f -n '_example_state _example ' -a 'injection ' -d 'just trying to break things'
complete -c example -f -n '_example_state _example__action' -l custom -s c -d 'custom flag' -a '()' -r
complete -c example -f -n '_example_state _example__action' -l files -s f -d 'files flag' -a '(__fish_complete_suffix ".go")' -r
complete -c example -f -n '_example_state _example__action' -l groups -s g -d 'groups flag' -a '(__fish_complete_groups)' -r
complete -c example -f -n '_example_state _example__action' -l hosts -d 'hosts flag' -a '(__fish_print_hostnames)' -r
complete -c example -f -n '_example_state _example__action' -l message -s m -d 'message flag' -a '(echo -e ERR\tmessage example\n_\t\n\n)' -r
complete -c example -f -n '_example_state _example__action' -l multi_parts -d 'multi_parts flag' -a '(echo -e multi/parts\nmulti/parts/example\nmulti/parts/test\nexample/parts)' -r
complete -c example -f -n '_example_state _example__action' -l message -s m -d 'message flag' -a '(echo -e "ERR\tmessage example\n_")' -r
complete -c example -f -n '_example_state _example__action' -l multi_parts -d 'multi_parts flag' -a '(echo -e "multi/parts\nmulti/parts/example\nmulti/parts/test\nexample/parts")' -r
complete -c example -f -n '_example_state _example__action' -l net_interfaces -s n -d 'net_interfaces flag' -a '(__fish_print_interfaces)' -r
complete -c example -f -n '_example_state _example__action' -l users -s u -d 'users flag' -a '(__fish_complete_users)' -r
complete -c example -f -n '_example_state _example__action' -l values -s v -d 'values flag' -a '(echo -e values\nexample)' -r
complete -c example -f -n '_example_state _example__action' -l values_described -s d -d 'values with description flag' -a '(echo -e values\tvalueDescription\nexample\texampleDescription\n\n)' -r
complete -c example -f -n '_example_state _example__action' -l values -s v -d 'values flag' -a '(echo -e "values\nexample")' -r
complete -c example -f -n '_example_state _example__action' -l values_described -s d -d 'values with description flag' -a '(echo -e "values\tvalueDescription\nexample\texampleDescription\n\n")' -r
complete -c example -f -n '_example_state _example__action' -a '(_example_callback _)'
complete -c example -f -n '_example_state _example__callback' -l callback -s c -d 'Help message for callback' -a '(_example_callback _example__callback##callback)' -r
complete -c example -f -n '_example_state _example__callback' -a '(_example_callback _)'
complete -c example -f -n '_example_state _example__condition' -l required -s r -d 'required flag' -a '(echo -e valid\ninvalid)' -r
complete -c example -f -n '_example_state _example__condition' -l required -s r -d 'required flag' -a '(echo -e "valid\ninvalid")' -r
complete -c example -f -n '_example_state _example__condition' -a '(_example_callback _)'
complete -c example -f -n '_example_state _example__injection' -a '(_example_callback _)'
`
assert.Equal(t, expected, carapace.Gen(rootCmd).Fish())
}
Expand Down Expand Up @@ -207,6 +225,7 @@ function _example {
"alias:action example"
"callback:callback example"
"condition:condition example"
"injection:just trying to break things"
)
_describe "command" commands
;;
Expand All @@ -225,6 +244,9 @@ function _example {
condition)
_example__condition
;;
injection)
_example__injection
;;
esac
}
Expand Down Expand Up @@ -255,6 +277,19 @@ function _example__condition {
"(-r --required)"{-r,--required}"[required flag]: :_values '' valid invalid" \
"1:: : eval \$(${os_args[1]} _carapace zsh '_example__condition#1' ${${os_args:1:gs/\"/\\\"}:gs/\'/\\\"})"
}
function _example__injection {
_arguments -C \
"1:: :_values '' echo\ fail" \
"2:: :_values '' echo\ fail" \
"3:: :_values '' echo\ fail" \
"4:: :_values '' \ echo\ fail\ " \
"5:: :_values '' \ echo\ fail\ " \
"6:: :_values '' \ echo\ fail\ " \
"7:: :_values '' echo\ fail" \
"8:: : _message -r 'no values to complete'" \
"9:: :_values '' LAST\ POSITIONAL\ VALUE"
}
if compquote '' 2>/dev/null; then _example; else compdef _example example; fi
`
assert.Equal(t, expected, carapace.Gen(rootCmd).Zsh())
Expand Down
35 changes: 27 additions & 8 deletions fish/action.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,23 @@ import (
"strings"
)

var sanitizer = strings.NewReplacer(
`$`, ``,
"`", ``,
`\`, ``,
`"`, `'`,
`(`, `[`,
`)`, `]`,
)

func Sanitize(values ...string) []string {
sanitized := make([]string, len(values))
for index, value := range values {
sanitized[index] = sanitizer.Replace(value)
}
return sanitized
}

func Callback(prefix string, uid string) string {
return ActionExecute(fmt.Sprintf(`_%v_callback %v`, prefix, uid))
}
Expand Down Expand Up @@ -34,32 +51,34 @@ func ActionHosts() string {
}

func ActionValues(values ...string) string {
if len(strings.TrimSpace(strings.Join(values, ""))) == 0 {
sanitized := Sanitize(values...)
if len(strings.TrimSpace(strings.Join(sanitized, ""))) == 0 {
return ActionMessage("no values to complete")
}

vals := make([]string, len(values))
for index, val := range values {
vals := make([]string, len(sanitized))
for index, val := range sanitized {
// TODO escape special characters
//vals[index] = strings.Replace(val, " ", `\ `, -1)
vals[index] = val
}
return ActionExecute(fmt.Sprintf(`echo -e %v`, strings.Join(vals, `\n`)))
return ActionExecute(fmt.Sprintf(`echo -e "%v"`, strings.Join(vals, `\n`)))
}

func ActionValuesDescribed(values ...string) string {
sanitized := Sanitize(values...)
// TODO verify length (description always exists)
vals := make([]string, len(values))
for index, val := range values {
vals := make([]string, len(sanitized))
for index, val := range sanitized {
if index%2 == 0 {
vals[index/2] = fmt.Sprintf(`%v\t%v`, val, values[index+1])
}
}
return ActionValues(vals...)
return ActionExecute(fmt.Sprintf(`echo -e "%v"`, strings.Join(vals, `\n`)))
}

func ActionMessage(msg string) string {
return ActionValuesDescribed("ERR", msg, "_", "")
return ActionExecute(fmt.Sprintf(`echo -e "ERR\t%v\n_"`, Sanitize(msg)[0]))
}

func ActionMultiParts(separator rune, values ...string) string {
Expand Down
44 changes: 37 additions & 7 deletions zsh/action.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,30 @@ import (
"strings"
)

var sanitizer = strings.NewReplacer(
`$`, ``,
"`", ``,
`\`, ``,
`"`, ``,
`'`, ``,
`|`, ``,
`>`, ``,
`<`, ``,
`&`, ``,
`(`, ``,
`)`, ``,
`;`, ``,
`#`, ``,
)

func Sanitize(values ...string) []string {
sanitized := make([]string, len(values))
for index, value := range values {
sanitized[index] = sanitizer.Replace(value)
}
return sanitized
}

func Callback(uid string) string {
return ActionExecute(fmt.Sprintf(`${os_args[1]} _carapace zsh '%v' ${${os_args:1:gs/\"/\\\"}:gs/\'/\\\"}`, uid))
}
Expand Down Expand Up @@ -46,12 +70,13 @@ func ActionHosts() string {

// ActionValues completes arbitrary keywords (values)
func ActionValues(values ...string) string {
if len(strings.TrimSpace(strings.Join(values, ""))) == 0 {
sanitized := Sanitize(values...)
if len(strings.TrimSpace(strings.Join(sanitized, ""))) == 0 {
return ActionMessage("no values to complete")
}

vals := make([]string, len(values))
for index, val := range values {
vals := make([]string, len(sanitized))
for index, val := range sanitized {
// TODO escape special characters
vals[index] = strings.Replace(val, " ", `\ `, -1)
}
Expand All @@ -60,14 +85,19 @@ func ActionValues(values ...string) string {

// ActionValuesDescribed completes arbitrary key (values) with an additional description (value, description pairs)
func ActionValuesDescribed(values ...string) string {
sanitized := Sanitize(values...)
if len(strings.TrimSpace(strings.Join(sanitized, ""))) == 0 {
return ActionMessage("no values to complete")
}

// TODO verify length (description always exists)
vals := make([]string, len(values))
for index, val := range values {
vals := make([]string, len(sanitized))
for index, val := range sanitized {
if index%2 == 0 {
vals[index/2] = fmt.Sprintf("'%v[%v]'", val, values[index+1])
vals[index/2] = fmt.Sprintf("'%v[%v]'", strings.Replace(val, " ", `\ `, -1), strings.Replace(values[index+1], " ", `\ `, -1))
}
}
return ActionValues(vals...)
return fmt.Sprintf(`_values '' %v`, strings.Join(vals, " "))
}

// ActionMessage displays a help messages in places where no completions can be generated
Expand Down

0 comments on commit 352a0bf

Please sign in to comment.