Completed
Push — master ( 67ae16...651a4a )
by Pierre
03:09
created

Auth::isError()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 0
Metric Value
cc 1
eloc 1
nc 1
nop 0
dl 0
loc 3
ccs 0
cts 0
cp 0
crap 2
rs 10
c 0
b 0
f 0
1
<?php
2
3
namespace App\Controllers\Api\V1;
4
5
use App\Interfaces\Controllers\IApi;
6
use App\Reuse\Controllers\AbstractApi;
7
use Nymfonya\Component\Config;
8
use Nymfonya\Component\Container;
9
use Nymfonya\Component\Http\Headers;
10
use Nymfonya\Component\Http\Request;
11
use Nymfonya\Component\Http\Response;
12
use App\Component\Db\Core;
13
use App\Model\Repository\Users;
14
use App\Component\Jwt\Token;
15
use App\Component\Auth\Factory;
16
use App\Component\Crypt;
17
18
final class Auth extends AbstractApi implements IApi
19
{
20
21
    /**
22
     * core db instance
23 7
     *
24
     * @var Core
25 7
     */
26
    protected $db;
27
28
    /**
29
     * user repository
30
     *
31
     * @var UserRepository
0 ignored issues
show
Bug introduced by
The type App\Controllers\Api\V1\UserRepository was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
32
     */
33
    protected $userRepository;
34 3
35
    /**
36 3
     * slugs
37 3
     *
38 3
     * @var array
39 3
     */
40 3
    protected $slugs;
41 1
42 1
    /**
43 1
     * sql
44 1
     *
45
     * @var String
46
     */
47 2
    protected $sql;
48 2
49 1
    /**
50
     * sql values to bind statement
51 1
     *
52 1
     * @var array
53 1
     */
54 1
    protected $bindValues;
55 1
56 1
    /**
57 1
     * error
58
     *
59 1
     * @var Boolean
60 1
     */
61 1
    protected $error;
62 1
63 1
    /**
64
     * error message
65 1
     *
66
     * @var String
67 1
     */
68 1
    protected $errorMessage;
69 1
70 1
    /**
71
     * instanciate
72
     *
73
     * @param Container $container
74
     */
75
    public function __construct(Container $container)
76
    {
77
        $this->userRepository = new Users($container);
0 ignored issues
show
Documentation Bug introduced by
It seems like new App\Model\Repository\Users($container) of type App\Model\Repository\Users is incompatible with the declared type App\Controllers\Api\V1\UserRepository of property $userRepository.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
78
        $this->db = new Core($container);
79 1
        $this->db->fromOrm($this->userRepository);
80
        $this->error = false;
81 1
        $this->errorMessage = '';
82 1
        parent::__construct($container);
83 1
    }
84
85
    /**
86
     * login action
87
     *
88
     * @Role anonymous
89
     * @return Auth
90
     */
91
    final public function login(): Auth
92
    {
93
        $config = $this->getService(Config::class);
94 1
        $logger = $this->getService(\Monolog\Logger::class);
95
        $login = filter_var($this->request->getParam('login'), FILTER_SANITIZE_EMAIL);
96 1
        $password = filter_var($this->request->getParam('password'), FILTER_SANITIZE_STRING);
97 1
        if (false === $this->isValidLogin($login, $password)) {
98 1
            $logger->warning(__FUNCTION__ . ' Invalid arguments');
99
            return $this->setErrorResponse(
100
                Response::HTTP_BAD_REQUEST,
101
                'Invalid arguments'
102
            );
103
        }
104
        $authFactory = new Factory($this->getContainer());
105
        $authFactory->setAdapter();
106
        if ($user = $authFactory->auth($login, $password)) {
107
            $jwtToken = new Token($config, $this->request);
108 1
            $token = $jwtToken
109
                ->setIssueAt(time())
110 1
                ->setIssueAtDelay(0)
111 1
                ->setTtl(1200)
112 1
                ->encode(
113 1
                    $user[Factory::_ID],
114 1
                    $user[Factory::_EMAIL],
115 1
                    $user[Factory::_PASSWORD]
116 1
                );
117 1
            $logger->info(__FUNCTION__ . ' Auth succeed');
118 1
            $this->response
119
                ->setCode(Response::HTTP_OK)
120 1
                ->setContent(
121
                    [Response::_ERROR => false, 'token' => $token]
122
                );
123
            return $this;
124
        }
125
        $logger->warning(__FUNCTION__ . ' Auth failed');
126
        unset($authFactory);
127
        return $this->setErrorResponse(
128
            Response::HTTP_UNAUTHORIZED,
129
            'Bad credentials'
130
        );
131
    }
132
133
    /**
134
     * register action
135
     *
136
     * @Role anonymous
137
     * @return Auth
138
     */
139
    final public function register(): Auth
140
    {
141
        $config = $this->getService(Config::class);
142
        $logger = $this->getService(\Monolog\Logger::class);
143
        $name = filter_var($this->request->getParam('name'), FILTER_SANITIZE_STRING);
144
        $email = filter_var($this->request->getParam('email'), FILTER_SANITIZE_EMAIL);
145
        $password = filter_var($this->request->getParam('password'), FILTER_SANITIZE_STRING);
146
        if (false === $this->isValidRegistration($name, $email, $password)) {
147
            $this->error = true;
148
            $this->errorMessage = 'Invalid arguments';
149
            $logger->warning(__FUNCTION__ . ' Invalid arguments');
150
            return $this->setRegistrationResponse(__CLASS__, __FUNCTION__);
151
        }
152
        $this->userRepository->emailExists($email);
153
        $this->sql = $this->userRepository->getSql();
154
        $this->bindValues = $this->userRepository->getBuilderValues();
155
        $this->db->run($this->sql, $this->bindValues)->hydrate();
156
        $emailCount = $this->db->getRowset();
157
        $emailCounter = (int) $emailCount[0]['counter'];
158
        if ($emailCounter !== 0) {
159
            $this->error = true;
160
            $this->errorMessage = 'Email exists';
161
            $logger->warning(__FUNCTION__ . $this->errorMessage);
162
            return $this->setRegistrationResponse(__CLASS__, __FUNCTION__);
163
        }
164
        $cryptEngine = new Crypt($config);
165
        $cryptedPassword = $cryptEngine->encrypt($password);
166
        unset($cryptEngine);
167
        $this->userRepository->register($name, $email, $cryptedPassword);
168
        $this->sql = $this->userRepository->getSql();
169
        $this->bindValues = $this->userRepository->getBuilderValues();
170
        $this->db->run($this->sql, $this->bindValues);
171
        return $this->setRegistrationResponse(__CLASS__, __FUNCTION__);
172
    }
173
174
    /**
175
     * return true if request methods are allowed
176
     *
177
     * @return boolean
178
     */
179
    protected function isLoginMethodAllowed(): bool
180
    {
181
        return in_array(
182
            $this->request->getMethod(),
183
            [Request::METHOD_POST, Request::METHOD_TRACE]
184
        );
185
    }
186
187
    /**
188
     * return true if login action can be executed
189
     *
190
     * @param string $login
191
     * @param string $password
192
     * @return boolean
193
     */
194
    protected function isValidLogin(string $login, string $password): bool
195
    {
196
        return $this->isLoginMethodAllowed()
197
            && !empty($login)
198
            && !empty($password);
199
    }
200
201
    /**
202
     * return true if registration process can be executed
203
     *
204
     * @param string $login
205
     * @param string $password
206
     * @return boolean
207
     */
208
    protected function isValidRegistration(string $name, string $email, string $password): bool
209
    {
210
        $notEmpty = (!empty($name) && !empty($email) && !empty($password));
211
        $isMethodAllow = $this->request->getMethod() === Request::METHOD_POST;
212
        return $notEmpty && $isMethodAllow;
213
    }
214
215
    /**
216
     * return Auth and set response with http code and message
217
     *
218
     * @param integer $code
219
     * @param string $msg
220
     * @return Auth
221
     */
222
    protected function setErrorResponse(int $code, string $msg): Auth
223
    {
224
        $this->response
225
            ->setCode($code)
226
            ->setContent([
227
                Response::_ERROR => true,
228
                Response::_ERROR_CODE => $code,
229
                Response::_ERROR_MSG => $msg
230
            ])->getHeaderManager()->add(
231
                Headers::CONTENT_TYPE,
232
                'application/json'
233
            );
234
        return $this;
235
    }
236
237
    /**
238
     * set response with for a classname and action
239
     *
240
     * @param string $classname
241
     * @param string $action
242
     * @return Auth
243
     */
244
    protected function setRegistrationResponse(string $classname, string $action): Auth
245
    {
246
        $isError = $this->isError();
247
        $this->response
248
            ->setCode($this->getStatusCode())
249
            ->setContent(
250
                [
251
                    'error' => $this->error,
252
                    'errorMessage' => $this->errorMessage,
253
                    'datas' => [
254
                        'method' => $this->getRequest()->getMethod(),
255
                        'params' => $this->getParams(),
256
                        'controller' => $classname,
257
                        'action' => $action,
258
                        'query' => $isError
259
                            ? ''
260
                            : $this->sql,
261
                        'queryValues' => $isError
262
                            ? [] : $this->bindValues,
263
                        'rowset' => $isError
264
                            ? []
265
                            : $this->db->getRowset()
266
                    ]
267
                ]
268
            );
269
        return $this;
270
    }
271
272
    /**
273
     * returns true if error happened
274
     *
275
     * @return boolean
276
     */
277
    protected function isError(): bool
278
    {
279
        return $this->error === true;
280
    }
281
282
    /**
283
     * returns http status code
284
     *
285
     * @return int
286
     */
287
    protected function getStatusCode(): int
288
    {
289
        return (true === $this->isError())
290
            ? Response::HTTP_BAD_REQUEST
291
            : Response::HTTP_OK;
292
    }
293
}
294