diff --git a/backend/app/Auth/BcryptPasswordHasher.php b/backend/app/Auth/BcryptPasswordHasher.php new file mode 100644 index 0000000..0bc4a46 --- /dev/null +++ b/backend/app/Auth/BcryptPasswordHasher.php @@ -0,0 +1,16 @@ +token; + } + + public function getUser(): User + { + return $this->user; + } + + public function getCreatedAt(): DateTimeImmutable + { + return $this->createdAt; + } + + public function getExpiresAt(): DateTimeImmutable + { + return $this->expiresAt; + } + + public function isExpired(DateTimeImmutable $now): bool + { + return $now >= $this->expiresAt; + } +} diff --git a/backend/app/Auth/SessionRepository.php b/backend/app/Auth/SessionRepository.php new file mode 100644 index 0000000..cabae60 --- /dev/null +++ b/backend/app/Auth/SessionRepository.php @@ -0,0 +1,12 @@ +domain = mb_strtolower($domain); + $normalized = $local.'@'.$this->domain; + + if (filter_var($normalized, FILTER_VALIDATE_EMAIL) === false) { + throw new InvalidArgumentException(self::ERROR_MESSAGE." $email"); + } + + $this->normalized = $normalized; + } + + public function value(): string + { + return $this->normalized; + } + + public function equals(self $other): bool + { + return $this->normalized === $other->normalized; + } + + public function getDomain(): string + { + return $this->domain; + } + + public function __toString(): string + { + return $this->normalized; + } +} diff --git a/backend/app/User/CreateUserDto.php b/backend/app/User/CreateUserDto.php new file mode 100644 index 0000000..d10b373 --- /dev/null +++ b/backend/app/User/CreateUserDto.php @@ -0,0 +1,13 @@ +id; + } + + public function getEmail(): EmailAddress + { + return $this->email; + } + + public function getPasswordHash(): string + { + return $this->passwordHash; + } +} diff --git a/backend/app/User/UserRepository.php b/backend/app/User/UserRepository.php new file mode 100644 index 0000000..975b50d --- /dev/null +++ b/backend/app/User/UserRepository.php @@ -0,0 +1,14 @@ +addDefinitions([ + + // Services + PasswordHasher::class => DI\create(BcryptPasswordHasher::class), + TokenGenerator::class => DI\create(RandomTokenGenerator::class), + Clock::class => DI\create(SystemClock::class), + + // Use cases + AuthenticateUser::class => DI\autowire(), + CreateSession::class => DI\autowire(), + Logout::class => DI\autowire(), + + // HTTP layer + AuthController::class => DI\autowire(), + AuthMiddleware::class => DI\autowire(), + +]); + +return $builder->build(); diff --git a/backend/config/routes.php b/backend/config/routes.php new file mode 100644 index 0000000..cd9f359 --- /dev/null +++ b/backend/config/routes.php @@ -0,0 +1,17 @@ +get('/me', [AuthController::class, 'me']) + ->add(AuthMiddleware::class); + + $app->post('/login', [AuthController::class, 'login']); + + $app->post('/logout', [AuthController::class, 'logout']) + ->add(AuthMiddleware::class); +}; diff --git a/backend/public/index.php b/backend/public/index.php new file mode 100644 index 0000000..0209daf --- /dev/null +++ b/backend/public/index.php @@ -0,0 +1,19 @@ +run(); +})();