package localconfig import ( "bufio" "encoding/json" "errors" "fmt" "math/rand" "os" "strings" "time" "github.com/ProtonMail/gopenpgp/v2/helper" "github.com/howeyc/gopass" ) // Creds is user credentials type Creds struct { Login string Password string } func randomString(n int) string { rand.Seed(time.Now().UnixNano()) var letters = []rune("яшертёыуиопющэъасдфгчйкльжзхцвбнмabéàèùàçïôÖcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789&([-|_@])=+§!:;,*%$£µ") s := make([]rune, n) for i := range s { s[i] = letters[rand.Intn(len(letters))] } return string(s) } func loadRootKey() []byte { rkpath := getConfig("rk") rk, err := os.ReadFile(rkpath) if err != nil { rk = []byte(randomString(64)) os.WriteFile(rkpath, rk, 0600) } return rk } func (creds *Creds) Exists(filename string) bool { if _, err := os.Stat(getConfig(filename)); err == nil { return true } else if errors.Is(err, os.ErrNotExist) { return false } else { return false } } // Init will initalize login/password func (creds *Creds) Init(filename string) { fmt.Print("Enter login: ") var login string reader := bufio.NewReader(os.Stdin) login, _ = reader.ReadString('\n') creds.Login = strings.Trim(login, "\r\n") if login != "" { fmt.Print("Enter password:") bytePassword, _ := gopass.GetPasswd() silentPassword := string(bytePassword) if silentPassword != "" { creds.Password = silentPassword b, _ := json.Marshal(creds) fmt.Println("Writing credentials to : " + getConfig(filename)) armor, _ := helper.EncryptMessageWithPassword(loadRootKey(), string(b)) os.WriteFile(getConfig(filename), []byte(armor), 0600) } } } // Pw : update password func (creds *Creds) NewPw(filename string) { fmt.Print("Enter new password:") bytePassword, _ := gopass.GetPasswd() silentPassword := string(bytePassword) if silentPassword != "" { creds.Password = silentPassword b, _ := json.Marshal(creds) armor, _ := helper.EncryptMessageWithPassword(loadRootKey(), string(b)) os.WriteFile(getConfig(filename), []byte(armor), 0600) } } // Load credentials if available or creates them func (creds *Creds) Load(filename string) error { indata, err := os.ReadFile(getConfig(filename)) if err != nil { creds.Init(filename) return nil } pass, err := helper.DecryptMessageWithPassword(loadRootKey(), string(indata)) if err != nil { creds.Init(filename) return nil } err = json.Unmarshal([]byte(pass), &creds) if err != nil { creds.Init(filename) return nil } return nil }