howmuch/internal/pkg/token/token.go
2024-10-15 10:14:40 +02:00

118 lines
2.9 KiB
Go

// MIT License
//
// Copyright (c) 2024 vinchent <vinchent@vinchent.xyz>
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
package token
import (
"errors"
"fmt"
"sync"
"time"
"github.com/gin-gonic/gin"
"github.com/golang-jwt/jwt/v5"
)
type Config struct {
secretKey string
expiryTime time.Duration
}
type Claims struct {
IdentityKey string `json:"identity_key"`
jwt.RegisteredClaims
}
type TokenResp struct {
Raw string
Identity string
Expiry time.Time
}
var (
once sync.Once
config Config
)
var ErrMissingHeader = errors.New("Authorization is needed in the header")
func Init(secretKey string, expiryTime time.Duration) {
once.Do(func() {
config.secretKey = secretKey
config.expiryTime = expiryTime
})
}
func Sign(identityKey string) (string, error) {
token := jwt.NewWithClaims(jwt.SigningMethodHS256, Claims{
identityKey,
jwt.RegisteredClaims{
ExpiresAt: jwt.NewNumericDate(time.Now().Add(config.expiryTime)),
IssuedAt: jwt.NewNumericDate(time.Now()),
NotBefore: jwt.NewNumericDate(time.Now()),
},
})
return token.SignedString([]byte(config.secretKey))
}
func Parse(tokenString string) (*TokenResp, error) {
token, err := jwt.ParseWithClaims(
tokenString,
&Claims{},
func(t *jwt.Token) (interface{}, error) {
if _, ok := t.Method.(*jwt.SigningMethodHMAC); !ok {
return nil, jwt.ErrSignatureInvalid
}
return []byte(config.secretKey), nil
},
)
if err != nil {
return nil, err
}
if claims, ok := token.Claims.(*Claims); ok {
return &TokenResp{
tokenString,
claims.IdentityKey,
claims.ExpiresAt.Time,
}, nil
}
return nil, nil
}
func ParseRequest(c *gin.Context) (*TokenResp, error) {
// NOTE: Authorization: Bearer sdkfjlsfjlskdfjlsjdflk...slkdfjlka
header := c.GetHeader("Authorization")
if len(header) == 0 {
return nil, ErrMissingHeader
}
// get the token
var t string
fmt.Sscanf(header, "Bearer %s", &t)
return Parse(t)
}