-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathextract.go
117 lines (91 loc) · 3.57 KB
/
extract.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
package main
import (
"fmt"
"errors"
"io/ioutil"
"os"
"regexp"
"bytes"
)
type ExtractOptions struct {
StateFile string `short:"s" long:"state-file" description:"The state file. Defaults to STDIN"`
CredentialFile string `short:"f" long:"credential-file" description:"the credential file to create or update with the new creds" required:"true"`
Key string `short:"k" long:"key" description:"the moustache name for the credential placeholder" required:"true"`
Pattern string `short:"p" long:"pattern" description:"The regular expression to find and extract the credentials (first capture group or entire expression)" required:"true"`
Multi bool `short:"m" long:"multi" description:"Replace multiple entries that match the capture group (will NOT work without capture group)"`
}
var extractOptions ExtractOptions
func (extractOptions *ExtractOptions) OpenStateFile() ([]byte, error) {
if(extractOptions.StateFile == "") {
output, stdoutError := ioutil.ReadAll(os.Stdin)
if(stdoutError != nil) {
return nil, errors.New("Could not read from stdin")
}
return output, nil
}
output, readFileError := ioutil.ReadFile(extractOptions.StateFile)
if (readFileError != nil) {
return nil, errors.New(fmt.Sprintf("Could not read input file '%s'", extractOptions.StateFile))
}
return output, nil
}
func (extractOptions *ExtractOptions) Execute(args []string) error {
state, stateFileError := extractOptions.OpenStateFile()
if (stateFileError != nil) {
return stateFileError
}
pattern, regexpError := regexp.Compile(extractOptions.Pattern)
if (regexpError != nil) {
return errors.New(fmt.Sprintf("Could not compile pattern as regular expression '%s'", extractOptions.Pattern))
}
matches := pattern.FindAllSubmatch(state, -1)
template := []byte("{{" + extractOptions.Key + "}}")
var newState string
var cred []byte
if (len(matches) < 1) {
return errors.New(fmt.Sprintf("Could not match pattern '%s' in the state-file", extractOptions.Pattern))
} else if(len(matches) > 1) {
return errors.New(fmt.Sprintf("Matched pattern '%s' %d times(s) in the state-file, you need to improve the match count", extractOptions.Pattern, len(matches)))
} else {
if (len(matches[0]) > 2) {
return errors.New(fmt.Sprintf("Matched capture group %d times(s) in the state-file, cannot have more than one sub group match", len(matches[0])))
} else if (len(matches[0]) > 1) {
cred = matches[0][1]
if (globalOptions.Debug) {
fmt.Printf("Capture group match:\n\n%s",string(cred))
return nil
}
if (extractOptions.Multi) {
groupKiller, _ := regexp.Compile(regexp.QuoteMeta(string(matches[0][1])))
newState = string(groupKiller.ReplaceAll(state, template))
} else {
newState = string(pattern.ReplaceAllFunc(state, func(match []byte) []byte {
return bytes.Replace(match, cred, template, 1)
}))
}
} else {
if (extractOptions.Multi) {
return errors.New("Multi is on, but no capture groups matched")
}
cred = matches[0][0]
if (globalOptions.Debug) {
fmt.Printf("Whole expression match:\n\n%s",string(cred))
return nil
}
newState = string(pattern.ReplaceAll(state, template))
}
credentialFileError := ioutil.WriteFile(extractOptions.CredentialFile ,cred, 0644)
if (credentialFileError != nil) {
return errors.New(fmt.Sprintf("Could not write to credentials file '%s'", extractOptions.CredentialFile))
}
}
fmt.Print(newState)
return nil
}
func init() {
parser.AddCommand(
"extract",
"Extract Credentials",
"The extract command extracts credentials matching a regex and leaves a placeholder in the statefile",
&extractOptions)
}