Compare commits

..

No commits in common. "f0a7b34212d168dbb7d53e34eb107bf51f3beb7e" and "c0739eeddfbb08370b495c8208f2de8c3fe2533d" have entirely different histories.

22 changed files with 242 additions and 140 deletions

View File

@ -16,7 +16,6 @@ class Container
{
static SokoWeb\Interfaces\Database\IConnection $dbConnection;
static SokoWeb\Interfaces\Database\IAuditLogger $auditLogger;
static SokoWeb\Interfaces\PersistentData\IPersistentDataManager $persistentDataManager;
static SokoWeb\Routing\RouteCollection $routeCollection;
static SokoWeb\Interfaces\Session\ISessionHandler $sessionHandler;
static SokoWeb\Interfaces\Request\IRequest $request;
@ -24,4 +23,3 @@ class Container
Container::$dbConnection = new SokoWeb\Database\Mysql\Connection($_ENV['DB_HOST'], $_ENV['DB_USER'], $_ENV['DB_PASSWORD'], $_ENV['DB_NAME']);
Container::$auditLogger = new RVR\Database\AuditLogger(Container::$dbConnection, 'audit_log');
Container::$persistentDataManager = new SokoWeb\PersistentData\PersistentDataManager(Container::$dbConnection, Container::$auditLogger);

View File

@ -10,7 +10,7 @@
}
],
"require": {
"esoko/soko-web": "0.6",
"esoko/soko-web": "0.5",
"firebase/php-jwt": "^6.4"
},
"require-dev": {

8
composer.lock generated
View File

@ -4,15 +4,15 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically"
],
"content-hash": "7b9e3854a5b7ef69d360c1dfbac75c17",
"content-hash": "05dba423c5e5dd40b5a7b9d4180d3673",
"packages": [
{
"name": "esoko/soko-web",
"version": "0.6",
"version": "v0.5",
"source": {
"type": "git",
"url": "https://git.esoko.eu/esoko/soko-web.git",
"reference": "5e0579463cf0f4203c46e0d4f9c09cd283dbf0b8"
"reference": "3893ed22316e84aa4ffab7fbb3d5e823b928b001"
},
"require": {
"phpmailer/phpmailer": "^6.8",
@ -33,7 +33,7 @@
"GNU GPL 3.0"
],
"description": "Lightweight web framework",
"time": "2023-04-19T21:35:03+00:00"
"time": "2023-04-18T21:17:08+00:00"
},
{
"name": "firebase/php-jwt",

View File

@ -1,6 +1,7 @@
<?php namespace RVR\Cli;
use DateTime;
use SokoWeb\PersistentData\PersistentDataManager;
use RVR\PersistentData\Model\OAuthClient;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputArgument;
@ -32,7 +33,8 @@ class AddOAuthClientCommand extends Command
}
try {
\Container::$persistentDataManager->saveToDb($oAuthClient);
$pdm = new PersistentDataManager();
$pdm->saveToDb($oAuthClient);
} catch (\Exception $e) {
$output->writeln('<error>Adding OAuth client failed!</error>');
$output->writeln('');

View File

@ -1,5 +1,6 @@
<?php namespace RVR\Cli;
use SokoWeb\PersistentData\PersistentDataManager;
use RVR\Repository\OAuthClientRepository;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputArgument;
@ -31,7 +32,8 @@ class AddOAuthRedirectUriCommand extends Command
$oAuthClient->setRedirectUrisArray($redirectUris);
try {
\Container::$persistentDataManager->saveToDb($oAuthClient);
$pdm = new PersistentDataManager();
$pdm->saveToDb($oAuthClient);
} catch (\Exception $e) {
$output->writeln('<error>Adding redirect URI failed!</error>');
$output->writeln('');

View File

@ -1,6 +1,7 @@
<?php namespace RVR\Cli;
use DateTime;
use SokoWeb\PersistentData\PersistentDataManager;
use RVR\PersistentData\Model\User;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputArgument;
@ -35,7 +36,8 @@ class AddUserCommand extends Command
}
try {
\Container::$persistentDataManager->saveToDb($user);
$pdm = new PersistentDataManager();
$pdm->saveToDb($user);
} catch (\Exception $e) {
$output->writeln('<error>Adding user failed!</error>');
$output->writeln('');

View File

@ -4,6 +4,7 @@ use DateTime;
use SokoWeb\Database\Query\Modify;
use SokoWeb\Database\Query\Select;
use SokoWeb\Interfaces\Database\IResultSet;
use SokoWeb\PersistentData\PersistentDataManager;
use RVR\Repository\UserPasswordResetterRepository;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputInterface;
@ -11,12 +12,15 @@ use Symfony\Component\Console\Output\OutputInterface;
class MaintainDatabaseCommand extends Command
{
private PersistentDataManager $pdm;
private UserPasswordResetterRepository $userPasswordResetterRepository;
public function __construct()
{
parent::__construct();
$this->pdm = new PersistentDataManager();
$this->userPasswordResetterRepository = new UserPasswordResetterRepository();
}
@ -50,7 +54,7 @@ class MaintainDatabaseCommand extends Command
private function deleteExpiredPasswordResetters(): void
{
foreach ($this->userPasswordResetterRepository->getAllExpired() as $passwordResetter) {
\Container::$persistentDataManager->deleteFromDb($passwordResetter);
$this->pdm->deleteFromDb($passwordResetter);
}
}

View File

@ -1,5 +1,6 @@
<?php namespace RVR\Cli;
use SokoWeb\PersistentData\PersistentDataManager;
use RVR\Repository\OAuthClientRepository;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputArgument;
@ -31,7 +32,8 @@ class RemoveOAuthRedirectUriCommand extends Command
$oAuthClient->setRedirectUrisArray($redirectUris);
try {
\Container::$persistentDataManager->saveToDb($oAuthClient);
$pdm = new PersistentDataManager();
$pdm->saveToDb($oAuthClient);
} catch (\Exception $e) {
$output->writeln('<error>Removing redirect URI failed!</error>');
$output->writeln('');

View File

@ -8,20 +8,28 @@ use RVR\Repository\CommunityRepository;
use RVR\Repository\CommunityMemberRepository;
use RVR\Repository\UserRepository;
use SokoWeb\Interfaces\Authentication\IAuthenticationRequired;
use SokoWeb\Interfaces\Request\IRequest;
use SokoWeb\Interfaces\Response\IContent;
use SokoWeb\PersistentData\PersistentDataManager;
use SokoWeb\Response\HtmlContent;
use SokoWeb\Response\JsonContent;
class CommunityController implements IAuthenticationRequired
{
private IRequest $request;
private PersistentDataManager $pdm;
private UserRepository $userRepository;
private CommunityRepository $communityRepository;
private CommunityMemberRepository $communityMemberRepository;
public function __construct()
public function __construct(IRequest $request)
{
$this->request = $request;
$this->pdm = new PersistentDataManager();
$this->userRepository = new UserRepository();
$this->communityRepository = new CommunityRepository();
$this->communityMemberRepository = new CommunityMemberRepository();
@ -34,7 +42,7 @@ class CommunityController implements IAuthenticationRequired
public function getCommunityHome(): ?IContent
{
if (!$this->checkPermission(\Container::$request->query('communityId'), false, $community, $ownCommunityMember)) {
if (!$this->checkPermission($this->request->query('communityId'), false, $community, $ownCommunityMember)) {
return null;
}
@ -54,7 +62,7 @@ class CommunityController implements IAuthenticationRequired
public function getCommunityEdit(): ?IContent
{
if (!$this->checkPermission(\Container::$request->query('communityId'), true, $community, $ownCommunityMember)) {
if (!$this->checkPermission($this->request->query('communityId'), true, $community, $ownCommunityMember)) {
return null;
}
@ -65,7 +73,7 @@ class CommunityController implements IAuthenticationRequired
public function getMembersEdit(): ?IContent
{
if (!$this->checkPermission(\Container::$request->query('communityId'), true, $community, $ownCommunityMember)) {
if (!$this->checkPermission($this->request->query('communityId'), true, $community, $ownCommunityMember)) {
return null;
}
@ -87,60 +95,60 @@ class CommunityController implements IAuthenticationRequired
public function newMember(): ?IContent
{
if (!$this->checkPermission(\Container::$request->query('communityId'), true, $community, $ownCommunityMember)) {
if (!$this->checkPermission($this->request->query('communityId'), true, $community, $ownCommunityMember)) {
return null;
}
$user = $this->userRepository->getById(\Container::$request->post('user_id'));
$user = $this->userRepository->getById($this->request->post('user_id'));
$communityMember = new CommunityMember();
$communityMember->setCommunity($community);
$communityMember->setUser($user);
\Container::$persistentDataManager->saveToDb($communityMember);
$this->pdm->saveToDb($communityMember);
return new JsonContent(['success' => true]);
}
public function editMember(): ?IContent
{
if (!$this->checkPermission(\Container::$request->query('communityId'), true, $community, $ownCommunityMember)) {
if (!$this->checkPermission($this->request->query('communityId'), true, $community, $ownCommunityMember)) {
return null;
}
$communityMember = $this->communityMemberRepository->getById(\Container::$request->post('community_member_id'));
if ($communityMember->getUserId() === \Container::$request->user()->getUniqueId()) {
$communityMember = $this->communityMemberRepository->getById($this->request->post('community_member_id'));
if ($communityMember->getUserId() === $this->request->user()->getUniqueId()) {
return new JsonContent([
'error' => ['errorText' => 'Own user cannot be edited.']
]);
}
$communityMember->setOwner(\Container::$request->post('owner'));
\Container::$persistentDataManager->saveToDb($communityMember);
$communityMember->setOwner($this->request->post('owner'));
$this->pdm->saveToDb($communityMember);
return new JsonContent(['success' => true]);
}
public function deleteMember(): ?IContent
{
if (!$this->checkPermission(\Container::$request->query('communityId'), true, $community, $ownCommunityMember)) {
if (!$this->checkPermission($this->request->query('communityId'), true, $community, $ownCommunityMember)) {
return null;
}
$communityMember = $this->communityMemberRepository->getById(\Container::$request->post('community_member_id'));
if ($communityMember->getUserId() === \Container::$request->user()->getUniqueId()) {
$communityMember = $this->communityMemberRepository->getById($this->request->post('community_member_id'));
if ($communityMember->getUserId() === $this->request->user()->getUniqueId()) {
return new JsonContent([
'error' => ['errorText' => 'Own user cannot be deleted.']
]);
}
\Container::$persistentDataManager->deleteFromDb($communityMember);
$this->pdm->deleteFromDb($communityMember);
return new JsonContent(['success' => true]);
}
public function saveCommunity(): ?IContent
{
$communityId = \Container::$request->query('communityId');
$communityId = $this->request->query('communityId');
if ($communityId){
if (!$this->checkPermission($communityId, true, $community, $ownCommunityMember)) {
return null;
@ -149,8 +157,8 @@ class CommunityController implements IAuthenticationRequired
$community = new Community();
}
$name = \Container::$request->post('name');
$currency = \Container::$request->post('currency');
$name = $this->request->post('name');
$currency = $this->request->post('currency');
if (strlen($name) === 0 || strlen($currency) === 0 || strlen($currency) > 3) {
return new JsonContent([
'error' => ['errorText' => 'Please fill all required fields!']
@ -162,19 +170,19 @@ class CommunityController implements IAuthenticationRequired
if (!$communityId) {
$community->setCreatedDate(new DateTime());
}
\Container::$persistentDataManager->saveToDb($community);
$this->pdm->saveToDb($community);
if (!$communityId) {
/**
* @var User $user
*/
$user = \Container::$request->user();
$user = $this->request->user();
$communityMember = new CommunityMember();
$communityMember->setCommunity($community);
$communityMember->setUser($user);
$communityMember->setOwner(true);
\Container::$persistentDataManager->saveToDb($communityMember);
$this->pdm->saveToDb($communityMember);
}
return new JsonContent([
@ -196,7 +204,7 @@ class CommunityController implements IAuthenticationRequired
/**
* @var User $user
*/
$user = \Container::$request->user();
$user = $this->request->user();
$ownCommunityMember = $this->communityMemberRepository->getByCommunityAndUser($community, $user);
if ($ownCommunityMember === null || ($needToBeOwner && !$ownCommunityMember->getOwner())) {

View File

@ -3,15 +3,19 @@
use RVR\PersistentData\Model\User;
use RVR\Repository\CommunityMemberRepository;
use SokoWeb\Interfaces\Authentication\IAuthenticationRequired;
use SokoWeb\Interfaces\Request\IRequest;
use SokoWeb\Interfaces\Response\IContent;
use SokoWeb\Response\HtmlContent;
class HomeController implements IAuthenticationRequired
{
private IRequest $request;
private CommunityMemberRepository $communityMemberRepository;
public function __construct()
public function __construct(IRequest $request)
{
$this->request = $request;
$this->communityMemberRepository = new CommunityMemberRepository();
}
@ -25,7 +29,7 @@ class HomeController implements IAuthenticationRequired
/**
* @var User $user
*/
$user = \Container::$request->user();
$user = $this->request->user();
$ownCommunityMembers = $this->communityMemberRepository->getAllByUser($user, true);
$communities = [];

View File

@ -2,11 +2,13 @@
use DateTime;
use SokoWeb\Http\Request;
use SokoWeb\Interfaces\Request\IRequest;
use SokoWeb\Interfaces\Response\IContent;
use SokoWeb\Interfaces\Response\IRedirect;
use SokoWeb\Mailing\Mail;
use SokoWeb\OAuth\GoogleOAuth;
use RVR\PersistentData\Model\UserPasswordResetter;
use SokoWeb\PersistentData\PersistentDataManager;
use RVR\Repository\UserPasswordResetterRepository;
use RVR\Repository\UserRepository;
use SokoWeb\Response\HtmlContent;
@ -17,24 +19,30 @@ use SokoWeb\Util\JwtParser;
class LoginController
{
private IRequest $request;
private PersistentDataManager $pdm;
private UserRepository $userRepository;
private UserPasswordResetterRepository $userPasswordResetterRepository;
private string $redirectUrl;
public function __construct()
public function __construct(IRequest $request)
{
$this->request = $request;
$this->pdm = new PersistentDataManager();
$this->userRepository = new UserRepository();
$this->userPasswordResetterRepository = new UserPasswordResetterRepository();
$this->redirectUrl = \Container::$request->session()->has('redirect_after_login') ?
\Container::$request->session()->get('redirect_after_login') :
$this->redirectUrl = $this->request->session()->has('redirect_after_login') ?
$this->request->session()->get('redirect_after_login') :
\Container::$routeCollection->getRoute('home')->generateLink();
}
public function getLoginForm()
{
if (\Container::$request->user() !== null) {
if ($this->request->user() !== null) {
$this->deleteRedirectUrl();
return new Redirect($this->redirectUrl, IRedirect::TEMPORARY);
}
@ -47,13 +55,13 @@ class LoginController
$state = bin2hex(random_bytes(16));
$nonce = bin2hex(random_bytes(16));
\Container::$request->session()->set('oauth_state', $state);
\Container::$request->session()->set('oauth_nonce', $nonce);
$this->request->session()->set('oauth_state', $state);
$this->request->session()->set('oauth_nonce', $nonce);
$oAuth = new GoogleOAuth(new Request());
$url = $oAuth->getDialogUrl(
$state,
\Container::$request->getBase() . \Container::$routeCollection->getRoute('login-google-action')->generateLink(),
$this->request->getBase() . \Container::$routeCollection->getRoute('login-google-action')->generateLink(),
$nonce
);
@ -62,12 +70,12 @@ class LoginController
public function getRequestPasswordResetForm()
{
if (\Container::$request->user() !== null) {
if ($this->request->user() !== null) {
$this->deleteRedirectUrl();
return new Redirect($this->redirectUrl, IRedirect::TEMPORARY);
}
return new HtmlContent('login/password_reset_request', ['email' => \Container::$request->query('email')]);
return new HtmlContent('login/password_reset_request', ['email' => $this->request->query('email')]);
}
public function getRequestPasswordResetSuccess(): IContent
@ -77,12 +85,12 @@ class LoginController
public function getResetPasswordForm()
{
if (\Container::$request->user() !== null) {
if ($this->request->user() !== null) {
$this->deleteRedirectUrl();
return new Redirect($this->redirectUrl, IRedirect::TEMPORARY);
}
$token = \Container::$request->query('token');
$token = $this->request->query('token');
$resetter = $this->userPasswordResetterRepository->getByToken($token);
if ($resetter === null || $resetter->getExpiresDate() < new DateTime()) {
@ -96,22 +104,22 @@ class LoginController
public function login(): IContent
{
if (\Container::$request->user() !== null) {
if ($this->request->user() !== null) {
$this->deleteRedirectUrl();
return new JsonContent(['success' => true]);
}
$user = $this->userRepository->getByEmailOrUsername(\Container::$request->post('email'));
if ($user === null || !$user->checkPassword(\Container::$request->post('password'))) {
$user = $this->userRepository->getByEmailOrUsername($this->request->post('email'));
if ($user === null || !$user->checkPassword($this->request->post('password'))) {
return new JsonContent([
'error' => [
'errorText' => 'No user found with the given email address / username or the given password is wrong. You can <a href="' .
\Container::$routeCollection->getRoute('password-requestReset')->generateLink(['email' => \Container::$request->post('email')]) . '" title="Request password reset">request password reset</a>!'
\Container::$routeCollection->getRoute('password-requestReset')->generateLink(['email' => $this->request->post('email')]) . '" title="Request password reset">request password reset</a>!'
]
]);
}
\Container::$request->setUser($user);
$this->request->setUser($user);
$this->deleteRedirectUrl();
return new JsonContent(['success' => true]);
@ -121,19 +129,19 @@ class LoginController
{
$defaultError = 'Authentication with Google failed. Please <a href="' . \Container::$routeCollection->getRoute('login-google')->generateLink() . '" title="Login with Google">try again</a>!';
if (\Container::$request->user() !== null) {
if ($this->request->user() !== null) {
$this->deleteRedirectUrl();
return new Redirect($this->redirectUrl, IRedirect::TEMPORARY);
}
if (\Container::$request->query('state') !== \Container::$request->session()->get('oauth_state')) {
if ($this->request->query('state') !== $this->request->session()->get('oauth_state')) {
return new HtmlContent('login/google_login_error', ['error' => $defaultError]);
}
$oAuth = new GoogleOAuth(new Request());
$tokenData = $oAuth->getToken(
\Container::$request->query('code'),
\Container::$request->getBase() . \Container::$routeCollection->getRoute('login-google-action')->generateLink()
$this->request->query('code'),
$this->request->getBase() . \Container::$routeCollection->getRoute('login-google-action')->generateLink()
);
if (!isset($tokenData['id_token'])) {
@ -143,7 +151,7 @@ class LoginController
$jwtParser = new JwtParser($tokenData['id_token']);
$idToken = $jwtParser->getPayload();
if ($idToken['nonce'] !== \Container::$request->session()->get('oauth_nonce')) {
if ($idToken['nonce'] !== $this->request->session()->get('oauth_nonce')) {
return new HtmlContent('login/google_login_error', ['error' => $defaultError]);
}
@ -156,7 +164,7 @@ class LoginController
return new HtmlContent('login/google_login_error', ['error' => 'No user found for this Google account.']);
}
\Container::$request->setUser($user);
$this->request->setUser($user);
$this->deleteRedirectUrl();
return new Redirect($this->redirectUrl, IRedirect::TEMPORARY);
@ -164,14 +172,14 @@ class LoginController
public function logout(): IRedirect
{
\Container::$request->setUser(null);
$this->request->setUser(null);
return new Redirect(\Container::$routeCollection->getRoute('home')->generateLink(), IRedirect::TEMPORARY);
}
public function requestPasswordReset(): IContent
{
if (\Container::$request->user() !== null) {
if ($this->request->user() !== null) {
$this->deleteRedirectUrl();
return new JsonContent([
'redirect' => [
@ -181,18 +189,18 @@ class LoginController
}
if (!empty($_ENV['RECAPTCHA_SITEKEY'])) {
if (!\Container::$request->post('g-recaptcha-response')) {
if (!$this->request->post('g-recaptcha-response')) {
return new JsonContent(['error' => ['errorText' => 'Please check "I\'m not a robot" in the reCAPTCHA box!']]);
}
$captchaValidator = new CaptchaValidator();
$captchaResponse = $captchaValidator->validate(\Container::$request->post('g-recaptcha-response'));
$captchaResponse = $captchaValidator->validate($this->request->post('g-recaptcha-response'));
if (!$captchaResponse['success']) {
return new JsonContent(['error' => ['errorText' => 'reCAPTCHA challenge failed. Please try again!']]);
}
}
$user = $this->userRepository->getByEmailOrUsername(\Container::$request->post('email'));
$user = $this->userRepository->getByEmailOrUsername($this->request->post('email'));
if ($user === null) {
return new JsonContent([
'error' => [
@ -219,10 +227,10 @@ class LoginController
$passwordResetter->setExpiresDate($expires);
if ($existingResetter !== null) {
\Container::$persistentDataManager->deleteFromDb($existingResetter);
$this->pdm->deleteFromDb($existingResetter);
}
\Container::$persistentDataManager->saveToDb($passwordResetter);
$this->pdm->saveToDb($passwordResetter);
$this->sendPasswordResetEmail($user->getEmail(), $token, $expires);
@ -231,7 +239,7 @@ class LoginController
public function resetPassword(): IContent
{
if (\Container::$request->user() !== null) {
if ($this->request->user() !== null) {
$this->deleteRedirectUrl();
return new JsonContent([
'redirect' => [
@ -240,7 +248,7 @@ class LoginController
]);
}
$token = \Container::$request->query('token');
$token = $this->request->query('token');
$resetter = $this->userPasswordResetterRepository->getByToken($token);
if ($resetter === null || $resetter->getExpiresDate() < new DateTime()) {
@ -251,7 +259,7 @@ class LoginController
]);
}
if (strlen(\Container::$request->post('password')) < 6) {
if (strlen($this->request->post('password')) < 6) {
return new JsonContent([
'error' => [
'errorText' => 'The given password is too short. Please choose a password that is at least 6 characters long!'
@ -259,18 +267,18 @@ class LoginController
]);
}
if (\Container::$request->post('password') !== \Container::$request->post('password_confirm')) {
if ($this->request->post('password') !== $this->request->post('password_confirm')) {
return new JsonContent(['error' => ['errorText' => 'The given passwords do not match.']]);
}
\Container::$persistentDataManager->deleteFromDb($resetter);
$this->pdm->deleteFromDb($resetter);
$user = $this->userRepository->getById($resetter->getUserId());
$user->setPlainPassword(\Container::$request->post('password'));
$user->setPlainPassword($this->request->post('password'));
\Container::$persistentDataManager->saveToDb($user);
$this->pdm->saveToDb($user);
\Container::$request->setUser($user);
$this->request->setUser($user);
$this->deleteRedirectUrl();
return new JsonContent(['success' => true]);
@ -283,7 +291,7 @@ class LoginController
$mail->setSubject($_ENV['APP_NAME'] . ' - Password reset');
$mail->setBodyFromTemplate('password-reset', [
'EMAIL' => $email,
'RESET_LINK' => \Container::$request->getBase() .
'RESET_LINK' => $this->request->getBase() .
\Container::$routeCollection->getRoute('password-reset')->generateLink(['token' => $token]),
'EXPIRES' => $expires->format('Y-m-d H:i T')
]);
@ -292,6 +300,6 @@ class LoginController
private function deleteRedirectUrl(): void
{
\Container::$request->session()->delete('redirect_after_login');
$this->request->session()->delete('redirect_after_login');
}
}

View File

@ -5,16 +5,24 @@ use RVR\PersistentData\Model\OAuthToken;
use RVR\PersistentData\Model\User;
use RVR\Repository\OAuthClientRepository;
use SokoWeb\Interfaces\Authentication\IAuthenticationRequired;
use SokoWeb\Interfaces\Request\IRequest;
use SokoWeb\Interfaces\Response\IRedirect;
use SokoWeb\Response\Redirect;
use SokoWeb\PersistentData\PersistentDataManager;
use SokoWeb\Response\HtmlContent;
class OAuthAuthController implements IAuthenticationRequired
{
private IRequest $request;
private PersistentDataManager $pdm;
private OAuthClientRepository $oAuthClientRepository;
public function __construct()
public function __construct(IRequest $request)
{
$this->request = $request;
$this->pdm = new PersistentDataManager();
$this->oAuthClientRepository = new OAuthClientRepository();
}
@ -25,11 +33,11 @@ class OAuthAuthController implements IAuthenticationRequired
public function auth()
{
$redirectUri = \Container::$request->query('redirect_uri');
$clientId = \Container::$request->query('client_id');
$scope = \Container::$request->query('scope') ? \Container::$request->query('scope'): '';
$state = \Container::$request->query('state');
$nonce = \Container::$request->query('nonce') ? \Container::$request->query('nonce'): '';
$redirectUri = $this->request->query('redirect_uri');
$clientId = $this->request->query('client_id');
$scope = $this->request->query('scope') ? $this->request->query('scope'): '';
$state = $this->request->query('state');
$nonce = $this->request->query('nonce') ? $this->request->query('nonce'): '';
if (!$clientId || !$redirectUri || !$state) {
return new HtmlContent('oauth/oauth_error', ['error' => 'An invalid request was made. Please start authentication again.']);
@ -54,7 +62,7 @@ class OAuthAuthController implements IAuthenticationRequired
/**
* @var ?User $user
*/
$user = \Container::$request->user();
$user = $this->request->user();
$code = bin2hex(random_bytes(16));
$accessToken = bin2hex(random_bytes(16));
@ -66,7 +74,7 @@ class OAuthAuthController implements IAuthenticationRequired
$token->setAccessToken($accessToken);
$token->setCreatedDate(new DateTime());
$token->setExpiresDate(new DateTime('+5 minutes'));
\Container::$persistentDataManager->saveToDb($token);
$this->pdm->saveToDb($token);
$redirectUriQuery = array_merge($redirectUriQuery, [
'state' => $state,

View File

@ -6,19 +6,23 @@ use RVR\Repository\OAuthTokenRepository;
use RVR\Repository\UserRepository;
use RVR\PersistentData\Model\User;
use RVR\Repository\OAuthClientRepository;
use SokoWeb\Interfaces\Request\IRequest;
use SokoWeb\Interfaces\Response\IContent;
use SokoWeb\Response\JsonContent;
class OAuthController
{
private IRequest $request;
private OAuthClientRepository $oAuthClientRepository;
private OAuthTokenRepository $oAuthTokenRepository;
private UserRepository $userRepository;
public function __construct()
public function __construct(IRequest $request)
{
$this->request = $request;
$this->oAuthClientRepository = new OAuthClientRepository();
$this->oAuthTokenRepository = new OAuthTokenRepository();
$this->userRepository = new UserRepository();
@ -26,9 +30,9 @@ class OAuthController
public function getToken(): ?IContent
{
$clientId = \Container::$request->post('client_id');
$clientSecret = \Container::$request->post('client_secret');
$code = \Container::$request->post('code');
$clientId = $this->request->post('client_id');
$clientSecret = $this->request->post('client_secret');
$code = $this->request->post('code');
if (!$clientId || !$clientSecret || !$code) {
return new JsonContent([
@ -76,7 +80,7 @@ class OAuthController
public function getUserInfo() : IContent
{
$authorization = \Container::$request->header('Authorization');
$authorization = $this->request->header('Authorization');
if ($authorization === null) {
return new JsonContent([
'error' => 'No Authorization header was sent.'
@ -104,10 +108,10 @@ class OAuthController
{
return new JsonContent([
'issuer' => $_ENV['APP_URL'],
'authorization_endpoint' => \Container::$request->getBase() . \Container::$routeCollection->getRoute('oauth-auth')->generateLink(),
'token_endpoint' => \Container::$request->getBase() . \Container::$routeCollection->getRoute('oauth-token')->generateLink(),
'userinfo_endpoint' => \Container::$request->getBase() . \Container::$routeCollection->getRoute('oauth-userinfo')->generateLink(),
'jwks_uri' => \Container::$request->getBase() . \Container::$routeCollection->getRoute('oauth-certs')->generateLink(),
'authorization_endpoint' => $this->request->getBase() . \Container::$routeCollection->getRoute('oauth-auth')->generateLink(),
'token_endpoint' => $this->request->getBase() . \Container::$routeCollection->getRoute('oauth-token')->generateLink(),
'userinfo_endpoint' => $this->request->getBase() . \Container::$routeCollection->getRoute('oauth-userinfo')->generateLink(),
'jwks_uri' => $this->request->getBase() . \Container::$routeCollection->getRoute('oauth-certs')->generateLink(),
'response_types_supported' =>
[
'code',

View File

@ -3,9 +3,11 @@
use DateTime;
use SokoWeb\Http\Request;
use SokoWeb\Interfaces\Authentication\IAuthenticationRequired;
use SokoWeb\Interfaces\Request\IRequest;
use SokoWeb\Interfaces\Response\IContent;
use SokoWeb\Interfaces\Response\IRedirect;
use SokoWeb\OAuth\GoogleOAuth;
use SokoWeb\PersistentData\PersistentDataManager;
use RVR\PersistentData\Model\User;
use SokoWeb\Response\HtmlContent;
use SokoWeb\Response\JsonContent;
@ -15,10 +17,16 @@ use RVR\Repository\UserRepository;
class UserController implements IAuthenticationRequired
{
private IRequest $request;
private PersistentDataManager $pdm;
private UserRepository $userRepository;
public function __construct()
public function __construct(IRequest $request)
{
$this->request = $request;
$this->pdm = new PersistentDataManager();
$this->userRepository = new UserRepository();
}
@ -32,7 +40,7 @@ class UserController implements IAuthenticationRequired
/**
* @var User $user
*/
$user = \Container::$request->user();
$user = $this->request->user();
return new HtmlContent('account/account', ['user' => $user->toArray()]);
}
@ -42,19 +50,19 @@ class UserController implements IAuthenticationRequired
/**
* @var User $user
*/
$user = \Container::$request->user();
$user = $this->request->user();
$state = bin2hex(random_bytes(16));
$nonce = bin2hex(random_bytes(16));
\Container::$request->session()->set('oauth_state', $state);
\Container::$request->session()->set('oauth_nonce', $nonce);
$this->request->session()->set('oauth_state', $state);
$this->request->session()->set('oauth_nonce', $nonce);
$oAuth = new GoogleOAuth(new Request());
$url = $oAuth->getDialogUrl(
$state,
\Container::$request->getBase() . \Container::$routeCollection->getRoute('account.googleAuthenticate-action')->generateLink(),
$this->request->getBase() . \Container::$routeCollection->getRoute('account.googleAuthenticate-action')->generateLink(),
$nonce,
$user->getEmail()
);
@ -67,16 +75,16 @@ class UserController implements IAuthenticationRequired
/**
* @var User $user
*/
$user = \Container::$request->user();
$user = $this->request->user();
if (\Container::$request->query('state') !== \Container::$request->session()->get('oauth_state')) {
if ($this->request->query('state') !== $this->request->session()->get('oauth_state')) {
return new HtmlContent('account/google_authenticate', ['success' => false]);
}
$oAuth = new GoogleOAuth(new Request());
$tokenData = $oAuth->getToken(
\Container::$request->query('code'),
\Container::$request->getBase() . \Container::$routeCollection->getRoute('account.googleAuthenticate-action')->generateLink()
$this->request->query('code'),
$this->request->getBase() . \Container::$routeCollection->getRoute('account.googleAuthenticate-action')->generateLink()
);
if (!isset($tokenData['id_token'])) {
@ -86,7 +94,7 @@ class UserController implements IAuthenticationRequired
$jwtParser = new JwtParser($tokenData['id_token']);
$idToken = $jwtParser->getPayload();
if ($idToken['nonce'] !== \Container::$request->session()->get('oauth_nonce')) {
if ($idToken['nonce'] !== $this->request->session()->get('oauth_nonce')) {
return new HtmlContent('account/google_authenticate', ['success' => false]);
}
@ -98,7 +106,7 @@ class UserController implements IAuthenticationRequired
}
$authenticatedWithGoogleUntil = new DateTime('+45 seconds');
\Container::$request->session()->set('authenticated_with_google_until', $authenticatedWithGoogleUntil);
$this->request->session()->set('authenticated_with_google_until', $authenticatedWithGoogleUntil);
return new HtmlContent('account/google_authenticate', [
'success' => true,
@ -111,18 +119,18 @@ class UserController implements IAuthenticationRequired
/**
* @var User $user
*/
$user = \Container::$request->user();
$user = $this->request->user();
if (!$this->confirmUserIdentity(
$user,
\Container::$request->session()->get('authenticated_with_google_until'),
\Container::$request->post('password'),
$this->request->session()->get('authenticated_with_google_until'),
$this->request->post('password'),
$error
)) {
return new JsonContent(['error' => ['errorText' => $error]]);
}
$newEmail = \Container::$request->post('email');
$newEmail = $this->request->post('email');
if ($newEmail !== $user->getEmail()) {
if (!filter_var($newEmail, FILTER_VALIDATE_EMAIL)) {
return new JsonContent(['error' => ['errorText' => 'Please provide a valid email address.']]);
@ -135,7 +143,7 @@ class UserController implements IAuthenticationRequired
$user->setEmail($newEmail);
}
$newUsername = \Container::$request->post('username');
$newUsername = $this->request->post('username');
if ($newUsername !== $user->getUsername()) {
if (strlen($newUsername) > 0) {
if (filter_var($newUsername, FILTER_VALIDATE_EMAIL)) {
@ -152,7 +160,7 @@ class UserController implements IAuthenticationRequired
}
}
$newPassword = \Container::$request->post('password_new');
$newPassword = $this->request->post('password_new');
if (strlen($newPassword) > 0) {
if (strlen($newPassword) < 6) {
return new JsonContent([
@ -162,7 +170,7 @@ class UserController implements IAuthenticationRequired
]);
}
if ($newPassword !== \Container::$request->post('password_new_confirm')) {
if ($newPassword !== $this->request->post('password_new_confirm')) {
return new JsonContent([
'error' => [
'errorText' => 'The given new passwords do not match.'
@ -173,13 +181,13 @@ class UserController implements IAuthenticationRequired
$user->setPlainPassword($newPassword);
}
$user->setNickname(\Container::$request->post('nickname'));
$user->setPhone(\Container::$request->post('phone'));
$user->setIdNumber(\Container::$request->post('id_number'));
$user->setNickname($this->request->post('nickname'));
$user->setPhone($this->request->post('phone'));
$user->setIdNumber($this->request->post('id_number'));
\Container::$persistentDataManager->saveToDb($user);
$this->pdm->saveToDb($user);
\Container::$request->session()->delete('authenticated_with_google_until');
$this->request->session()->delete('authenticated_with_google_until');
return new JsonContent(['success' => true]);
}

View File

@ -2,15 +2,19 @@
use RVR\Repository\UserRepository;
use SokoWeb\Interfaces\Authentication\IAuthenticationRequired;
use SokoWeb\Interfaces\Request\IRequest;
use SokoWeb\Interfaces\Response\IContent;
use SokoWeb\Response\JsonContent;
class UserSearchController implements IAuthenticationRequired
{
private IRequest $request;
private UserRepository $userRepository;
public function __construct()
public function __construct(IRequest $request)
{
$this->request = $request;
$this->userRepository = new UserRepository();
}
@ -21,7 +25,7 @@ class UserSearchController implements IAuthenticationRequired
public function searchUser(): IContent
{
$users = iterator_to_array($this->userRepository->searchByName(\Container::$request->query('q')));
$users = iterator_to_array($this->userRepository->searchByName($this->request->query('q')));
usort($users, function($a, $b) {
return strnatcmp($a->getDisplayName(), $b->getDisplayName());
});

View File

@ -5,12 +5,20 @@ use RVR\PersistentData\Model\Community;
use RVR\PersistentData\Model\CommunityMember;
use RVR\PersistentData\Model\User;
use SokoWeb\Database\Query\Select;
use SokoWeb\PersistentData\PersistentDataManager;
class CommunityMemberRepository
{
private PersistentDataManager $pdm;
public function __construct()
{
$this->pdm = new PersistentDataManager();
}
public function getById(int $id): ?CommunityMember
{
return \Container::$persistentDataManager->selectFromDbById($id, CommunityMember::class);
return $this->pdm->selectFromDbById($id, CommunityMember::class);
}
public function getAllByCommunity(Community $community, bool $useRelations = false): Generator
@ -18,7 +26,7 @@ class CommunityMemberRepository
$select = new Select(\Container::$dbConnection);
$select->where('community_id', '=', $community->getId());
yield from \Container::$persistentDataManager->selectMultipleFromDb($select, CommunityMember::class, $useRelations);
yield from $this->pdm->selectMultipleFromDb($select, CommunityMember::class, $useRelations);
}
public function getAllByUser(User $user, bool $useRelations = false): Generator
@ -26,7 +34,7 @@ class CommunityMemberRepository
$select = new Select(\Container::$dbConnection);
$select->where('user_id', '=', $user->getId());
yield from \Container::$persistentDataManager->selectMultipleFromDb($select, CommunityMember::class, $useRelations);
yield from $this->pdm->selectMultipleFromDb($select, CommunityMember::class, $useRelations);
}
public function getByCommunityAndUser(Community $community, User $user) : ?CommunityMember
@ -35,6 +43,6 @@ class CommunityMemberRepository
$select->where('community_id', '=', $community->getId());
$select->where('user_id', '=', $user->getId());
return \Container::$persistentDataManager->selectFromDb($select, CommunityMember::class);
return $this->pdm->selectFromDb($select, CommunityMember::class);
}
}

View File

@ -1,11 +1,19 @@
<?php namespace RVR\Repository;
use RVR\PersistentData\Model\Community;
use SokoWeb\PersistentData\PersistentDataManager;
class CommunityRepository
{
private PersistentDataManager $pdm;
public function __construct()
{
$this->pdm = new PersistentDataManager();
}
public function getById(int $id): ?Community
{
return \Container::$persistentDataManager->selectFromDbById($id, Community::class);
return $this->pdm->selectFromDbById($id, Community::class);
}
}

View File

@ -2,12 +2,20 @@
use SokoWeb\Database\Query\Select;
use RVR\PersistentData\Model\OAuthClient;
use SokoWeb\PersistentData\PersistentDataManager;
class OAuthClientRepository
{
private PersistentDataManager $pdm;
public function __construct()
{
$this->pdm = new PersistentDataManager();
}
public function getById(int $id): ?OAuthClient
{
return \Container::$persistentDataManager->selectFromDbById($id, OAuthClient::class);
return $this->pdm->selectFromDbById($id, OAuthClient::class);
}
public function getByClientId(string $clientId): ?OAuthClient
@ -15,6 +23,6 @@ class OAuthClientRepository
$select = new Select(\Container::$dbConnection);
$select->where('client_id', '=', $clientId);
return \Container::$persistentDataManager->selectFromDb($select, OAuthClient::class);
return $this->pdm->selectFromDb($select, OAuthClient::class);
}
}

View File

@ -4,12 +4,20 @@ use DateTime;
use Generator;
use SokoWeb\Database\Query\Select;
use RVR\PersistentData\Model\OAuthToken;
use SokoWeb\PersistentData\PersistentDataManager;
class OAuthTokenRepository
{
private PersistentDataManager $pdm;
public function __construct()
{
$this->pdm = new PersistentDataManager();
}
public function getById(int $id): ?OAuthToken
{
return \Container::$persistentDataManager->selectFromDbById($id, OAuthToken::class);
return $this->pdm->selectFromDbById($id, OAuthToken::class);
}
public function getByCode(string $code): ?OAuthToken
@ -17,7 +25,7 @@ class OAuthTokenRepository
$select = new Select(\Container::$dbConnection);
$select->where('code', '=', $code);
return \Container::$persistentDataManager->selectFromDb($select, OAuthToken::class);
return $this->pdm->selectFromDb($select, OAuthToken::class);
}
public function getByAccessToken(string $accessToken): ?OAuthToken
@ -25,7 +33,7 @@ class OAuthTokenRepository
$select = new Select(\Container::$dbConnection);
$select->where('access_token', '=', $accessToken);
return \Container::$persistentDataManager->selectFromDb($select, OAuthToken::class);
return $this->pdm->selectFromDb($select, OAuthToken::class);
}
public function getAllExpired(): Generator
@ -33,6 +41,6 @@ class OAuthTokenRepository
$select = new Select(\Container::$dbConnection);
$select->where('expires', '<', (new DateTime())->format('Y-m-d H:i:s'));
yield from \Container::$persistentDataManager->selectMultipleFromDb($select, OAuthToken::class);
yield from $this->pdm->selectMultipleFromDb($select, OAuthToken::class);
}
}

View File

@ -5,12 +5,20 @@ use Generator;
use SokoWeb\Database\Query\Select;
use RVR\PersistentData\Model\User;
use RVR\PersistentData\Model\UserPasswordResetter;
use SokoWeb\PersistentData\PersistentDataManager;
class UserPasswordResetterRepository
{
private PersistentDataManager $pdm;
public function __construct()
{
$this->pdm = new PersistentDataManager();
}
public function getById(int $userConfirmationId): ?UserPasswordResetter
{
return \Container::$persistentDataManager->selectFromDbById($userConfirmationId, UserPasswordResetter::class);
return $this->pdm->selectFromDbById($userConfirmationId, UserPasswordResetter::class);
}
public function getByToken(string $token): ?UserPasswordResetter
@ -18,7 +26,7 @@ class UserPasswordResetterRepository
$select = new Select(\Container::$dbConnection);
$select->where('token', '=', $token);
return \Container::$persistentDataManager->selectFromDb($select, UserPasswordResetter::class);
return $this->pdm->selectFromDb($select, UserPasswordResetter::class);
}
public function getByUser(User $user): ?UserPasswordResetter
@ -26,7 +34,7 @@ class UserPasswordResetterRepository
$select = new Select(\Container::$dbConnection);
$select->where('user_id', '=', $user->getId());
return \Container::$persistentDataManager->selectFromDb($select, UserPasswordResetter::class);
return $this->pdm->selectFromDb($select, UserPasswordResetter::class);
}
public function getAllExpired(): Generator
@ -34,6 +42,6 @@ class UserPasswordResetterRepository
$select = new Select(\Container::$dbConnection);
$select->where('expires', '<', (new DateTime())->format('Y-m-d H:i:s'));
yield from \Container::$persistentDataManager->selectMultipleFromDb($select, UserPasswordResetter::class);
yield from $this->pdm->selectMultipleFromDb($select, UserPasswordResetter::class);
}
}

View File

@ -4,12 +4,20 @@ use Generator;
use SokoWeb\Interfaces\Repository\IUserRepository;
use SokoWeb\Database\Query\Select;
use RVR\PersistentData\Model\User;
use SokoWeb\PersistentData\PersistentDataManager;
class UserRepository implements IUserRepository
{
private PersistentDataManager $pdm;
public function __construct()
{
$this->pdm = new PersistentDataManager();
}
public function getById(int $userId): ?User
{
return \Container::$persistentDataManager->selectFromDbById($userId, User::class);
return $this->pdm->selectFromDbById($userId, User::class);
}
public function getByEmail(string $email): ?User
@ -17,7 +25,7 @@ class UserRepository implements IUserRepository
$select = new Select(\Container::$dbConnection);
$select->where('email', '=', $email);
return \Container::$persistentDataManager->selectFromDb($select, User::class);
return $this->pdm->selectFromDb($select, User::class);
}
public function getByUsername(string $username): ?User
@ -25,7 +33,7 @@ class UserRepository implements IUserRepository
$select = new Select(\Container::$dbConnection);
$select->where('username', '=', $username);
return \Container::$persistentDataManager->selectFromDb($select, User::class);
return $this->pdm->selectFromDb($select, User::class);
}
public function getByEmailOrUsername(string $emailOrUsername): ?User
@ -42,7 +50,7 @@ class UserRepository implements IUserRepository
$select = new Select(\Container::$dbConnection);
$select->where('google_sub', '=', $sub);
return \Container::$persistentDataManager->selectFromDb($select, User::class);
return $this->pdm->selectFromDb($select, User::class);
}
public function searchByName(string $name): Generator
@ -52,6 +60,6 @@ class UserRepository implements IUserRepository
$select->orWhere('nickname', 'LIKE', '%' . $name . '%');
$select->limit(10);
yield from \Container::$persistentDataManager->selectMultipleFromDb($select, User::class);
yield from $this->pdm->selectMultipleFromDb($select, User::class);
}
}

View File

@ -69,7 +69,7 @@ Container::$routeCollection->group('communities', function (RouteCollection $rou
});
});
Container::$sessionHandler = new DatabaseSessionHandler(Container::$dbConnection);
Container::$sessionHandler = new DatabaseSessionHandler();
session_set_save_handler(Container::$sessionHandler, true);
session_start([