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
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
|
package main
import (
"bufio"
"encoding/json"
"fmt"
"io/ioutil"
"os"
"strconv"
"strings"
"github.com/mitchellh/go-homedir"
)
type passListEntry struct {
Name string `json:"name"`
Pass string `json:"pass"`
}
//Secure encryption algorithm from https://socketloop.com/tutorials/golang-rotate-47-caesar-cipher-by-47-characters-example
func rot47(input string) string {
var result []string
for i := range input[:len(input)] {
j := int(input[i])
if (j >= 33) && (j <= 126) {
result = append(result, string(rune(33+((j+14)%94))))
} else {
result = append(result, string(input[i]))
}
}
return strings.Join(result, "")
}
//Encrypt the credentials and write them to a file.
func saveCredsToFile(filepath string, passlist []passListEntry) string {
file, err := os.OpenFile(filepath, os.O_TRUNC|os.O_CREATE|os.O_WRONLY, 0644)
if err != nil {
fmt.Println(err.Error())
return err.Error()
}
defer file.Close()
stringToWrite := rot47(credsToJSON(passlist))
if _, err := file.WriteString(stringToWrite); err != nil {
fmt.Println(err.Error())
return err.Error()
}
return "Success"
}
//Load the credentials from the encrypted file
func loadCredsFromFile(filepath string) ([]passListEntry, string) {
buff, err := ioutil.ReadFile(filepath)
if err != nil {
fmt.Println(err.Error())
return nil, "Failed to open or read file"
}
//Decrypt passwords
buff = []byte(rot47(string(buff)))
//Load decrypted passwords
var passlist []passListEntry
err = json.Unmarshal(buff, &passlist)
if err != nil {
fmt.Println(err.Error())
return nil, "Failed to load creds"
}
return passlist, "Ok"
}
//Convert the array of credentials to JSON
func credsToJSON(passlist []passListEntry) string {
jsonBuffer, err := json.Marshal(passlist)
if err != nil {
fmt.Println(err.Error())
return "Something went wrong"
}
return string(jsonBuffer)
}
//Python style input function
func input(prompt string) string {
fmt.Print(prompt)
scanner := bufio.NewScanner(os.Stdin)
if scanner.Scan() {
return scanner.Text()
}
return ""
}
func serviceSearch(passlist []passListEntry, serviceName string) (int, passListEntry) {
//A linear search is the best I can do, Steve says it's Oh Log N whatever that means
for index, entry := range passlist {
if entry.Name == serviceName {
return index, entry
}
}
return -1, passListEntry{}
}
func getPwdForService(passlist []passListEntry, serviceName string) string {
index, entry := serviceSearch(passlist, serviceName)
if index != -1 {
return entry.Pass
}
return "Pass not found"
}
func setPwdForService(passlist []passListEntry, serviceName string, newPwd string) []passListEntry {
index, entry := serviceSearch(passlist, serviceName)
//If service exists, update entry
if index != -1 {
entry.Pass = newPwd
passlist[index] = entry
return passlist
}
//If it doesn't, create an entry
entry = passListEntry{Name: serviceName, Pass: newPwd}
passlist = append(passlist, entry)
return passlist
}
func deletePwdByService(passlist []passListEntry, serviceName string) (resultList []passListEntry, status string) {
index, _ := serviceSearch(passlist, serviceName)
if index != -1 {
//remove Pwd from passlist
resultList = append(passlist[:index], passlist[index+1:]...)
status = "Ok"
return
}
return passlist, "Pass not found"
}
func printAllPasswords(passlist []passListEntry) {
for _, entry := range passlist {
fmt.Println(entry.Name, "\t", entry.Pass)
}
}
func main() {
credsPath, err := homedir.Expand("~/.overpass")
if err != nil {
fmt.Println("Error finding home path:", err.Error())
}
//Load credentials
passlist, status := loadCredsFromFile(credsPath)
if status != "Ok" {
fmt.Println(status)
fmt.Println("Continuing with new password file.")
passlist = make([]passListEntry, 0)
}
fmt.Println("Welcome to Overpass")
//Determine function
option := -1
fmt.Print(
"Options:\n" +
"1\tRetrieve Password For Service\n" +
"2\tSet or Update Password For Service\n" +
"3\tDelete Password For Service\n" +
"4\tRetrieve All Passwords\n" +
"5\tExit\n")
for option > 5 || option < 1 {
optionString := input("Choose an option:\t")
optionChoice, err := strconv.Atoi(optionString)
if err != nil || optionChoice > 5 || optionChoice < 1 {
fmt.Println("Please enter a valid number")
}
option = optionChoice
}
switch option {
case 1:
service := input("Enter Service Name:\t")
getPwdForService(passlist, service)
case 2:
service := input("Enter Service Name:\t")
newPwd := input("Enter new password:\t")
passlist = setPwdForService(passlist, service, newPwd)
saveCredsToFile(credsPath, passlist)
case 3:
service := input("Enter Service Name:\t")
passlist, status := deletePwdByService(passlist, service)
if status != "Ok" {
fmt.Println(status)
}
saveCredsToFile(credsPath, passlist)
case 4:
printAllPasswords(passlist)
}
}
|