2024-05-07 22:20:50 -07:00
|
|
|
package repositoryservices
|
2024-05-05 10:02:17 -07:00
|
|
|
|
|
|
|
import (
|
|
|
|
"context"
|
|
|
|
"database/sql"
|
|
|
|
"errors"
|
|
|
|
|
2024-05-09 19:09:11 -07:00
|
|
|
"git.jamestombleson.com/jtom38/newsbot-api/internal/entity"
|
2024-05-05 10:02:17 -07:00
|
|
|
"git.jamestombleson.com/jtom38/newsbot-api/internal/repository"
|
|
|
|
"github.com/google/uuid"
|
|
|
|
)
|
|
|
|
|
|
|
|
const (
|
|
|
|
ErrUnexpectedAmountOfRowsUpdated = "got a unexpected of rows updated"
|
|
|
|
)
|
|
|
|
|
|
|
|
type RefreshToken interface {
|
|
|
|
Create(ctx context.Context, username string) (string, error)
|
2024-05-09 19:09:11 -07:00
|
|
|
GetByName(ctx context.Context, name string) (entity.RefreshTokenEntity, error)
|
2024-05-05 10:02:17 -07:00
|
|
|
Delete(ctx context.Context, id int64) (int64, error)
|
|
|
|
IsRequestValid(ctx context.Context, username, refreshToken string) error
|
|
|
|
}
|
|
|
|
|
|
|
|
// A new jwt token can be made if the user has the correct refresh token for the user.
|
|
|
|
// It will also require the old JWT token so the expire time is pulled and part of the validation
|
|
|
|
type RefreshTokenService struct {
|
|
|
|
table repository.RefreshTokenRepository
|
|
|
|
}
|
|
|
|
|
|
|
|
func NewRefreshTokenService(conn *sql.DB) RefreshTokenService {
|
|
|
|
return RefreshTokenService{
|
|
|
|
table: repository.NewRefreshTokenRepository(conn),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func (rt RefreshTokenService) Create(ctx context.Context, username string) (string, error) {
|
|
|
|
//if a refresh token already exists for a user, reuse
|
|
|
|
existingToken, err := rt.GetByName(ctx, username)
|
|
|
|
if err == nil {
|
|
|
|
rowsRemoved, err := rt.Delete(ctx, existingToken.ID)
|
|
|
|
if err != nil {
|
|
|
|
return "", err
|
|
|
|
}
|
|
|
|
|
|
|
|
if rowsRemoved != 1 {
|
|
|
|
return "", errors.New(ErrUnexpectedAmountOfRowsUpdated)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
token, err := uuid.NewV7()
|
|
|
|
if err != nil {
|
|
|
|
return "", err
|
|
|
|
}
|
|
|
|
|
|
|
|
rows, err := rt.table.Create(ctx, username, token.String())
|
|
|
|
if err != nil {
|
|
|
|
return "", err
|
|
|
|
}
|
|
|
|
|
|
|
|
if rows != 1 {
|
|
|
|
return "", errors.New("expected one row but got none")
|
|
|
|
}
|
|
|
|
return token.String(), nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// Find the saved refresh token for a user and return it if it exists
|
2024-05-09 19:09:11 -07:00
|
|
|
func (rt RefreshTokenService) GetByName(ctx context.Context, name string) (entity.RefreshTokenEntity, error) {
|
2024-05-05 10:02:17 -07:00
|
|
|
return rt.table.GetByUsername(ctx, name)
|
|
|
|
}
|
|
|
|
|
|
|
|
// This will request that a object is removed from the database
|
|
|
|
func (rt RefreshTokenService) Delete(ctx context.Context, id int64) (int64, error) {
|
|
|
|
return rt.table.DeleteById(ctx, id)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (rt RefreshTokenService) IsRequestValid(ctx context.Context, username, refreshToken string) error {
|
|
|
|
token, err := rt.GetByName(ctx, username)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
if token.Token != refreshToken {
|
|
|
|
return errors.New("the refresh token given does not match")
|
|
|
|
}
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|