0633aca607
We want to send email verification reminders to users from the satellite core, but some of the functionality required to do so exists in the satellite console service. We could simply import the console service into the core to achieve this, but the service requires a lot of dependencies that would go unused just to be able to send these emails. Instead, we break out the needed functionality into a new service which can be imported separately by the console service and the future email chore. The consoleauth service creates, signs, and checks the expiration of auth tokens. Change-Id: I2ad794b7fd256f8af24c1a8d73a203d508069078
91 lines
2.0 KiB
Go
91 lines
2.0 KiB
Go
// Copyright (C) 2022 Storj Labs, Inc.
|
|
// See LICENSE for copying information.
|
|
|
|
package consoleauth
|
|
|
|
import (
|
|
"context"
|
|
"encoding/base64"
|
|
"time"
|
|
|
|
"github.com/spacemonkeygo/monkit/v3"
|
|
|
|
"storj.io/common/uuid"
|
|
)
|
|
|
|
var mon = monkit.Package()
|
|
|
|
// Config contains configuration parameters for console auth.
|
|
type Config struct {
|
|
TokenExpirationTime time.Duration `help:"expiration time for auth tokens, account recovery tokens, and activation tokens" default:"24h"`
|
|
}
|
|
|
|
// Service handles creating, signing, and checking the expiration of auth tokens.
|
|
type Service struct {
|
|
config Config
|
|
Signer
|
|
}
|
|
|
|
// NewService creates a new consoleauth service.
|
|
func NewService(config Config, signer Signer) *Service {
|
|
return &Service{
|
|
config: config,
|
|
Signer: signer,
|
|
}
|
|
}
|
|
|
|
// Signer creates signature for provided data.
|
|
type Signer interface {
|
|
Sign(data []byte) ([]byte, error)
|
|
}
|
|
|
|
// CreateToken creates a new auth token.
|
|
func (s *Service) CreateToken(ctx context.Context, id uuid.UUID, email string) (_ string, err error) {
|
|
defer mon.Task()(&ctx)(&err)
|
|
claims := &Claims{
|
|
ID: id,
|
|
Expiration: time.Now().Add(s.config.TokenExpirationTime),
|
|
}
|
|
if email != "" {
|
|
claims.Email = email
|
|
}
|
|
|
|
return s.createToken(ctx, claims)
|
|
}
|
|
|
|
// createToken creates string representation.
|
|
func (s *Service) createToken(ctx context.Context, claims *Claims) (_ string, err error) {
|
|
defer mon.Task()(&ctx)(&err)
|
|
|
|
json, err := claims.JSON()
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
|
|
token := Token{Payload: json}
|
|
err = s.SignToken(&token)
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
|
|
return token.String(), nil
|
|
}
|
|
|
|
// SignToken signs token.
|
|
func (s *Service) SignToken(token *Token) error {
|
|
encoded := base64.URLEncoding.EncodeToString(token.Payload)
|
|
|
|
signature, err := s.Signer.Sign([]byte(encoded))
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
token.Signature = signature
|
|
return nil
|
|
}
|
|
|
|
// IsExpired returns whether token is expired.
|
|
func (s *Service) IsExpired(now, tokenCreatedAt time.Time) bool {
|
|
return now.Sub(tokenCreatedAt) > s.config.TokenExpirationTime
|
|
}
|