/
git_profile.go
169 lines (142 loc) · 4.55 KB
/
git_profile.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
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
package user
import (
"context"
"crypto/aes"
"crypto/cipher"
"crypto/rand"
"encoding/hex"
"errors"
"fmt"
"io"
"log"
"os"
"github.com/artisoft-io/jetstore/jets/awsi"
"github.com/jackc/pgx/v4"
"github.com/jackc/pgx/v4/pgxpool"
)
type GitProfile struct {
Name string `json:"git_name"`
Email string `json:"git_email"`
GitHandle string `json:"git_handle"`
GitToken string `json:"git_token"`
}
var jetsEncriptionKey string
var DevMode bool
func init() {
jetsEncriptionKey = os.Getenv("JETS_ENCRYPTION_KEY")
if jetsEncriptionKey == "" {
log.Println("user.init(): Could not load value for JETS_ENCRYPTION_KEY")
}
AdminEmail = os.Getenv("JETS_ADMIN_EMAIL")
_, DevMode = os.LookupEnv("JETSTORE_DEV_MODE")
// Get secret to sign jwt tokens
var err error
awsApiSecret := os.Getenv("AWS_API_SECRET")
apiSecret := os.Getenv("API_SECRET")
if apiSecret == "" && awsApiSecret != "" {
apiSecret, err = awsi.GetSecretValue(awsApiSecret)
if err != nil {
log.Println("user.init(): could not get secret value for AWS_API_SECRET")
}
}
ApiSecret = apiSecret
TokenExpiration = 60
}
func GetGitProfile(dbpool *pgxpool.Pool, userEmail string) (GitProfile, error) {
var gitProfile GitProfile
stmt := fmt.Sprintf(
"SELECT git_name, git_email, git_handle, git_token FROM jetsapi.users WHERE user_email = '%s'",
userEmail)
err := dbpool.QueryRow(context.Background(), stmt).Scan(
&gitProfile.Name, &gitProfile.Email, &gitProfile.GitHandle, &gitProfile.GitToken)
if err != nil {
if errors.Is(err, pgx.ErrNoRows) {
log.Println("Error user not found")
return gitProfile, errors.New("error: user not found")
}
log.Println("Error while reading user's git profile from users table:", err)
return gitProfile, err
}
// Decrypt the git token
encryptedGitToken := gitProfile.GitToken
gitProfile.GitToken = DecryptGitToken(encryptedGitToken)
return gitProfile, nil
}
// func EncryptWithEmail(dataToEncrypt, email string) string {
// encryptedEmail := encrypt(email, jetsEncriptionKey)
// if len(encryptedEmail) < 32 {
// return ""
// }
// return encrypt(dataToEncrypt, encryptedEmail[:32])
// }
func EncryptGitToken(gitToken string) string {
return encrypt(gitToken, jetsEncriptionKey)
}
// func DecryptWithEmail(encryptedData, email string) string {
// encryptedEmail := encrypt(email, jetsEncriptionKey)
// if len(encryptedEmail) < 32 {
// return ""
// }
// return decrypt(encryptedData, encryptedEmail[:32])
// }
func DecryptGitToken(encryptedGitToken string) string {
return decrypt(encryptedGitToken, jetsEncriptionKey)
}
// From: https://www.melvinvivas.com/how-to-encrypt-and-decrypt-data-using-aes
func encrypt(stringToEncrypt string, keyString string) (encryptedString string) {
if stringToEncrypt == "" || len(keyString) != 32 {
log.Println("ERROR: decrypt called with empty stringToEncrypt or len(key) != 32")
return ""
}
//Since the key is in string, we need to convert decode it to bytes
key := []byte(keyString)
plaintext := []byte(stringToEncrypt)
//Create a new Cipher Block from the key
block, err := aes.NewCipher(key)
if err != nil {
panic(err.Error())
}
//Create a new GCM - https://en.wikipedia.org/wiki/Galois/Counter_Mode
//https://golang.org/pkg/crypto/cipher/#NewGCM
aesGCM, err := cipher.NewGCM(block)
if err != nil {
panic(err.Error())
}
//Create a nonce. Nonce should be from GCM
nonce := make([]byte, aesGCM.NonceSize())
if _, err = io.ReadFull(rand.Reader, nonce); err != nil {
panic(err.Error())
}
//Encrypt the data using aesGCM.Seal
//Since we don't want to save the nonce somewhere else in this case, we add it as a prefix to the encrypted data. The first nonce argument in Seal is the prefix.
ciphertext := aesGCM.Seal(nonce, nonce, plaintext, nil)
return fmt.Sprintf("%x", ciphertext)
}
func decrypt(encryptedString string, keyString string) (decryptedString string) {
if encryptedString == "" || len(keyString) != 32 {
log.Println("ERROR: decrypt called with empty encryptedString or len(key) != 32")
return ""
}
key := []byte(keyString)
enc, _ := hex.DecodeString(encryptedString)
//Create a new Cipher Block from the key
block, err := aes.NewCipher(key)
if err != nil {
panic(err.Error())
}
//Create a new GCM
aesGCM, err := cipher.NewGCM(block)
if err != nil {
panic(err.Error())
}
//Get the nonce size
nonceSize := aesGCM.NonceSize()
//Extract the nonce from the encrypted data
nonce, ciphertext := enc[:nonceSize], enc[nonceSize:]
//Decrypt the data
plaintext, err := aesGCM.Open(nil, nonce, ciphertext, nil)
if err != nil {
panic(err.Error())
}
return string(plaintext)
}