-
Notifications
You must be signed in to change notification settings - Fork 5
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Kristof Daja
committed
Jun 6, 2023
1 parent
5a9a1ad
commit da4fc59
Showing
10 changed files
with
452 additions
and
5 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
package main | ||
|
||
import ( | ||
"os" | ||
|
||
"gopkg.in/yaml.v2" | ||
) | ||
|
||
type UserConfig struct { | ||
Host string `yaml:"host"` | ||
HostAuthType string `yaml:"host_auth_type"` | ||
Username string `yaml:"username"` | ||
Password string `yaml:"password"` | ||
PasswordEncrypted string `yaml:"password_encrypted"` | ||
ProjectSlugs []string `yaml:"project_slugs"` | ||
} | ||
|
||
func readConfigFile(path string) (*UserConfig, error) { | ||
b, err := os.ReadFile(path) | ||
if err != nil { | ||
return cfg, err | ||
} | ||
s := UserConfig{} | ||
err = yaml.Unmarshal([]byte(b), &s) | ||
return &s, err | ||
} | ||
|
||
func writeConfigFile(cfg *UserConfig, path string) error { | ||
cfgCopy := *cfg | ||
cfgCopy.Password = "" // clear password to avoid writing it back to config | ||
b, err := yaml.Marshal(&cfgCopy) | ||
if err != nil { | ||
return err | ||
} | ||
return os.WriteFile(path, b, 0644) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
package main | ||
|
||
import ( | ||
"log" | ||
|
||
"github.com/denisbrodbeck/machineid" | ||
"github.com/theriverman/taigo/cli/passwordbasedencryption" | ||
) | ||
|
||
func PasswordEncrypt(plainPassword string) string { | ||
machineID, err := machineid.ID() | ||
if err != nil { | ||
log.Fatal(err) | ||
} | ||
s, err := passwordbasedencryption.Encrypt(machineID, 5, plainPassword) | ||
if err != nil { | ||
log.Fatal(err) | ||
} | ||
return s | ||
} | ||
|
||
func PasswordDecrypt(encryptedPassword string) string { | ||
machineID, err := machineid.ID() | ||
if err != nil { | ||
log.Fatal(err) | ||
} | ||
s, err := passwordbasedencryption.Decrypt(machineID, 5, encryptedPassword) | ||
if err != nil { | ||
log.Fatal(err) | ||
} | ||
return s | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
module github.com/theriverman/taigo/cli | ||
|
||
replace github.com/theriverman/taigo => ../ | ||
|
||
replace github.com/theriverman/taigo/cli/passwordbasedencryption => ./passwordbasedencryption | ||
|
||
go 1.19 | ||
|
||
require ( | ||
github.com/denisbrodbeck/machineid v1.0.1 | ||
github.com/theriverman/taigo v1.6.1 | ||
github.com/theriverman/taigo/cli/passwordbasedencryption v0.0.0-00010101000000-000000000000 | ||
gopkg.in/yaml.v2 v2.4.0 | ||
) | ||
|
||
require ( | ||
github.com/google/go-querystring v1.0.0 // indirect | ||
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f // indirect | ||
golang.org/x/text v0.3.8 // indirect | ||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,34 @@ | ||
github.com/denisbrodbeck/machineid v1.0.1 h1:geKr9qtkB876mXguW2X6TU4ZynleN6ezuMSRhl4D7AQ= | ||
github.com/denisbrodbeck/machineid v1.0.1/go.mod h1:dJUwb7PTidGDeYyUBmXZ2GphQBbjJCrnectwCyxcUSI= | ||
github.com/google/go-querystring v1.0.0 h1:Xkwi/a1rcvNg1PPYe5vI8GbeBY/jrVuDX5ASuANWTrk= | ||
github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck= | ||
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= | ||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= | ||
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= | ||
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= | ||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= | ||
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= | ||
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= | ||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= | ||
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= | ||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= | ||
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= | ||
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= | ||
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= | ||
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f h1:v4INt8xihDGvnrfjMDVXGxw9wrfxYyCjk0KbXjhR55s= | ||
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= | ||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= | ||
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= | ||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= | ||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= | ||
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= | ||
golang.org/x/text v0.3.8 h1:nAL+RVCQ9uMn3vJZbV+MRnydTJFPf8qqY42YiA6MrqY= | ||
golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ= | ||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= | ||
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= | ||
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= | ||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= | ||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= | ||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= | ||
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= | ||
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,106 @@ | ||
package main | ||
|
||
import ( | ||
"fmt" | ||
"log" | ||
"net/http" | ||
"os" | ||
"path/filepath" | ||
|
||
taiga "github.com/theriverman/taigo" | ||
) | ||
|
||
const TaigoCfgFolder string = "TaigoCLI" | ||
const UserCfgFilename string = "taigocli.cfg.yaml" | ||
const DefaultTaigaHost string = "https://api.taiga.io" | ||
const DefaultTaigaHostAuthType string = "normal" | ||
|
||
var cfg *UserConfig = &UserConfig{} | ||
var client taiga.Client | ||
|
||
var AppName string = "Taigo CLI" | ||
var username, password string // if set, overrides cfg.Username|Password | ||
|
||
func init() { | ||
/* | ||
setup userspace | ||
*/ | ||
// get home | ||
userHomeDir, err := os.UserHomeDir() | ||
if err != nil { | ||
log.Fatal(err) | ||
} | ||
// check/create TaigoCli directory existence | ||
TaigoCliHomeDir := filepath.Join(userHomeDir, TaigoCfgFolder) | ||
TaigoCliCfgPath := filepath.Join(TaigoCliHomeDir, UserCfgFilename) | ||
if err = os.MkdirAll(TaigoCliHomeDir, 0644); err != nil { | ||
log.Fatal(err) | ||
} | ||
// get/create config file | ||
if cfg, err = readConfigFile(TaigoCliCfgPath); err != nil { | ||
log.Printf("config file not found (%s). creating a new one", err) | ||
if err = writeConfigFile(cfg, TaigoCliCfgPath); err != nil { | ||
log.Fatalln("writeConfigFile:", err) | ||
} | ||
} | ||
/* | ||
setup Taigo client | ||
*/ | ||
// new client | ||
client = taiga.Client{ | ||
BaseURL: DefaultTaigaHost, | ||
HTTPClient: &http.Client{}, | ||
} | ||
// store the password in an encrypted fashion | ||
if password != "" { | ||
cfg.Password = password | ||
} | ||
if cfg.PasswordEncrypted != "" { | ||
cfg.Password = PasswordDecrypt(cfg.PasswordEncrypted) | ||
} else if cfg.Password != "" { | ||
cfg.PasswordEncrypted = PasswordEncrypt(cfg.Password) | ||
} | ||
// set default values if empty/missing from config file | ||
if cfg.Host != "" { | ||
client.BaseURL = cfg.Host | ||
} | ||
if username != "" { | ||
cfg.Username = username | ||
} | ||
if err = writeConfigFile(cfg, TaigoCliCfgPath); err != nil { | ||
log.Fatalln("writeConfigFile:", err) | ||
} | ||
} | ||
|
||
func main() { | ||
// init client | ||
if err := client.Initialise(); err != nil { | ||
log.Fatal(err) | ||
} | ||
// create credentials | ||
credentials := &taiga.Credentials{ | ||
Type: DefaultTaigaHostAuthType, | ||
Username: cfg.Username, | ||
Password: cfg.Password, | ||
} | ||
// set host auth type | ||
if cfg.HostAuthType != "" { | ||
credentials.Type = cfg.HostAuthType | ||
} | ||
// authenticate (get/set token) | ||
if err := client.AuthByCredentials(credentials); err != nil { | ||
log.Fatal(err) | ||
} | ||
// get /users/me | ||
me, _ := client.User.Me() | ||
fmt.Println("Me: (ID, Username, FullName)", me.ID, me.Username, me.FullName) | ||
|
||
// Get Project (by its slug) | ||
// slug := "therivermantaigo-taigo-public-test" | ||
// fmt.Printf("Getting Project (slug=%s)..\n", slug) | ||
// project, err := client.Project.GetBySlug(slug) | ||
// if err != nil { | ||
// fmt.Println(err) | ||
// } | ||
// fmt.Printf("Project name: %s \n\n", project.Name) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
module github.com/theriverman/taigo/cli/passwordbasedencryption | ||
|
||
go 1.19 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,110 @@ | ||
/* | ||
Original author: LucasSloan/passwordbasedencryption | ||
Original GitGub: https://github.com/LucasSloan/passwordbasedencryption | ||
*/ | ||
|
||
package passwordbasedencryption | ||
|
||
import ( | ||
"strings" | ||
|
||
"encoding/base64" | ||
|
||
"crypto/cipher" | ||
"crypto/des" | ||
"crypto/md5" | ||
"crypto/rand" | ||
) | ||
|
||
func getDerivedKey(password string, salt string, count int) ([]byte, []byte) { | ||
key := md5.Sum([]byte(password + salt)) | ||
for i := 0; i < count-1; i++ { | ||
key = md5.Sum(key[:]) | ||
} | ||
return key[:8], key[8:] | ||
} | ||
|
||
func Encrypt(password string, obtenationIterations int, plainText string) (string, error) { | ||
salt := make([]byte, 8) | ||
_, err := rand.Read(salt) | ||
if err != nil { | ||
return "", err | ||
} | ||
|
||
encText, err := doEncrypt(password, plainText, salt, obtenationIterations) | ||
if err != nil { | ||
return "", err | ||
} | ||
|
||
return base64.StdEncoding.EncodeToString(append(salt, encText...)), nil | ||
} | ||
|
||
func Decrypt(password string, obtenationIterations int, cipherText string) (string, error) { | ||
msgBytes, err := base64.StdEncoding.DecodeString(cipherText) | ||
if err != nil { | ||
return "", err | ||
} | ||
|
||
salt := msgBytes[:8] | ||
encText := msgBytes[8:] | ||
return doDecrypt(password, encText, salt, obtenationIterations) | ||
} | ||
|
||
func EncryptWithFixedSalt(password string, obtenationIterations int, plainText string, fixedSalt string) (string, error) { | ||
salt := make([]byte, 8) | ||
copy(salt[:], fixedSalt) | ||
|
||
encText, err := doEncrypt(password, plainText, salt, obtenationIterations) | ||
if err != nil { | ||
return "", err | ||
} | ||
return base64.StdEncoding.EncodeToString(encText), nil | ||
} | ||
|
||
func DecryptWithFixedSalt(password string, obtenationIterations int, cipherText string, fixedSalt string) (string, error) { | ||
msgBytes, err := base64.StdEncoding.DecodeString(cipherText) | ||
if err != nil { | ||
return "", err | ||
} | ||
|
||
salt := make([]byte, 8) | ||
copy(salt[:], fixedSalt) | ||
encText := msgBytes[:] | ||
return doDecrypt(password, encText, salt, obtenationIterations) | ||
} | ||
|
||
func doEncrypt(password, plainText string, salt []byte, obtenationIterations int) ([]byte, error) { | ||
padNum := byte(8 - len(plainText)%8) | ||
for i := byte(0); i < padNum; i++ { | ||
plainText += string(padNum) | ||
} | ||
|
||
dk, iv := getDerivedKey(password, string(salt), obtenationIterations) | ||
block, err := des.NewCipher(dk) | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
encrypter := cipher.NewCBCEncrypter(block, iv) | ||
encrypted := make([]byte, len(plainText)) | ||
encrypter.CryptBlocks(encrypted, []byte(plainText)) | ||
|
||
return encrypted, nil | ||
} | ||
|
||
func doDecrypt(password string, encText, salt []byte, obtenationIterations int) (string, error) { | ||
dk, iv := getDerivedKey(password, string(salt), obtenationIterations) | ||
block, err := des.NewCipher(dk) | ||
|
||
if err != nil { | ||
return "", err | ||
} | ||
|
||
decrypter := cipher.NewCBCDecrypter(block, iv) | ||
decrypted := make([]byte, len(encText)) | ||
decrypter.CryptBlocks(decrypted, encText) | ||
|
||
decryptedString := strings.TrimRight(string(decrypted), "\x01\x02\x03\x04\x05\x06\x07\x08") | ||
|
||
return decryptedString, nil | ||
} |
Oops, something went wrong.