Issues (121)

src/Controllers/AuthController.php (2 issues)

1
<?php
2
3
namespace Jidaikobo\Kontiki\Controllers;
4
5
use Psr\Http\Message\ResponseInterface as Response;
6
use Psr\Http\Message\ServerRequestInterface as Request;
7
use Slim\App;
8
use Slim\Views\PhpRenderer;
9
use Jidaikobo\Kontiki\Core\Auth;
10
use Jidaikobo\Kontiki\Managers\CsrfManager;
11
use Jidaikobo\Kontiki\Managers\FlashManager;
12
use Jidaikobo\Kontiki\Models\UserModel;
13
use Jidaikobo\Kontiki\Services\FormService;
14
use Jidaikobo\Kontiki\Services\RateLimitService;
15
use Jidaikobo\Kontiki\Services\RoutesService;
16
17
class AuthController extends BaseController
18
{
19
    private Auth $auth;
20
    private FormService $formService;
21
    private RateLimitService $rateLimitService;
22
    private UserModel $model;
23
24
    public function __construct(
25
        CsrfManager $csrfManager,
26
        FlashManager $flashManager,
27
        PhpRenderer $view,
28
        RoutesService $routesService,
29
        Auth $auth,
30
        FormService $formService,
31
        RateLimitService $rateLimitService,
32
        UserModel $model
33
    ) {
34
        parent::__construct(
35
            $csrfManager,
36
            $flashManager,
37
            $view,
38
            $routesService
39
        );
40
        $this->auth = $auth;
41
        $this->formService = $formService;
42
        $this->formService->setModel($model);
43
        $this->rateLimitService = $rateLimitService;
44
        $this->model = $model;
45
    }
46
47
    public static function registerRoutes(App $app, string $basePath = ''): void
48
    {
49
        $app->get('/login', AuthController::class . ':showLoginForm')->setName('login');
50
        $app->post('/login', AuthController::class . ':processLogin');
51
        $app->get('/logout', AuthController::class . ':logout');
52
    }
53
54
    public function showLoginForm(Request $request, Response $response): Response
55
    {
56
        $ip = $_SERVER['REMOTE_ADDR'] ?? 'UNKNOWN';
57
        if ($this->rateLimitService->isIpBlocked($ip)) {
58
            http_response_code(403);
59
            die("Access denied due to too many failed login attempts.");
0 ignored issues
show
Bug Best Practice introduced by
In this branch, the function will implicitly return null which is incompatible with the type-hinted return Psr\Http\Message\ResponseInterface. Consider adding a return statement or allowing null as return value.

For hinted functions/methods where all return statements with the correct type are only reachable via conditions, ?null? gets implicitly returned which may be incompatible with the hinted type. Let?s take a look at an example:

interface ReturnsInt {
    public function returnsIntHinted(): int;
}

class MyClass implements ReturnsInt {
    public function returnsIntHinted(): int
    {
        if (foo()) {
            return 123;
        }
        // here: null is implicitly returned
    }
}
Loading history...
Using exit here is not recommended.

In general, usage of exit should be done with care and only when running in a scripting context like a CLI script.

Loading history...
60
        }
61
62
        if ($this->auth->isLoggedIn()) {
63
            return $this->redirectResponse($request, $response, 'dashboard');
64
        }
65
66
        $redirectUrl = $request->getQueryParams()['redirect'] ?? '';
67
        $data = $this->flashManager->getData(
68
            'data',
69
            ['username' => '', 'redirectUrl' => $redirectUrl]
70
        );
71
72
        $content = $this->view->fetch('auth/login.php', $data);
73
        $content = $this->formService->addMessages(
74
            $content,
75
            $this->flashManager->getData('errors', [])
76
        );
77
78
        return $this->renderResponse(
79
            $response,
80
            __('login', 'Login'),
81
            $content,
82
            'layout-simple.php'
83
        );
84
    }
85
86
    public function processLogin(Request $request, Response $response): Response
87
    {
88
        $data = $request->getParsedBody() ?? [];
89
        $username = $data['username'] ?? '';
90
        $password = $data['password'] ?? '';
91
        $redirectRaw = $data['redirectUrl'] ?? '';
92
        $redirectUrl = trim($redirectRaw) !== '' ? $redirectRaw : 'dashboard';
93
        $ip = $_SERVER['REMOTE_ADDR'] ?? 'UNKNOWN';
94
95
        // Login successful
96
        if ($this->auth->login($username, $password)) {
97
            $this->rateLimitService->resetRateLimit($ip);
98
            $this->rateLimitService->cleanOldRateLimitData();
99
            return $this->redirectResponse($request, $response, $redirectUrl);
100
        }
101
102
        // Login Failed
103
        $this->rateLimitService->recordFailedLogin($ip);
104
        $this->flashManager->addErrors([
105
            ['messages' => [__('wrong_username_or_password', 'Incorrect username or password')]],
106
        ]);
107
        $this->flashManager->setData(
108
            'data',
109
            ['username' => $username, 'redirectUrl' => $redirectUrl]
110
        ); // not keep password
111
        return $this->redirectResponse($request, $response, 'login');
112
    }
113
114
    public function logout(Request $request, Response $response): Response
115
    {
116
        $this->auth->logout();
117
        return $this->redirectResponse($request, $response, 'login');
118
    }
119
}
120