kuma-archive/internal/service/auth.go

180 lines
3.2 KiB
Go

package service
import (
"crypto/rand"
"crypto/sha256"
"encoding/base64"
"encoding/hex"
"fmt"
"os"
"strings"
)
type AuthService struct{}
type Account struct {
Username string
Password string
Salt string
}
func NewAuthService() *AuthService {
return &AuthService{}
}
func init() {
db, err := Open()
if err != nil {
_, _ = fmt.Fprintf(os.Stderr, "%v\n", err)
return
}
defer db.Close()
stmt, err := db.Prepare(strings.TrimSpace(`
create table Account(
username varchar(25),
password varchar(255),
salt varchar(50),
constraint PK_Account_ID primary key(username)
);
`))
if err != nil {
return
}
defer stmt.Close()
if _, err = stmt.Exec(); err != nil {
_, _ = fmt.Fprintf(os.Stderr, "%v\n", err)
return
}
}
func (s *AuthService) Create(data *Account) error {
db, err := Open()
if err != nil {
return err
}
defer db.Close()
stmt, err := db.Prepare("insert into Account values(?, ?, ?);")
if err != nil {
return err
}
defer stmt.Close()
salt := genSalt()
if _, err = stmt.Exec(data.Username, encrypt(data.Password, salt), salt); err != nil {
return err
}
return nil
}
func (s *AuthService) Read(username string) (*Account, error) {
db, err := Open()
if err != nil {
return nil, err
}
defer db.Close()
stmt, err := db.Prepare("select * from Account where username = ?;")
if err != nil {
return nil, err
}
defer stmt.Close()
var account Account
if err := stmt.QueryRow(username).Scan(&account.Username, &account.Password, &account.Salt); err != nil {
return nil, err
}
return &account, nil
}
func (s *AuthService) Update(username, password string) error {
db, err := Open()
if err != nil {
return err
}
defer db.Close()
stmt, err := db.Prepare("update Account set password = ?, salt = ? where username = ?;")
if err != nil {
return err
}
defer stmt.Close()
salt := genSalt()
if _, err = stmt.Exec(encrypt(password, salt), salt, username); err != nil {
return err
}
return nil
}
func (s *AuthService) Delete(username string) error {
db, err := Open()
if err != nil {
return err
}
defer db.Close()
stmt, err := db.Prepare("delete from Account where username = ?;")
if err != nil {
return err
}
defer stmt.Close()
if _, err = stmt.Exec(username); err != nil {
return err
}
return nil
}
func (s *AuthService) Verify(username, password string) (bool, error) {
account, err := s.Read(username)
if err != nil {
return false, err
}
if encrypt(password, account.Salt) == account.Password {
return true, nil
}
return false, nil
}
func (s *AuthService) VerifyToken(username, encryptPw string) (bool, error) {
account, err := s.Read(username)
if err != nil {
return false, err
}
if encryptPw == account.Password {
return true, nil
}
return false, nil
}
func (s *AuthService) Token(username, password string) string {
raw := fmt.Sprintf("%s:%s", username, password)
return base64.StdEncoding.EncodeToString([]byte(raw))
}
func encrypt(password, salt string) string {
hash := sha256.New()
hash.Write([]byte(password + salt))
return hex.EncodeToString(hash.Sum(nil))
}
func genSalt() string {
b := make([]byte, 16)
_, err := rand.Read(b)
if err != nil {
_, _ = fmt.Fprintf(os.Stderr, "%v\n", err)
return ""
}
return hex.EncodeToString(b)
}