mirror of https://github.com/curusarn/resh
parent
4b7f063d0b
commit
f08d35eab5
@ -1,2 +1,6 @@ |
||||
github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ= |
||||
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= |
||||
github.com/mattn/go-shellwords v1.0.5 h1:JhhFTIOslh5ZsPrpa3Wdg8bF0WI3b44EMblmU9wIsXc= |
||||
github.com/mattn/go-shellwords v1.0.5/go.mod h1:3xCvwCdWdlDJUrvuMn7Wuy9eWs4pE8vqg+NOMyg4B2o= |
||||
github.com/whilp/git-urls v0.0.0-20160530060445-31bac0d230fa h1:rW+Lu6281ed/4XGuVIa4/YebTRNvoUJlfJ44ktEVwZk= |
||||
github.com/whilp/git-urls v0.0.0-20160530060445-31bac0d230fa/go.mod h1:2rx5KE5FLD0HRfkkpyn8JwbVLBdhgeiOb2D2D9LLKM4= |
||||
|
||||
@ -0,0 +1,262 @@ |
||||
package main |
||||
|
||||
import ( |
||||
"bufio" |
||||
"crypto/sha1" |
||||
"encoding/hex" |
||||
"encoding/json" |
||||
"errors" |
||||
"flag" |
||||
"fmt" |
||||
"log" |
||||
"net/url" |
||||
"os" |
||||
"os/user" |
||||
"path" |
||||
"path/filepath" |
||||
"strings" |
||||
|
||||
"github.com/curusarn/resh/common" |
||||
"github.com/mattn/go-shellwords" |
||||
giturls "github.com/whilp/git-urls" |
||||
) |
||||
|
||||
// Version from git set during build
|
||||
var Version string |
||||
|
||||
// Revision from git set during build
|
||||
var Revision string |
||||
|
||||
func main() { |
||||
usr, _ := user.Current() |
||||
dir := usr.HomeDir |
||||
historyPath := filepath.Join(dir, ".resh_history.json") |
||||
// outputPath := filepath.Join(dir, "resh_history_sanitized.json")
|
||||
sanitizerDataPath := filepath.Join(dir, ".resh", "sanitizer_data") |
||||
|
||||
showVersion := flag.Bool("version", false, "Show version and exit") |
||||
showRevision := flag.Bool("revision", false, "Show git revision and exit") |
||||
// outputToStdout := flag.Bool("stdout", false, "Print output to stdout instead of file")
|
||||
|
||||
flag.Parse() |
||||
|
||||
if *showVersion == true { |
||||
fmt.Println(Version) |
||||
os.Exit(0) |
||||
} |
||||
if *showRevision == true { |
||||
fmt.Println(Revision) |
||||
os.Exit(0) |
||||
} |
||||
sanitizer := sanitizer{} |
||||
err := sanitizer.init(sanitizerDataPath) |
||||
if err != nil { |
||||
log.Fatal("Sanitizer init() error:", err) |
||||
} |
||||
|
||||
file, err := os.Open(historyPath) |
||||
if err != nil { |
||||
log.Fatal("Open() resh history file error:", err) |
||||
} |
||||
defer file.Close() |
||||
|
||||
scanner := bufio.NewScanner(file) |
||||
for scanner.Scan() { |
||||
record := common.Record{} |
||||
line := scanner.Text() |
||||
err = json.Unmarshal([]byte(line), &record) |
||||
if err != nil { |
||||
log.Println("Decoding error:", err) |
||||
log.Println("Line:", line) |
||||
return |
||||
} |
||||
err = sanitizer.sanitize(&record) |
||||
if err != nil { |
||||
log.Println("Sanitization error:", err) |
||||
log.Println("Line:", line) |
||||
return |
||||
} |
||||
outLine, err := json.Marshal(&record) |
||||
if err != nil { |
||||
log.Println("Encoding error:", err) |
||||
log.Println("Line:", line) |
||||
return |
||||
} |
||||
fmt.Println(string(outLine)) |
||||
} |
||||
} |
||||
|
||||
type sanitizer struct { |
||||
GlobalWhitelist map[string]bool |
||||
PathWhitelist map[string]bool |
||||
// CmdWhitelist []string
|
||||
} |
||||
|
||||
func (s *sanitizer) init(dataPath string) error { |
||||
globalData := path.Join(dataPath, "whitelist.txt") |
||||
s.GlobalWhitelist = loadData(globalData) |
||||
pathData := path.Join(dataPath, "path_whitelist.txt") |
||||
s.PathWhitelist = loadData(pathData) |
||||
return nil |
||||
} |
||||
|
||||
func loadData(fname string) map[string]bool { |
||||
file, err := os.Open(fname) |
||||
if err != nil { |
||||
log.Fatal("Open() file error:", err) |
||||
} |
||||
defer file.Close() |
||||
|
||||
scanner := bufio.NewScanner(file) |
||||
data := make(map[string]bool) |
||||
for scanner.Scan() { |
||||
line := scanner.Text() |
||||
data[line] = true |
||||
} |
||||
return data |
||||
} |
||||
|
||||
func (s *sanitizer) sanitize(record *common.Record) error { |
||||
record.Pwd = s.sanitizePath(record.Pwd) |
||||
record.RealPwd = s.sanitizePath(record.RealPwd) |
||||
record.PwdAfter = s.sanitizePath(record.PwdAfter) |
||||
record.RealPwdAfter = s.sanitizePath(record.RealPwdAfter) |
||||
record.GitDir = s.sanitizePath(record.GitDir) |
||||
record.GitRealDir = s.sanitizePath(record.GitRealDir) |
||||
record.Home = s.sanitizePath(record.Home) |
||||
record.ShellEnv = s.sanitizePath(record.ShellEnv) |
||||
|
||||
record.Host = s.sanitizeTokenDontUseWhitelist(record.Host) |
||||
record.Uname = s.sanitizeTokenDontUseWhitelist(record.Uname) |
||||
record.Login = s.sanitizeTokenDontUseWhitelist(record.Login) |
||||
record.MachineId = s.sanitizeTokenDontUseWhitelist(record.MachineId) |
||||
|
||||
var err error |
||||
record.GitOriginRemote, err = s.sanitizeGitURL(record.GitOriginRemote) |
||||
if err != nil { |
||||
log.Println("Error while snitizing GitOriginRemote url", record.GitOriginRemote, ":", err) |
||||
return err |
||||
} |
||||
|
||||
fmt.Println("....") |
||||
parser := shellwords.NewParser() |
||||
|
||||
args, err := parser.Parse(record.CmdLine) |
||||
if err != nil { |
||||
log.Println("Parsing error @ position", parser.Position, ":", err) |
||||
log.Println("CmdLine:", record.CmdLine) |
||||
return err |
||||
} |
||||
fmt.Println(args) |
||||
|
||||
return nil |
||||
|
||||
// var tokens []string
|
||||
// word := ""
|
||||
// for _, char := range strings.Split(, "") {
|
||||
// if unicode.IsSpace([]rune(char)[0]) {
|
||||
// if len(word) > 0 {
|
||||
// tokens = append(tokens, word)
|
||||
// word = ""
|
||||
// }
|
||||
// tokens = append(tokens, char)
|
||||
// } else {
|
||||
// word += char
|
||||
// }
|
||||
// }
|
||||
// if len(word) > 0 {
|
||||
// tokens = append(tokens, word)
|
||||
// }
|
||||
// for _, token := range tokens {
|
||||
// fmt.Println(token)
|
||||
// }
|
||||
// return nil
|
||||
} |
||||
|
||||
func (s *sanitizer) sanitizeGitURL(rawURL string) (string, error) { |
||||
parsedURL, err := giturls.Parse(rawURL) |
||||
if err != nil { |
||||
return rawURL, err |
||||
} |
||||
return s.sanitizeParsedURL(parsedURL) |
||||
} |
||||
|
||||
func (s *sanitizer) sanitizeURL(rawURL string) (string, error) { |
||||
parsedURL, err := url.Parse(rawURL) |
||||
if err != nil { |
||||
return rawURL, err |
||||
} |
||||
return s.sanitizeParsedURL(parsedURL) |
||||
} |
||||
|
||||
func (s *sanitizer) sanitizeParsedURL(parsedURL *url.URL) (string, error) { |
||||
// Scheme string
|
||||
parsedURL.Opaque = s.sanitizeToken(parsedURL.Opaque) |
||||
|
||||
userinfo := parsedURL.User.Username() // only get username => password won't even make it to the sanitized data
|
||||
if len(userinfo) > 0 { |
||||
parsedURL.User = url.User(s.sanitizeToken(userinfo)) |
||||
} else { |
||||
// we need to do this because `gitUrls.Parse()` sets `User` to `url.User("")` instead of `nil`
|
||||
parsedURL.User = nil |
||||
} |
||||
var err error |
||||
parsedURL.Host, err = s.sanitizeTwoPartToken(parsedURL.Host, ":") |
||||
if err != nil { |
||||
return parsedURL.String(), err |
||||
} |
||||
parsedURL.Path = s.sanitizePath(parsedURL.Path) |
||||
// ForceQuery bool
|
||||
parsedURL.RawQuery = s.sanitizeToken(parsedURL.RawQuery) |
||||
parsedURL.Fragment = s.sanitizeToken(parsedURL.Fragment) |
||||
|
||||
return parsedURL.String(), nil |
||||
} |
||||
|
||||
func (s *sanitizer) sanitizePath(path string) string { |
||||
var sanPath string |
||||
for _, token := range strings.Split(path, "/") { |
||||
if s.PathWhitelist[token] != true { |
||||
token = s.sanitizeToken(token) |
||||
} |
||||
sanPath += token + "/" |
||||
} |
||||
if len(sanPath) > 0 { |
||||
sanPath = sanPath[:len(sanPath)-1] |
||||
} |
||||
return sanPath |
||||
} |
||||
|
||||
func (s *sanitizer) sanitizeTwoPartToken(token string, delimeter string) (string, error) { |
||||
tokenParts := strings.Split(token, delimeter) |
||||
if len(tokenParts) <= 1 { |
||||
return s.sanitizeToken(token), nil |
||||
} |
||||
if len(tokenParts) == 2 { |
||||
return s.sanitizeToken(tokenParts[0]) + delimeter + s.sanitizeToken(tokenParts[1]), nil |
||||
} |
||||
return token, errors.New("Token has more than two parts") |
||||
} |
||||
|
||||
func (s *sanitizer) sanitizeToken(token string) string { |
||||
return s._sanitizeToken(token, true) |
||||
} |
||||
|
||||
func (s *sanitizer) sanitizeTokenDontUseWhitelist(token string) string { |
||||
return s._sanitizeToken(token, false) |
||||
} |
||||
|
||||
func (s *sanitizer) _sanitizeToken(token string, useWhitelist bool) string { |
||||
if len(token) <= 0 { |
||||
return token |
||||
} |
||||
if useWhitelist == true && s.GlobalWhitelist[token] == true { |
||||
return token |
||||
} |
||||
// hash with sha1
|
||||
// trim to 12 characters
|
||||
h := sha1.New() |
||||
h.Write([]byte(token)) |
||||
sum := h.Sum(nil) |
||||
return hex.EncodeToString(sum)[:12] |
||||
} |
||||
@ -0,0 +1,23 @@ |
||||
|
||||
. |
||||
.. |
||||
bin |
||||
boot |
||||
dev |
||||
etc |
||||
home |
||||
lib |
||||
lib64 |
||||
lost+found |
||||
media |
||||
mnt |
||||
opt |
||||
proc |
||||
root |
||||
run |
||||
sbin |
||||
srv |
||||
sys |
||||
tmp |
||||
usr |
||||
var |
||||
@ -0,0 +1,28 @@ |
||||
|
||||
. |
||||
.. |
||||
bin |
||||
boot |
||||
dev |
||||
etc |
||||
home |
||||
lib |
||||
lib64 |
||||
lost+found |
||||
media |
||||
mnt |
||||
opt |
||||
proc |
||||
root |
||||
run |
||||
sbin |
||||
srv |
||||
sys |
||||
tmp |
||||
usr |
||||
var |
||||
bash |
||||
zsh |
||||
fish |
||||
github.com |
||||
git |
||||
Loading…
Reference in new issue