Test Failed
Pull Request — master (#166)
by Maximo
05:27
created

AuthController::recover()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 16
Code Lines 9

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 0
Metric Value
cc 1
eloc 9
nc 1
nop 0
dl 0
loc 16
ccs 0
cts 11
cp 0
crap 2
rs 9.9666
c 0
b 0
f 0
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Canvas\Api\Controllers;
6
7
use Canvas\Models\Users;
8
use Canvas\Models\Sources;
9
use Canvas\Models\UserLinkedSources;
10
use Canvas\Exception\ServerErrorHttpException;
11
use Canvas\Exception\ModelException;
12
use Baka\Auth\Models\Users as BakaUsers;
13
use Canvas\Traits\AuthTrait;
14
use Canvas\Traits\SocialLoginTrait;
15
use Exception;
16
use Phalcon\Http\Response;
17
use Phalcon\Validation\Validator\Confirmation;
18
use Phalcon\Validation\Validator\Email as EmailValidator;
0 ignored issues
show
Bug introduced by
The type Phalcon\Validation\Validator\Email 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...
19
use Phalcon\Validation\Validator\PresenceOf;
0 ignored issues
show
Bug introduced by
The type Phalcon\Validation\Validator\PresenceOf 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...
20
use Phalcon\Validation\Validator\StringLength;
0 ignored issues
show
Bug introduced by
The type Phalcon\Validation\Validator\StringLength 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...
21
use Baka\Auth\Models\Sessions;
22
use Canvas\Auth\Factory;
23
use Canvas\Validation as CanvasValidation;
24
use Canvas\Notifications\ResetPassword;
25
use Canvas\Hashing\Password;
26
use Canvas\Notifications\PasswordUpdate;
27
use Canvas\Validations\PasswordValidation;
28
29
/**
30
 * Class AuthController.
31
 *
32
 * @package Canvas\Api\Controllers
33
 *
34
 * @property Users $userData
35
 * @property Request $request
36
 * @property Config $config
37
 * @property \Baka\Mail\Message $mail
38
 * @property Apps $app
39
 */
40
class AuthController extends \Baka\Auth\AuthController
41
{
42
    /**
43
     * Auth Trait.
44
     */
45
    use AuthTrait;
46
    use SocialLoginTrait;
47
48
    /**
49
     * Setup for this controller.
50
     *
51
     * @return void
52
     */
53
    public function onConstruct()
54
    {
55
        $this->userLinkedSourcesModel = new UserLinkedSources();
56
        $this->userModel = new Users();
57
58
        if (!isset($this->config->jwt)) {
59
            throw new ServerErrorHttpException('You need to configure your app JWT');
60
        }
61
    }
62
63
    /**
64
     * User Login.
65
     * @method POST
66
     * @url /v1/auth
67
     *
68
     * @return Response
69
     */
70
    public function login() : Response
71
    {
72
        $email = trim($this->request->getPost('email', 'string', ''));
73
        $password = trim($this->request->getPost('password', 'string', ''));
74
        $admin = 0;
75
        $userIp = !defined('API_TESTS') ? $this->request->getClientAddress() : '127.0.0.1'; //help getting the client ip on scrutinizer :(
76
        $remember = $this->request->getPost('remember', 'int', 1);
77
78
        //Ok let validate user password
79
        $validation = new CanvasValidation();
80
        $validation->add('email', new PresenceOf(['message' => _('The email is required.')]));
81
        $validation->add('password', new PresenceOf(['message' => _('The password is required.')]));
82
83
        //validate this form for password
84
        $validation->validate($this->request->getPost());
85
86
        /**
87
         * Login the user via ecosystem or app.
88
         */
89
        $auth = Factory::create($this->app->ecosystemAuth());
90
        $userData = $auth::login($email, $password, $remember, $admin, $userIp);
0 ignored issues
show
Bug introduced by
The method login() does not exist on Canvas\Auth\Auth. Since it exists in all sub-types, consider adding an abstract or default implementation to Canvas\Auth\Auth. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

90
        /** @scrutinizer ignore-call */ 
91
        $userData = $auth::login($email, $password, $remember, $admin, $userIp);
Loading history...
91
        $token = $userData->getToken();
92
93
        //start session
94
        $session = new Sessions();
95
        $session->start($userData, $token['sessionId'], $token['token'], $userIp, 1);
96
97
        return $this->response([
98
            'token' => $token['token'],
99
            'time' => date('Y-m-d H:i:s'),
100
            'expires' => date('Y-m-d H:i:s', time() + $this->config->jwt->payload->exp),
101
            'id' => $userData->getId(),
102
        ]);
103
    }
104
105
    /**
106
     * User Signup.
107
     *
108
     * @method POST
109
     * @url /v1/users
110
     *
111
     * @return Response
112
     */
113
    public function signup() : Response
114
    {
115
        $user = $this->userModel;
116
117
        $user->email = $this->request->getPost('email', 'email');
118
        $user->firstname = ltrim(trim($this->request->getPost('firstname', 'string', '')));
119
        $user->lastname = ltrim(trim($this->request->getPost('lastname', 'string', '')));
120
        $user->password = ltrim(trim($this->request->getPost('password', 'string', '')));
121
        $userIp = !defined('API_TESTS') ? $this->request->getClientAddress() : '127.0.0.1'; //help getting the client ip on scrutinizer :(
122
        $user->displayname = ltrim(trim($this->request->getPost('displayname', 'string', '')));
123
        $user->defaultCompanyName = ltrim(trim($this->request->getPost('default_company', 'string', '')));
124
125
        //Ok let validate user password
126
        $validation = new CanvasValidation();
127
        $validation->add('password', new PresenceOf(['message' => _('The password is required.')]));
128
        $validation->add('firstname', new PresenceOf(['message' => _('The firstname is required.')]));
129
        $validation->add('email', new EmailValidator(['message' => _('The email is not valid.')]));
130
131
        $validation->add(
132
            'password',
133
            new StringLength([
134
                'min' => 8,
135
                'messageMinimum' => _('Password is too short. Minimum 8 characters.'),
136
            ])
137
        );
138
139
        $validation->add('password', new Confirmation([
140
            'message' => _('Password and confirmation do not match.'),
141
            'with' => 'verify_password',
142
        ]));
143
144
        //validate this form for password
145
        $validation->validate($this->request->getPost());
146
147
        //user registration
148
        try {
149
            $this->db->begin();
150
151
            $user->signup();
152
153
            $this->db->commit();
154
        } catch (Exception $e) {
155
            $this->db->rollback();
156
157
            throw new Exception($e->getMessage());
158
        }
159
160
        $token = $user->getToken();
161
162
        //start session
163
        $session = new Sessions();
164
        $session->start($user, $token['sessionId'], $token['token'], $userIp, 1);
165
166
        $authSession = [
167
            'token' => $token['token'],
168
            'time' => date('Y-m-d H:i:s'),
169
            'expires' => date('Y-m-d H:i:s', time() + $this->config->jwt->payload->exp),
170
            'id' => $user->getId(),
171
        ];
172
173
        $user->password = null;
174
        $this->sendEmail($user, 'signup');
0 ignored issues
show
Deprecated Code introduced by
The function Canvas\Api\Controllers\AuthController::sendEmail() has been deprecated: move to notifications ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

174
        /** @scrutinizer ignore-deprecated */ $this->sendEmail($user, 'signup');

This function has been deprecated. The supplier of the function has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead.

Loading history...
175
176
        return $this->response([
177
            'user' => $user,
178
            'session' => $authSession
179
        ]);
180
    }
181
182
    /**
183
     * Send email to change current email for user.
184
     * @param int $id
185
     * @return Response
186
     */
187
    public function sendEmailChange(int $id): Response
188
    {
189
        //Search for user
190
        $user = Users::getById($id);
191
192
        if (!is_object($user)) {
193
            throw new NotFoundHttpException(_('User not found'));
0 ignored issues
show
Bug introduced by
The type Canvas\Api\Controllers\NotFoundHttpException 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...
194
        }
195
196
        //Send email
197
        $this->sendEmail($user, 'email-change');
0 ignored issues
show
Deprecated Code introduced by
The function Canvas\Api\Controllers\AuthController::sendEmail() has been deprecated: move to notifications ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

197
        /** @scrutinizer ignore-deprecated */ $this->sendEmail($user, 'email-change');

This function has been deprecated. The supplier of the function has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead.

Loading history...
198
199
        return $this->response($user);
200
    }
201
202
    /**
203
     * Change user's email.
204
     * @param string $hash
205
     * @return Response
206
     */
207
    public function changeUserEmail(string $hash): Response
208
    {
209
        $newEmail = $this->request->getPost('new_email', 'string');
210
        $password = $this->request->getPost('password', 'string');
211
212
        //Search user by key
213
        $user = Users::getByUserActivationEmail($hash);
214
215
        if (!is_object($user)) {
216
            throw new NotFoundHttpException(_('User not found'));
217
        }
218
219
        $this->db->begin();
220
221
        $user->email = $newEmail;
222
223
        if (!$user->update()) {
224
            throw new ModelException((string)current($user->getMessages()));
225
        }
226
227
        if (!$userData = $this->loginUsers($user->email, $password)) {
228
            $this->db->rollback();
229
        }
230
231
        $this->db->commit();
232
233
        return $this->response($userData);
234
    }
235
236
    /**
237
     * Login user using Access Token.
238
     * @return Response
239
     */
240
    public function loginBySocial(): Response
241
    {
242
        $request = $this->request->getPostData();
243
244
        $source = Sources::findFirstOrFail([
245
            'title = ?0 and is_deleted = 0',
246
            'bind' => [$request['provider']]
247
        ]);
248
249
        return $this->response($this->providerLogin($source, $request['social_id'], $request['email']));
250
    }
251
252
    /**
253
     * Send the user how filled out the form to the specify email
254
     * a link to reset his password.
255
     *
256
     * @return Response
257
     */
258
    public function recover(): Response
259
    {
260
        $email = $this->request->getPost('email', 'email');
261
262
        $validation = new CanvasValidation();
263
        $validation->add('email', new PresenceOf(['message' => _('The email is required.')]));
264
        $validation->add('email', new EmailValidator(['message' => _('The email is invalid.')]));
265
266
        $validation->validate($this->request->getPost());
267
268
        $recoverUser = Users::getByEmail($email);
269
        $recoverUser->generateForgotHash();
270
271
        $recoverUser->notify(new ResetPassword($recoverUser));
272
273
        return $this->response(_('Check your email to recover your password'));
274
    }
275
276
    /**
277
     * Reset the user password.
278
     * @method PUT
279
     * @url /v1/reset
280
     *
281
     * @return Response
282
     */
283
    public function reset(string $key) : Response
284
    {
285
        //is the key empty or does it existe?
286
        if (empty($key) || !$userData = Users::findFirst(['user_activation_forgot = :key:', 'bind' => ['key' => $key]])) {
287
            throw new Exception(_('This Key to reset password doesn\'t exist'));
288
        }
289
290
        // Get the new password and the verify
291
        $newPassword = trim($this->request->getPost('new_password', 'string'));
292
        $verifyPassword = trim($this->request->getPost('verify_password', 'string'));
293
294
        //Ok let validate user password
295
        PasswordValidation::validate($newPassword, $verifyPassword);
296
297
        // Has the password and set it
298
        $userData->resetPassword($newPassword);
299
        $userData->updateOrFail();
300
        
301
        //log the user out of the site from all devices
302
        $session = new Sessions();
303
        $session->end($userData);
304
305
        $userData->notify(new PasswordUpdate($userData));
306
307
        return $this->response(_('Password Updated'));
308
    }
309
310
    /**
311
    * Set the email config array we are going to be sending.
312
    *
313
    * @deprecated move to notifications
314
    * @param String $emailAction
315
    * @param Users  $user
316
    * @return void
317
    */
318
    protected function sendEmail(BakaUsers $user, string $type): void
319
    {
320
        $send = true;
321
        $subject = null;
322
        $body = null;
323
        switch ($type) {
324
            case 'recover':
325
                $recoveryLink = $this->config->app->frontEndUrl . '/users/reset-password/' . $user->user_activation_forgot;
326
                $subject = _('Password Recovery');
327
                $body = sprintf(_('Click %shere%s to set a new password for your account.'), '<a href="' . $recoveryLink . '" target="_blank">', '</a>');
328
                // send email to recover password
329
                break;
330
            case 'reset':
331
                $activationUrl = $this->config->app->frontEndUrl . '/user/activate/' . $user->user_activation_key;
332
                $subject = _('Password Updated!');
333
                $body = sprintf(_('Your password was update please, use this link to activate your account: %sActivate account%s'), '<a href="' . $activationUrl . '">', '</a>');
334
                // send email that password was update
335
                break;
336
            case 'email-change':
337
                $emailChangeUrl = $this->config->app->frontEndUrl . '/user/' . $user->user_activation_email . '/email';
338
                $subject = _('Email Change Request');
339
                $body = sprintf(_('Click %shere%s to set a new email for your account.'), '<a href="' . $emailChangeUrl . '">', '</a>');
340
                break;
341
            default:
342
                $send = false;
343
                break;
344
        }
345
346
        if ($send) {
347
            $this->mail
348
            ->to($user->email)
349
            ->subject($subject)
350
            ->content($body)
351
            ->sendNow();
352
        }
353
    }
354
}
355