cerrado @ 3784181e4fad3c947dfa95081d8a0b34f5be12d4

  1package service
  2
  3import (
  4	"bytes"
  5	"crypto/aes"
  6	"crypto/cipher"
  7	"crypto/rand"
  8	"encoding/base64"
  9	"fmt"
 10	"io"
 11
 12	"golang.org/x/crypto/bcrypt"
 13)
 14
 15type (
 16	AuthService struct {
 17		authRepository authRepository
 18	}
 19
 20	authRepository interface {
 21		GetPassphrase() []byte
 22		GetBase64AesKey() []byte
 23	}
 24)
 25
 26var tokenSeed = []byte("this is a token for cerrado")
 27
 28func NewAuthService(repostiory authRepository) *AuthService {
 29	return &AuthService{
 30		authRepository: repostiory,
 31	}
 32}
 33
 34func (a *AuthService) CheckAuth(username, password string) bool {
 35	passphrase := a.authRepository.GetPassphrase()
 36	pass := []byte(fmt.Sprintf("%s:%s", username, password))
 37
 38	err := bcrypt.CompareHashAndPassword(passphrase, pass)
 39
 40	return err == nil
 41}
 42
 43func (a *AuthService) IssueToken() ([]byte, error) {
 44	// TODO: do this block only once
 45	base := a.authRepository.GetBase64AesKey()
 46
 47	dbuf, err := base64.StdEncoding.DecodeString(string(base))
 48	if err != nil {
 49		return nil, err
 50	}
 51
 52	block, err := aes.NewCipher(dbuf)
 53	if err != nil {
 54		return nil, err
 55	}
 56
 57	gcm, err := cipher.NewGCM(block)
 58	if err != nil {
 59		return nil, err
 60	}
 61
 62	nonce := make([]byte, gcm.NonceSize())
 63	if _, err := io.ReadFull(rand.Reader, nonce); err != nil {
 64		return nil, err
 65	}
 66
 67	ciphertext := gcm.Seal(nonce, nonce, tokenSeed, nil)
 68
 69	return ciphertext, nil
 70}
 71
 72func (a *AuthService) ValidateToken(token []byte) (bool, error) {
 73	base := a.authRepository.GetBase64AesKey()
 74
 75	dbuf, err := base64.StdEncoding.DecodeString(string(base))
 76	if err != nil {
 77		return false, err
 78	}
 79
 80	block, err := aes.NewCipher(dbuf)
 81	if err != nil {
 82		return false, err
 83	}
 84
 85	gcm, err := cipher.NewGCM(block)
 86	if err != nil {
 87		return false, err
 88	}
 89
 90	nonceSize := gcm.NonceSize()
 91	if len(token) < nonceSize {
 92		return false, fmt.Errorf("ciphertext too short")
 93	}
 94
 95	nonce, ciphertext := token[:nonceSize], token[nonceSize:]
 96	plaintext, err := gcm.Open(nil, nonce, ciphertext, nil)
 97	if err != nil {
 98		return false, err
 99	}
100
101	return bytes.Equal(tokenSeed, plaintext), nil
102}
103
104func GenerateHash(username, password string) (string, error) {
105	passphrase := fmt.Sprintf("%s:%s", username, password)
106	bytes, err := bcrypt.GenerateFromPassword([]byte(passphrase), 14)
107	if err != nil {
108		return "", err
109	}
110
111	return string(bytes), nil
112}
113
114func GenerateAesKey() (string, error) {
115	key := make([]byte, 32)
116
117	_, err := rand.Read(key)
118	if err != nil {
119		return "", err
120	}
121
122	return base64.StdEncoding.EncodeToString(key), nil
123}