From 3605e8abc56ecb9b062a63fa4059f1576a359271 Mon Sep 17 00:00:00 2001 From: Simon Let Date: Mon, 16 Dec 2019 21:26:57 +0100 Subject: [PATCH] add reshctl sanitize, add last recall to recorded data --- Makefile | 34 ----------------------- cmd/collect/main.go | 8 +++--- cmd/control/cmd/root.go | 2 ++ cmd/control/cmd/sanitize.go | 54 +++++++++++++++++++++++++++++++++++++ cmd/sanitize/main.go | 41 +++++++++++++++++++++------- pkg/records/records.go | 11 ++++---- scripts/hooks.sh | 3 ++- scripts/widgets.sh | 6 +++-- 8 files changed, 104 insertions(+), 55 deletions(-) create mode 100644 cmd/control/cmd/sanitize.go diff --git a/Makefile b/Makefile index 5917e2c..8881dca 100644 --- a/Makefile +++ b/Makefile @@ -4,40 +4,6 @@ REVISION=$(shell [ -z "$(git status --untracked-files=no --porcelain)" ] && git VERSION="${LATEST_TAG}-DEV" GOFLAGS=-ldflags "-X main.version=${VERSION} -X main.commit=${REVISION}" -sanitize: - # - # - # I'm going to create a sanitized version of your resh history. - # Everything is done locally - your history won't leave this machine. - # The way this works is that any sensitive information in your history is going to be replaced with its SHA1 hash. - # There is also going to be a second version with hashes trimed to 12 characters for readability - # - # - # > full hashes: ~/resh_history_sanitized.json - # > 12 char hashes: ~/resh_history_sanitized_trim12.json - # - # - # Encountered any issues? Got questions? -> Hit me up at https://github.com/curusarn/resh/issues - # - # - # Running history sanitization ... - resh-sanitize -trim-hashes 0 --output ~/resh_history_sanitized.json - resh-sanitize -trim-hashes 12 --output ~/resh_history_sanitized_trim12.json - # - # - # SUCCESS - ALL DONE! - # - # - # PLEASE HAVE A LOOK AT THE RESULT USING THESE COMMANDS: - # - # > pretty print JSON: - @echo 'cat ~/resh_history_sanitized_trim12.json | jq' - # - # > only show executed commands, don't show metadata: - @echo "cat ~/resh_history_sanitized_trim12.json | jq '.[\"cmdLine\"]'" - # - # - # build: submodules bin/resh-session-init bin/resh-collect bin/resh-postcollect bin/resh-daemon\ bin/resh-evaluate bin/resh-sanitize bin/resh-control bin/resh-config bin/resh-inspect diff --git a/cmd/collect/main.go b/cmd/collect/main.go index eec8d79..8eba780 100644 --- a/cmd/collect/main.go +++ b/cmd/collect/main.go @@ -57,6 +57,7 @@ func main() { // recall metadata recallActions := flag.String("recall-actions", "", "recall actions that took place before executing the command") recallStrategy := flag.String("recall-strategy", "", "recall strategy used during recall actions") + recallLastCmdLine := flag.String("recall-last-cmdline", "", "last recalled cmdline") // posix variables cols := flag.String("cols", "-1", "$COLUMNS") @@ -241,9 +242,10 @@ func main() { ReshVersion: version, ReshRevision: commit, - RecallActionsRaw: *recallActions, - RecallPrefix: *recallPrefix, - RecallStrategy: *recallStrategy, + RecallActionsRaw: *recallActions, + RecallPrefix: *recallPrefix, + RecallStrategy: *recallStrategy, + RecallLastCmdLine: *recallLastCmdLine, }, } collect.SendRecord(rec, strconv.Itoa(config.Port), "/record") diff --git a/cmd/control/cmd/root.go b/cmd/control/cmd/root.go index 60e1fe1..6ea0407 100644 --- a/cmd/control/cmd/root.go +++ b/cmd/control/cmd/root.go @@ -62,6 +62,8 @@ func Execute(ver, com string) status.Code { rootCmd.AddCommand(updateCmd) + rootCmd.AddCommand(sanitizeCmd) + if err := rootCmd.Execute(); err != nil { fmt.Println(err) return status.Fail diff --git a/cmd/control/cmd/sanitize.go b/cmd/control/cmd/sanitize.go new file mode 100644 index 0000000..50b3b5f --- /dev/null +++ b/cmd/control/cmd/sanitize.go @@ -0,0 +1,54 @@ +package cmd + +import ( + "fmt" + "os" + "os/exec" + "os/user" + + "github.com/curusarn/resh/cmd/control/status" + "github.com/spf13/cobra" +) + +var sanitizeCmd = &cobra.Command{ + Use: "sanitize", + Short: "produce a sanitized version of your RESH history", + Run: func(cmd *cobra.Command, args []string) { + exitCode = status.Success + usr, _ := user.Current() + dir := usr.HomeDir + + fmt.Println() + fmt.Println(" HOW IT WORKS") + fmt.Println(" In sanitized history, all sensitive information is replaced with its SHA1 hashes.") + fmt.Println() + fmt.Println("Sanitizing ...") + fmt.Println(" * ~/resh_history_sanitized.json (full lengh hashes)") + execCmd := exec.Command("resh-sanitize", "-trim-hashes", "0", "--output", dir+"/resh_history_sanitized.json") + execCmd.Stdout = os.Stdout + execCmd.Stderr = os.Stderr + err := execCmd.Run() + if err != nil { + exitCode = status.Fail + } + + fmt.Println(" * ~/resh_history_sanitized_trim12.json (12 char hashes)") + execCmd = exec.Command("resh-sanitize", "-trim-hashes", "12", "--output", dir+"/resh_history_sanitized_trim12.json") + execCmd.Stdout = os.Stdout + execCmd.Stderr = os.Stderr + err = execCmd.Run() + if err != nil { + exitCode = status.Fail + } + fmt.Println() + fmt.Println("Please direct all questions and/or issues to: https://github.com/curusarn/resh/issues") + fmt.Println() + fmt.Println("Please look at the resulting sanitized history using commands below.") + fmt.Println(" * Pretty print JSON") + fmt.Println(" cat ~/resh_history_sanitized_trim12.json | jq") + fmt.Println() + fmt.Println(" * Only show commands, don't show metadata") + fmt.Println(" cat ~/resh_history_sanitized_trim12.json | jq '.[\"cmdLine\"]") + fmt.Println() + }, +} diff --git a/cmd/sanitize/main.go b/cmd/sanitize/main.go index 5b888cd..9d5a8aa 100644 --- a/cmd/sanitize/main.go +++ b/cmd/sanitize/main.go @@ -172,6 +172,10 @@ func (s *sanitizer) sanitizeRecord(record *records.Record) error { if err != nil { log.Fatal("Cmd:", record.CmdLine, "; sanitization error:", err) } + record.RecallLastCmdLine, err = s.sanitizeCmdLine(record.RecallLastCmdLine) + if err != nil { + log.Fatal("RecallLastCmdLine:", record.RecallLastCmdLine, "; sanitization error:", err) + } if len(record.RecallActionsRaw) > 0 { record.RecallActionsRaw, err = s.sanitizeRecallActions(record.RecallActionsRaw) @@ -187,24 +191,41 @@ func (s *sanitizer) sanitizeRecord(record *records.Record) error { // sanitizes the recall actions by replacing the recall prefix with it's length func (s *sanitizer) sanitizeRecallActions(str string) (string, error) { sanStr := "" - for x, actionStr := range strings.Split(str, ";") { + divider := ";" + if strings.Contains(str, "|||") { + divider = "|||" + // normal mode + } + for x, actionStr := range strings.Split(str, divider+"arrow_") { if x == 0 { continue } if len(actionStr) == 0 { return str, errors.New("Action can't be empty; idx=" + strconv.Itoa(x)) } - fields := strings.Split(actionStr, ":") - if len(fields) != 2 { - return str, errors.New("Action should have exactly one ':' - encountered:" + actionStr) - } - action := fields[0] - if action != "arrow_up" && action != "arrow_down" { - return str, errors.New("Action (part 1) should be either 'arrow_up' or 'arrow_down' - encountered:" + action) + var action string + var prefix string + if strings.HasPrefix(actionStr, "up:") { + action = "arrow_up" + if len(actionStr) < 3 { + return str, errors.New("Action is too short:" + actionStr) + } + if len(actionStr) != 3 { + prefix = actionStr[4:] + } + } else if strings.HasPrefix(actionStr, "down:") { + action = "arrow_down" + if len(actionStr) < 5 { + return str, errors.New("Action is too short:" + actionStr) + } + if len(actionStr) != 5 { + prefix = actionStr[6:] + } + } else { + return str, errors.New("Action should start with one of (arrow_up, arrow_down); got: arrow_" + actionStr) } - prefix := fields[1] sanPrefix := strconv.Itoa(len(prefix)) - sanStr += ";" + action + ":" + sanPrefix + sanStr += "|||" + action + ":" + sanPrefix } return sanStr, nil } diff --git a/pkg/records/records.go b/pkg/records/records.go index 96eba4f..9eaf5b5 100644 --- a/pkg/records/records.go +++ b/pkg/records/records.go @@ -84,11 +84,12 @@ type BaseRecord struct { SessionExit bool `json:"sessionExit,omitempty"` // recall metadata - Recalled bool `json:"recalled"` - RecallHistno int `json:"recallHistno,omitempty"` - RecallStrategy string `json:"recallStrategy,omitempty"` - RecallActionsRaw string `json:"recallActionsRaw,omitempty"` - RecallActions []string `json:"recallActions,omitempty"` + Recalled bool `json:"recalled"` + RecallHistno int `json:"recallHistno,omitempty"` + RecallStrategy string `json:"recallStrategy,omitempty"` + RecallActionsRaw string `json:"recallActionsRaw,omitempty"` + RecallActions []string `json:"recallActions,omitempty"` + RecallLastCmdLine string `json:"recallLastCmdLine"` // recall command RecallPrefix string `json:"recallPrefix,omitempty"` diff --git a/scripts/hooks.sh b/scripts/hooks.sh index 3d57b07..3a2c6f2 100644 --- a/scripts/hooks.sh +++ b/scripts/hooks.sh @@ -3,7 +3,7 @@ __resh_reset_variables() { __RESH_HISTNO=0 __RESH_HISTNO_MAX="" __RESH_HISTNO_ZERO_LINE="" - __RESH_HIST_PREV_LINE="" # deprecated + __RESH_HIST_PREV_LINE="" __RESH_HIST_PREV_CURSOR="" # deprecated __RESH_HIST_PREV_PREFIX="" __RESH_HIST_RECALL_ACTIONS="" @@ -18,6 +18,7 @@ __resh_preexec() { __resh_collect --cmdLine "$__RESH_CMDLINE" \ --recall-actions "$__RESH_HIST_RECALL_ACTIONS" \ --recall-strategy "$__RESH_HIST_RECALL_STRATEGY" \ + --recall-last-cmdline "$__RESH_HIST_PREV_LINE" \ > ~/.resh/collect_last_run_out.txt 2>&1 || echo "resh-collect ERROR: $(head -n 1 ~/.resh/collect_last_run_out.txt)" } diff --git a/scripts/widgets.sh b/scripts/widgets.sh index 2b52302..ceba081 100644 --- a/scripts/widgets.sh +++ b/scripts/widgets.sh @@ -29,13 +29,15 @@ __resh_helper_arrow_post() { [ "$__RESH_HIST_NO_PREFIX_MODE" -eq 1 ] && CURSOR=${#BUFFER} # save current prefix so we can spot when user moves cursor or edits (the prefix part of) the line __RESH_HIST_PREV_PREFIX=${BUFFER:0:$CURSOR} + # recorded to history + __RESH_HIST_PREV_LINE=${BUFFER} } __resh_widget_arrow_up() { # run helper function __resh_helper_arrow_pre # append curent recall action - __RESH_HIST_RECALL_ACTIONS="$__RESH_HIST_RECALL_ACTIONS;arrow_up:$__RESH_PREFIX" + __RESH_HIST_RECALL_ACTIONS="$__RESH_HIST_RECALL_ACTIONS|||arrow_up:$__RESH_PREFIX" # increment histno __RESH_HISTNO=$((__RESH_HISTNO+1)) if [ "${#__RESH_HISTNO_MAX}" -gt 0 ] && [ "${__RESH_HISTNO}" -gt "${__RESH_HISTNO_MAX}" ]; then @@ -67,7 +69,7 @@ __resh_widget_arrow_down() { # run helper function __resh_helper_arrow_pre # append curent recall action - __RESH_HIST_RECALL_ACTIONS="$__RESH_HIST_RECALL_ACTIONS;arrow_down:$__RESH_PREFIX" + __RESH_HIST_RECALL_ACTIONS="$__RESH_HIST_RECALL_ACTIONS|||arrow_down:$__RESH_PREFIX" # increment histno __RESH_HISTNO=$((__RESH_HISTNO-1)) # prevent HISTNO from getting negative (for now)