Initial commit

This commit is contained in:
new_gate 2024-07-27 07:31:04 +00:00
commit 2fa110e760
28 changed files with 2346 additions and 0 deletions

View file

@ -0,0 +1 @@
package services

View 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
View 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)
}