84 lines
2.5 KiB
Go
84 lines
2.5 KiB
Go
package usecase
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
|
|
"source.toby3d.me/website/indieauth/internal/auth"
|
|
"source.toby3d.me/website/indieauth/internal/domain"
|
|
"source.toby3d.me/website/indieauth/internal/profile"
|
|
"source.toby3d.me/website/indieauth/internal/random"
|
|
"source.toby3d.me/website/indieauth/internal/session"
|
|
)
|
|
|
|
type authUseCase struct {
|
|
config *domain.Config
|
|
profiles profile.Repository
|
|
sessions session.Repository
|
|
}
|
|
|
|
// NewAuthUseCase creates a new authentication use case.
|
|
func NewAuthUseCase(sessions session.Repository, profiles profile.Repository, config *domain.Config) auth.UseCase {
|
|
return &authUseCase{
|
|
config: config,
|
|
profiles: profiles,
|
|
sessions: sessions,
|
|
}
|
|
}
|
|
|
|
func (useCase *authUseCase) Generate(ctx context.Context, opts auth.GenerateOptions) (string, error) {
|
|
code, err := random.String(useCase.config.Code.Length)
|
|
if err != nil {
|
|
return "", fmt.Errorf("cannot generate random code: %w", err)
|
|
}
|
|
|
|
if err = useCase.sessions.Create(ctx, &domain.Session{
|
|
ClientID: opts.ClientID,
|
|
Code: code,
|
|
CodeChallenge: opts.CodeChallenge,
|
|
CodeChallengeMethod: opts.CodeChallengeMethod,
|
|
Me: opts.Me,
|
|
RedirectURI: opts.RedirectURI,
|
|
Scope: opts.Scope,
|
|
}); err != nil {
|
|
return "", fmt.Errorf("cannot save session in store: %w", err)
|
|
}
|
|
|
|
return code, nil
|
|
}
|
|
|
|
func (useCase *authUseCase) Exchange(ctx context.Context, opts auth.ExchangeOptions) (*domain.Me, error) {
|
|
session, err := useCase.sessions.GetAndDelete(ctx, opts.Code)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("cannot find session in store: %w", err)
|
|
}
|
|
|
|
if opts.ClientID.String() != session.ClientID.String() {
|
|
return nil, domain.NewError(
|
|
domain.ErrorCodeInvalidRequest,
|
|
"client's URL MUST match the client_id used in the authentication request",
|
|
"https://indieauth.net/source/#request",
|
|
)
|
|
}
|
|
|
|
if opts.RedirectURI.String() != session.RedirectURI.String() {
|
|
return nil, domain.NewError(
|
|
domain.ErrorCodeInvalidRequest,
|
|
"client's redirect URL MUST match the initial authentication request",
|
|
"https://indieauth.net/source/#request",
|
|
)
|
|
}
|
|
|
|
if session.CodeChallenge != "" &&
|
|
!session.CodeChallengeMethod.Validate(session.CodeChallenge, opts.CodeVerifier) {
|
|
return nil, domain.NewError(
|
|
domain.ErrorCodeInvalidRequest,
|
|
"code_verifier is not hashes to the same value as given in the code_challenge in the original "+
|
|
"authorization request",
|
|
"https://indieauth.net/source/#request",
|
|
)
|
|
}
|
|
|
|
return session.Me, nil
|
|
}
|