netbird/management/server/personal_access_token.go
2023-03-16 15:57:44 +01:00

65 lines
1.8 KiB
Go

package server
import (
"crypto/sha256"
"fmt"
"hash/crc32"
"time"
"codeberg.org/ac/base62"
b "github.com/hashicorp/go-secure-stdlib/base62"
"github.com/rs/xid"
)
const (
// PATPrefix is the globally used, 4 char prefix for personal access tokens
PATPrefix = "nbp_"
secretLength = 30
PATLength = 40
)
// PersonalAccessToken holds all information about a PAT including a hashed version of it for verification
type PersonalAccessToken struct {
ID string
Description string
HashedToken string
ExpirationDate time.Time
// scope could be added in future
CreatedBy string
CreatedAt time.Time
LastUsed time.Time
}
// CreateNewPAT will generate a new PersonalAccessToken that can be assigned to a User.
// Additionally, it will return the token in plain text once, to give to the user and only save a hashed version
func CreateNewPAT(description string, expirationInDays int, createdBy string) (*PersonalAccessToken, string, error) {
hashedToken, plainToken, err := generateNewToken()
if err != nil {
return nil, "", err
}
currentTime := time.Now().UTC()
return &PersonalAccessToken{
ID: xid.New().String(),
Description: description,
HashedToken: hashedToken,
ExpirationDate: currentTime.AddDate(0, 0, expirationInDays),
CreatedBy: createdBy,
CreatedAt: currentTime,
LastUsed: currentTime,
}, plainToken, nil
}
func generateNewToken() (string, string, error) {
secret, err := b.Random(secretLength)
if err != nil {
return "", "", err
}
checksum := crc32.ChecksumIEEE([]byte(secret))
encodedChecksum := base62.Encode(checksum)
paddedChecksum := fmt.Sprintf("%06s", encodedChecksum)
plainToken := PATPrefix + secret + paddedChecksum
hashedToken := sha256.Sum256([]byte(plainToken))
return string(hashedToken[:]), plainToken, nil
}