goshort/internal/service/token/tokenservice.go
Gustavo Maronato f06e933a80
Some checks failed
Build / build (push) Failing after 6m2s
remove unused go stuff
2023-08-30 21:33:57 -03:00

149 lines
4.1 KiB
Go

package tokenservice
import (
"context"
"fmt"
"strings"
"git.maronato.dev/maronato/goshort/internal/errs"
"git.maronato.dev/maronato/goshort/internal/storage"
"git.maronato.dev/maronato/goshort/internal/storage/models"
randomutil "git.maronato.dev/maronato/goshort/internal/util/random"
)
const (
// DefaultTokenLength is the default length of a token.
TokenLength = 32
// TokenPrefix is the prefix of a token.
TokenPrefix = "gst_"
// MinTokenNameLength is the minimum length of a token name.
MinTokenNameLength = 4
// MaxTokenNameLength is the maximum length of a token name.
MaxTokenNameLength = 32
)
// TokenService is the service that handles tokens.
type TokenService struct {
// db is the storage used by the service.
db storage.Storage
}
// NewTokenService creates a new TokenService.
func NewTokenService(db storage.Storage) *TokenService {
return &TokenService{
db: db,
}
}
// FindToken finds a token in the storage using its value.
func (s *TokenService) FindToken(ctx context.Context, value string) (*models.Token, error) {
// Check if the token has the prefix
if !strings.HasPrefix(value, TokenPrefix) {
return &models.Token{}, errs.ErrInvalidToken
}
if len(value) != TokenLength+len(TokenPrefix) {
return &models.Token{}, errs.ErrInvalidToken
}
// Get the token from storage
token, err := s.db.FindToken(ctx, value)
if err != nil {
return token, fmt.Errorf("could not get token from storage: %w", err)
}
return token, nil
}
// FindTokenByID finds a token in the storage using its ID.
func (s *TokenService) FindTokenByID(ctx context.Context, id string) (*models.Token, error) {
// Check if the ID is valid
if !models.LooksLikeID(id) {
return &models.Token{}, errs.ErrInvalidTokenID
}
// Get the token from storage
token, err := s.db.FindTokenByID(ctx, id)
if err != nil {
return token, fmt.Errorf("could not get token from storage: %w", err)
}
return token, nil
}
func (s *TokenService) ListTokens(ctx context.Context, user *models.User) ([]*models.Token, error) {
// Get the tokens from storage
tokens, err := s.db.ListTokens(ctx, user)
if err != nil {
return tokens, fmt.Errorf("could not get tokens from storage: %w", err)
}
return tokens, nil
}
// CreateToken creates a new token for a user.
func (s *TokenService) CreateToken(ctx context.Context, user *models.User, name string) (*models.Token, error) {
if name == "" {
// Make sure the name is valid
name = fmt.Sprintf("%s's token", user.Username)
}
// Generate a new token
token := &models.Token{
Name: name,
Value: TokenPrefix + randomutil.GenerateSecureToken(TokenLength),
UserID: &user.ID,
}
// Create the token in storage
newToken, err := s.db.CreateToken(ctx, token)
if err != nil {
return &models.Token{}, fmt.Errorf("could not create token in storage: %w", err)
}
return newToken, nil
}
// DeleteToken deletes a token from the storage.
func (s *TokenService) DeleteToken(ctx context.Context, token *models.Token) error {
// Delete the token from storage
err := s.db.DeleteToken(ctx, token)
if err != nil {
return fmt.Errorf("could not delete token from storage: %w", err)
}
return nil
}
func (s *TokenService) ChangeTokenName(ctx context.Context, token *models.Token, name string) (*models.Token, error) {
// Make sure the name is valid
if len(name) < MinTokenNameLength || len(name) > MaxTokenNameLength {
return &models.Token{}, errs.ErrInvalidTokenName
}
// Update it
newToken, err := s.db.ChangeTokenName(ctx, token, name)
if err != nil {
return &models.Token{}, fmt.Errorf("could not rename token: %w", err)
}
return newToken, nil
}
// FindTokenUserFromValue finds the user that owns a token.
func (s *TokenService) FindTokenUserFromValue(ctx context.Context, value string) (*models.User, error) {
// Get the token from storage
token, err := s.FindToken(ctx, value)
if err != nil {
return &models.User{}, errs.Errorf("could not get token from storage", err)
}
// Get the user from storage
user, err := s.db.FindUserByID(ctx, *token.UserID)
if err != nil {
return &models.User{}, errs.Errorf("could not get token user from storage", err)
}
return user, nil
}