Initial commit
This commit is contained in:
commit
2fa110e760
28 changed files with 2346 additions and 0 deletions
1
internal/services/email.go
Normal file
1
internal/services/email.go
Normal file
|
@ -0,0 +1 @@
|
|||
package services
|
147
internal/services/session.go
Normal file
147
internal/services/session.go
Normal file
|
@ -0,0 +1,147 @@
|
|||
package services
|
||||
|
||||
import (
|
||||
"context"
|
||||
"ms-auth/internal/lib"
|
||||
"ms-auth/internal/storage"
|
||||
)
|
||||
|
||||
type SessionProvider interface {
|
||||
CreateSession(ctx context.Context, userId int32) error
|
||||
ReadSessionByToken(ctx context.Context, token string) (*storage.Session, error)
|
||||
ReadSessionByUserId(ctx context.Context, userId int32) (*storage.Session, error)
|
||||
UpdateSession(ctx context.Context, session *storage.Session) error
|
||||
DeleteSessionByToken(ctx context.Context, token string) error
|
||||
DeleteSessionByUserId(ctx context.Context, userId int32) error
|
||||
}
|
||||
|
||||
// SessionService represents a service for managing sessions.
|
||||
type SessionService struct {
|
||||
sessionProvider SessionProvider
|
||||
userProvider UserProvider
|
||||
cfg *lib.Config
|
||||
}
|
||||
|
||||
// NewSessionService creates a new SessionService instance.
|
||||
//
|
||||
// Parameters:
|
||||
// - sessionProvider: The SessionProvider implementation used by the SessionService.
|
||||
// - userProvider: The UserProvider implementation used by the SessionService.
|
||||
// - cfg: The lib.Config object used by the SessionService.
|
||||
//
|
||||
// Returns:
|
||||
// - *SessionService: A pointer to the SessionService instance.
|
||||
func NewSessionService(sessionProvider SessionProvider, userProvider UserProvider, cfg *lib.Config) *SessionService {
|
||||
return &SessionService{
|
||||
sessionProvider: sessionProvider,
|
||||
userProvider: userProvider,
|
||||
cfg: cfg,
|
||||
}
|
||||
}
|
||||
|
||||
// Create creates a new session for a user with the given handle and password.
|
||||
//
|
||||
// Parameters:
|
||||
// - ctx: The context.Context object for the request.
|
||||
// - handle: The handle (username or email) of the user.
|
||||
// - password: The password of the user.
|
||||
//
|
||||
// Returns:
|
||||
// - *string: A pointer to the token of the newly created session, or nil if there was an error.
|
||||
// - error: An error if the creation of the session or the retrieval of the session's token failed.
|
||||
func (s *SessionService) Create(ctx context.Context, handle, password string) (*string, error) {
|
||||
var (
|
||||
err error
|
||||
user *storage.User
|
||||
)
|
||||
|
||||
if lib.ValidUsername(handle) == nil {
|
||||
user, err = s.userProvider.ReadUserByUsername(ctx, handle)
|
||||
} else if lib.ValidEmail(handle) == nil {
|
||||
user, err = s.userProvider.ReadUserByEmail(ctx, handle)
|
||||
} else {
|
||||
return nil, lib.ErrBadHandleOrPassword
|
||||
}
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
err = user.ComparePassword(password)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
err = s.sessionProvider.CreateSession(ctx, user.Id)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
session, err := s.sessionProvider.ReadSessionByUserId(ctx, user.Id)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
token, err := session.Token(s.cfg.JWTSecret)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &token, nil
|
||||
}
|
||||
|
||||
// Read retrieves the user ID associated with the given session token.
|
||||
//
|
||||
// Parameters:
|
||||
// - ctx: The context.Context object for the request.
|
||||
// - token: The session token.
|
||||
//
|
||||
// Returns:
|
||||
// - *int32: The user ID associated with the session token, or nil if an error occurs.
|
||||
// - error: An error object if any error occurs during the retrieval process.
|
||||
func (s *SessionService) Read(ctx context.Context, token string) (*int32, error) {
|
||||
session, err := s.sessionProvider.ReadSessionByToken(ctx, token)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return session.UserId, nil
|
||||
}
|
||||
|
||||
// Update updates the session associated with the given token.
|
||||
//
|
||||
// Parameters:
|
||||
// - ctx: The context.Context object for the request.
|
||||
// - token: The session token.
|
||||
//
|
||||
// Returns:
|
||||
// - error: An error object if any error occurs during the update process.
|
||||
func (s *SessionService) Update(ctx context.Context, token string) error {
|
||||
session, err := s.sessionProvider.ReadSessionByToken(ctx, token)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = s.sessionProvider.UpdateSession(ctx, session)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Delete deletes the session associated with the given token.
|
||||
//
|
||||
// Parameters:
|
||||
// - ctx: The context.Context object for the request.
|
||||
// - token: The session token.
|
||||
//
|
||||
// Returns:
|
||||
// - error: An error object if any error occurs during the deletion process.
|
||||
func (s *SessionService) Delete(ctx context.Context, token string) error {
|
||||
session, err := s.sessionProvider.ReadSessionByToken(ctx, token)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = s.sessionProvider.DeleteSessionByUserId(ctx, *session.UserId)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
244
internal/services/user.go
Normal file
244
internal/services/user.go
Normal file
|
@ -0,0 +1,244 @@
|
|||
package services
|
||||
|
||||
import (
|
||||
"context"
|
||||
"ms-auth/internal/lib"
|
||||
"ms-auth/internal/storage"
|
||||
"time"
|
||||
)
|
||||
|
||||
type UserProvider interface {
|
||||
CreateUser(
|
||||
ctx context.Context,
|
||||
username string,
|
||||
password string,
|
||||
email *string,
|
||||
expiresAt *time.Time,
|
||||
role *int32,
|
||||
) (*int32, error)
|
||||
ReadUserByEmail(ctx context.Context, email string) (*storage.User, error)
|
||||
ReadUserByUsername(ctx context.Context, username string) (*storage.User, error)
|
||||
ReadUserById(ctx context.Context, id int32) (*storage.User, error)
|
||||
UpdateUser(
|
||||
ctx context.Context,
|
||||
id int32,
|
||||
username *string,
|
||||
password *string,
|
||||
email *string,
|
||||
expiresAt *time.Time,
|
||||
role *int32,
|
||||
) error
|
||||
DeleteUser(ctx context.Context, id int32) error
|
||||
}
|
||||
|
||||
type ConfirmationProvider interface {
|
||||
CreateConfirmation(ctx context.Context, conf *storage.Confirmation) error
|
||||
ReadConfirmation(ctx context.Context, confId string) (*storage.Confirmation, error)
|
||||
DeleteConfirmation(ctx context.Context, confId string) error
|
||||
}
|
||||
|
||||
type EmailProvider interface {
|
||||
SendMail(ctx context.Context, to []string, subject string, body string) error
|
||||
}
|
||||
|
||||
// UserService represents a service for managing users.
|
||||
type UserService struct {
|
||||
userProvider UserProvider
|
||||
sessionProvider SessionProvider
|
||||
confirmationProvider ConfirmationProvider
|
||||
//emailProvider EmailProvider
|
||||
cfg *lib.Config
|
||||
}
|
||||
|
||||
// NewUserService creates a new UserService instance.
|
||||
//
|
||||
// Parameters:
|
||||
// - userProvider: The UserProvider implementation used by the UserService.
|
||||
// - sessionProvider: The SessionProvider implementation used by the UserService.
|
||||
// - confirmationProvider: The ConfirmationProvider implementation used by the UserService.
|
||||
// - emailProvider: The EmailProvider implementation used by the UserService.
|
||||
// - cfg: The lib.Config object used by the UserService.
|
||||
//
|
||||
// Returns:
|
||||
// - *UserService: A pointer to the newly created UserService instance.
|
||||
func NewUserService(
|
||||
userProvider UserProvider,
|
||||
sessionProvider SessionProvider,
|
||||
confirmationProvider ConfirmationProvider,
|
||||
//emailProvider EmailProvider,
|
||||
cfg *lib.Config,
|
||||
) *UserService {
|
||||
return &UserService{
|
||||
userProvider: userProvider,
|
||||
sessionProvider: sessionProvider,
|
||||
confirmationProvider: confirmationProvider,
|
||||
//emailProvider: emailProvider,
|
||||
cfg: cfg,
|
||||
}
|
||||
}
|
||||
|
||||
// CreateUser creates a new user with the provided information.
|
||||
//
|
||||
// Parameters:
|
||||
// - ctx: The context for the operation.
|
||||
// - token: The token associated with the session.
|
||||
// - username: The username of the new user.
|
||||
// - password: The password of the new user.
|
||||
// - email: The email of the new user (can be nil).
|
||||
// - expiresAt: The expiration time for the user account (can be nil).
|
||||
// - role: The role of the new user.
|
||||
//
|
||||
// Returns:
|
||||
// - *int32: The ID of the created user.
|
||||
// - error: An error if the operation fails.
|
||||
func (u *UserService) CreateUser(ctx context.Context, token, username, password string, email *string, expiresAt *time.Time, role *int32) (*int32, error) {
|
||||
user, err := u.ReadUserBySessionToken(ctx, token)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
canCreate := func() bool {
|
||||
if !user.IsAdmin() && !user.IsModerator() {
|
||||
return false
|
||||
}
|
||||
|
||||
if role != nil && user.IsModerator() {
|
||||
if lib.IsModerator(*role) || lib.IsAdmin(*role) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}()
|
||||
|
||||
if !canCreate {
|
||||
return nil, lib.ErrNoPermission
|
||||
}
|
||||
|
||||
return u.userProvider.CreateUser(ctx, username, password, email, expiresAt, role)
|
||||
}
|
||||
|
||||
// ReadUserBySessionToken reads a user by session token.
|
||||
//
|
||||
// Parameters:
|
||||
// - ctx: The context of the request.
|
||||
// - token: The session token to identify the user.
|
||||
//
|
||||
// Returns:
|
||||
// - *storage.User: The user information.
|
||||
// - error: An error if the operation fails.
|
||||
func (u *UserService) ReadUserBySessionToken(ctx context.Context, token string) (*storage.User, error) {
|
||||
session, err := u.sessionProvider.ReadSessionByToken(ctx, token)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return u.userProvider.ReadUserById(ctx, *session.UserId)
|
||||
}
|
||||
|
||||
// ReadUser reads a user by ID.
|
||||
//
|
||||
// Parameters:
|
||||
// - ctx: The context of the request.
|
||||
// - token: The session token to identify the user.
|
||||
// - id: The ID of the user to read.
|
||||
//
|
||||
// Returns:
|
||||
// - *storage.User: The user information.
|
||||
// - error: An error if the operation fails.
|
||||
func (u *UserService) ReadUser(ctx context.Context, token string, id int32) (*storage.User, error) {
|
||||
_, err := u.ReadUserBySessionToken(ctx, token)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return u.userProvider.ReadUserById(ctx, id)
|
||||
}
|
||||
|
||||
// UpdateUser updates a user's information.
|
||||
//
|
||||
// Parameters:
|
||||
// - ctx: The context of the request.
|
||||
// - token: The session token to identify the user.
|
||||
// - id: The ID of the user to update.
|
||||
// - username: The new username (can be nil).
|
||||
// - password: The new password (can be nil).
|
||||
// - email: The new email (can be nil).
|
||||
// - expiresAt: The new expiration time (can be nil).
|
||||
// - role: The new role (can be nil).
|
||||
//
|
||||
// Returns:
|
||||
// - error: An error if the operation fails.
|
||||
func (u *UserService) UpdateUser(
|
||||
ctx context.Context,
|
||||
token string,
|
||||
id int32,
|
||||
username *string,
|
||||
password *string,
|
||||
email *string,
|
||||
expiresAt *time.Time,
|
||||
role *int32,
|
||||
) error {
|
||||
me, err := u.ReadUserBySessionToken(ctx, token)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
user, err := u.userProvider.ReadUserById(ctx, id)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
hasAccess := func() bool {
|
||||
if me.Id == user.Id {
|
||||
return false
|
||||
}
|
||||
if me.IsAdmin() {
|
||||
return true
|
||||
}
|
||||
if me.IsModerator() && (user.IsParticipant() || user.IsSpectator()) {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}()
|
||||
|
||||
if !hasAccess {
|
||||
return lib.ErrNoPermission
|
||||
}
|
||||
|
||||
return u.userProvider.UpdateUser(ctx, id, username, password, email, expiresAt, role)
|
||||
}
|
||||
|
||||
// DeleteUser deletes a user by id.
|
||||
//
|
||||
// Parameters:
|
||||
// - ctx: The context of the request.
|
||||
// - token: The session token to identify the authenticated user.
|
||||
// - id: The ID of the user to delete.
|
||||
//
|
||||
// Returns:
|
||||
// - error: An error if the operation fails.
|
||||
func (u *UserService) DeleteUser(ctx context.Context, token string, id int32) error {
|
||||
user, err := u.ReadUserBySessionToken(ctx, token)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if user.Id == id || !user.IsAdmin() {
|
||||
return lib.ErrNoPermission
|
||||
}
|
||||
|
||||
return u.userProvider.DeleteUser(ctx, id)
|
||||
}
|
||||
|
||||
// ReadUserByEmail reads a user by email.
|
||||
//
|
||||
// Parameters:
|
||||
// - ctx: The context of the request.
|
||||
// - email: The email of the user to read.
|
||||
//
|
||||
// Returns:
|
||||
// - *storage.User: The user information.
|
||||
// - error: An error if the operation fails.
|
||||
func (u *UserService) ReadUserByEmail(ctx context.Context, email string) (*storage.User, error) {
|
||||
return u.userProvider.ReadUserByEmail(ctx, email)
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue