diff options
Diffstat (limited to 'pkg/service/auth.go')
-rw-r--r-- | pkg/service/auth.go | 117 |
1 files changed, 117 insertions, 0 deletions
diff --git a/pkg/service/auth.go b/pkg/service/auth.go new file mode 100644 index 0000000..1fbf4b6 --- /dev/null +++ b/pkg/service/auth.go @@ -0,0 +1,117 @@ +package service + +import ( + "bytes" + "crypto/aes" + "crypto/cipher" + "crypto/rand" + "encoding/base64" + "fmt" + "io" + + "golang.org/x/crypto/bcrypt" +) + +type ( + AuthService struct { + authRepository authRepository + } + + authRepository interface { + GetPassphrase() []byte + GetBase64AesKey() []byte + } +) + +var tokenSeed = []byte("cerrado") + +func (a *AuthService) CheckAuth(username, password string) bool { + passphrase := a.authRepository.GetPassphrase() + pass := []byte(fmt.Sprintf("%s:%s", username, password)) + + err := bcrypt.CompareHashAndPassword(passphrase, pass) + + return err == nil +} + +func (a *AuthService) IssueToken() ([]byte, error) { + // TODO: do this block only once + base := a.authRepository.GetBase64AesKey() + + dbuf, err := base64.StdEncoding.DecodeString(string(base)) + if err != nil { + return nil, err + } + + block, err := aes.NewCipher(dbuf) + if err != nil { + return nil, err + } + + gcm, err := cipher.NewGCM(block) + if err != nil { + return nil, err + } + + nonce := make([]byte, gcm.NonceSize()) + if _, err := io.ReadFull(rand.Reader, nonce); err != nil { + return nil, err + } + + ciphertext := gcm.Seal(nonce, nonce, tokenSeed, nil) + + return ciphertext, nil +} + +func (a *AuthService) ValidateToken(token []byte) (bool, error) { + base := a.authRepository.GetBase64AesKey() + + dbuf, err := base64.StdEncoding.DecodeString(string(base)) + if err != nil { + return false, err + } + + block, err := aes.NewCipher(dbuf) + if err != nil { + return false, err + } + + gcm, err := cipher.NewGCM(block) + if err != nil { + return false, err + } + + nonceSize := gcm.NonceSize() + if len(token) < nonceSize { + return false, fmt.Errorf("ciphertext too short") + } + + nonce, ciphertext := token[:nonceSize], token[nonceSize:] + plaintext, err := gcm.Open(nil, nonce, ciphertext, nil) + if err != nil { + return false, err + } + + return bytes.Equal(tokenSeed, plaintext), nil +} + +func GenerateHash(username, password string) (string, error) { + passphrase := fmt.Sprintf("%s:%s", username, password) + bytes, err := bcrypt.GenerateFromPassword([]byte(passphrase), 14) + if err != nil { + return "", err + } + + return string(bytes), nil +} + +func GenerateAesKey() (string, error) { + key := make([]byte, 32) + + _, err := rand.Read(key) + if err != nil { + return "", err + } + + return base64.StdEncoding.EncodeToString(key), nil +} |