11package models
22
33import (
4+ "crypto/hmac"
5+ "crypto/sha512"
6+ "encoding/hex"
7+ "errors"
8+ "os"
49 "time"
510
611 "gorm.io/gorm"
@@ -14,4 +19,69 @@ type APIKey struct {
1419 Name string
1520 TokenDigest string `gorm:"not null;unique"`
1621 BearerID uint `gorm:"not null"`
22+ Token string `gorm:"-"` // Virtual attribute for raw token value
23+ }
24+
25+ // BeforeCreate is a GORM hook that generates the token digest before creating a new APIKey record
26+ func (apiKey * APIKey ) BeforeCreate (tx * gorm.DB ) (err error ) {
27+ if apiKey .Token == "" {
28+ return errors .New ("token is required" )
29+ }
30+
31+ apiKey .TokenDigest , err = generateTokenHMACDigest (apiKey .Token )
32+ return
33+ }
34+
35+ // AuthenticateByToken finds an API key by its token
36+ func AuthenticateByToken (db * gorm.DB , token string ) (* APIKey , error ) {
37+ return authenticateByToken (db , token , false )
38+ }
39+
40+ // AuthenticateByToken finds an API key by its token and returns an error if not found
41+ func AuthenticateByTokenBang (db * gorm.DB , token string ) (* APIKey , error ) {
42+ return authenticateByToken (db , token , true )
43+ }
44+
45+ func authenticateByToken (db * gorm.DB , token string , bang bool ) (* APIKey , error ) {
46+ digest , err := generateTokenHMACDigest (token )
47+ if err != nil {
48+ return nil , err
49+ }
50+
51+ var apiKey APIKey
52+ var result * gorm.DB
53+ if bang {
54+ result = db .Where ("token_digest = ?" , digest ).First (& apiKey )
55+ } else {
56+ result = db .Where ("token_digest = ?" , digest ).Limit (1 ).Find (& apiKey )
57+ }
58+
59+ if result .Error != nil {
60+ return nil , result .Error
61+ }
62+
63+ if result .RowsAffected == 0 {
64+ return nil , nil // Return nil if no record is found
65+ }
66+
67+ return & apiKey , nil
68+ }
69+
70+ func generateTokenHMACDigest (token string ) (string , error ) {
71+ hmacSecretKey := os .Getenv ("API_KEY_HMAC_SECRET_KEY" )
72+ if hmacSecretKey == "" {
73+ // In test environment, use a default value
74+ if os .Getenv ("GO_ENV" ) == "test" {
75+ hmacSecretKey = "test"
76+ } else {
77+ return "" , errors .New ("API_KEY_HMAC_SECRET_KEY is not set" )
78+ }
79+ }
80+
81+ mac := hmac .New (sha512 .New , []byte (hmacSecretKey ))
82+ _ , err := mac .Write ([]byte (token ))
83+ if err != nil {
84+ return "" , err
85+ }
86+ return hex .EncodeToString (mac .Sum (nil )), nil
1787}
0 commit comments