Completed
Pull Request — develop (#51)
by Patrick
03:00
created

UsersAPI::checkUidAvailable()   B

Complexity

Conditions 6
Paths 8

Size

Total Lines 25
Code Lines 15

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 6
eloc 15
nc 8
nop 2
dl 0
loc 25
rs 8.439
c 0
b 0
f 0
1
<?php
2
class UsersAPI extends ProfilesAdminAPI
3
{
4
    public function setup($app)
5
    {
6
        $app->get('[/]', array($this, 'listUsers'));
7
        $app->post('[/]', array($this, 'createUser'));
8
        $app->get('/{uid}[/]', array($this, 'showUser'));
9
        $app->patch('/{uid}[/]', array($this, 'editUser'));
10
        $app->delete('/{uid}[/]', array($this, 'deleteUser'));
11
        $app->get('/{uid}/groups[/]', array($this, 'listGroupsForUser'));
12
        $app->post('/{uid}/Actions/link[/]', array($this, 'linkUser'));
13
        $app->post('/{uid}/Actions/reset_pass[/]', array($this, 'resetUserPassword'));
14
        $app->post('/Actions/check_email_available[/]', array($this, 'checkEmailAvailable'));
15
        $app->post('/Actions/check_uid_available[/]', array($this, 'checkUidAvailable'));
16
        $app->post('/Actions/remind_uid[/]', array($this, 'remindUid'));
17
    }
18
19
    public function listUsers($request, $response)
20
    {
21
        $odata = $request->getAttribute('odata', new \ODataParams(array()));
22
        if($this->validateIsAdmin($request, true) === false)
23
        {
24
            $users = array($this->user);
25
            $users = $odata->filterArrayPerSelect($users);
26
        }
27
        else
28
        {
29
            $auth = AuthProvider::getInstance();
30
            $users = $auth->getUsersByFilter($odata->filter, $odata->select, $odata->top, $odata->skip, 
31
                                             $odata->orderby);
32
        }
33
        return $response->withJson($users);
34
    }
35
36
    protected function validateCanCreateUser($proposedUser, $auth, &$message)
37
    {
38
        $user = $auth->getUsersByFilter(new \Data\Filter('mail eq '.$proposedUser->mail));
39 View Code Duplication
        if($user !== false && isset($user[0]))
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
40
        {
41
            $message = 'Email already exists!';
42
            return false;
43
        }
44
        $user = $auth->getUsersByFilter(new \Data\Filter('uid eq '.$proposedUser->uid));
45 View Code Duplication
        if($user !== false && isset($user[0]))
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
46
        {
47
            $message = 'Username already exists!';
48
            return false;
49
        }
50
        return true;
51
    }
52
53
    protected function validEmail($email)
54
    {
55
        if(filter_var($email) === false)
56
        {
57
            return false;
58
        }
59
        $pos = strpos($email, '@');
60
        if($pos === false)
61
        {
62
            return false;
63
        }
64
        $domain = substr($email, $pos + 1);
65
        if(checkdnsrr($domain, 'MX') === false)
66
        {
67
            return false;
68
        }
69
        return true;
70
    }
71
72
    protected function getFailArray($message)
73
    {
74
        return array('res'=>false, 'message'=>$message);
75
    }
76
77
    public function createUser($request, $response)
78
    {
79
        $this->user = $request->getAttribute('user');
80
        //This one is different. If they are logged in fail...
81
        if($this->user !== false)
82
        {
83
            return $response->withStatus(404);
84
        }
85
        $obj = $request->getParsedBody();
86
        if(!isset($obj->captcha))
87
        {
88
            return $response->withStatus(401);
89
        }
90
        $captcha = FlipSession::getVar('captcha');
91
        if($captcha === false)
92
        {
93
            return $response->withStatus(401);
94
        }
95
        if(!$captcha->is_answer_right($obj->captcha))
96
        {
97
            return $response->withJson($this->getFailArray('Incorrect answer to CAPTCHA!'), 412);
98
        }
99
        $auth = AuthProvider::getInstance();
100
        $message = false;
101
        if($this->validateCanCreateUser($obj, $auth, $message) === false)
102
        {
103
            return $response->withJson($this->getFailArray($message), 412);
104
        }
105
        else if($this->validEmail($obj->mail) === false)
106
        {
107
            return $response->withJson($this->getFailArray('Invalid Email Address!'));
108
        }
109
        $ret = $auth->createPendingUser($obj);
110
        if($ret == false)
111
        {
112
            return $response->withJson($this->getFailArray('Failed to save user registration!'), 500);
113
        }
114
        return $response->withJson($ret);
115
    }
116
117
    protected function userIsMe($request, $uid)
118
    {
119
        $this->user = $request->getAttribute('user');
120
        return ($uid === 'me' || ($this->user !== false && $uid === $this->user->uid));
121
    }
122
123 View Code Duplication
    protected function getUserByUIDReadOnly($request, $uid)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
124
    {
125
        if($this->userIsMe($request, $uid))
126
        {
127
            return $this->user;
128
        }
129
        if($this->user->isInGroupNamed('LDAPAdmins') || $this->hasLeadAccess($request))
0 ignored issues
show
Bug introduced by
The method hasLeadAccess() does not seem to exist on object<UsersAPI>.

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
130
        {
131
            $auth = \AuthProvider::getInstance();
132
            $filter = new \Data\Filter("uid eq $uid");
133
            $users = $auth->getUsersByFilter($filter);
134
            if($users !== false && isset($users[0]))
135
            {
136
                return $users[0];
137
            }
138
        }
139
        return false;
140
    }
141
142 View Code Duplication
    protected function getUserByUID($request, $uid)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
143
    {
144
        if($this->userIsMe($request, $uid))
145
        {
146
            return $this->user;
147
        }
148
        if($this->user->isInGroupNamed('LDAPAdmins'))
149
        {
150
            $auth = \AuthProvider::getInstance();
151
            $filter = new \Data\Filter("uid eq $uid");
152
            $users = $auth->getUsersByFilter($filter);
153
            if($users !== false && isset($users[0]))
154
            {
155
                return $users[0];
156
            }
157
        }
158
        return false;
159
    }
160
161
    public function showUser($request, $response, $args)
162
    {
163
        $uid = $args['uid'];
164
        $user = $request->getAttribute('user');
165
        if($user === false)
166
        {
167
            if($_SERVER['SERVER_ADDR'] === $_SERVER['REMOTE_ADDR'])
168
            {
169
                $user = \AuthProvider::getInstance()->getUsersByFilter(new \Data\Filter("uid eq $uid"));
170
                if($user === false || !isset($user[0]))
171
                {
172
                    return $response->withStatus(404);
173
                }
174
                return $response->withJson($user[0]);
175
            } 
176
            return $response->withStatus(401);
177
        }
178
        $user = $this->getUserByUIDReadOnly($request, $uid);
179
        if($user === false)
180
        {
181
            return $response->withStatus(404);
182
        }
183
        if(!is_object($user) && isset($user[0]))
184
        {
185
            $user = $user[0];
186
        }
187
        if($request->getAttribute('format') === 'vcard')
188
        {
189
            $response = $response->withHeader('Content-Type', 'text/x-vCard');
190
            $response->getBody()->write($user->getVcard());
191
            return $response;
192
        }
193
        return $response->withJson($user);
194
    }
195
196
    protected function sendPasswordResetEmail($user)
197
    {
198
        $forwardedFor = false;
199
        if(isset($_SERVER['HTTP_X_FORWARDED_FOR']))
200
        {
201
            $forwardedFor = $_SERVER['HTTP_X_FORWARDED_FOR'];
202
        }
203
        $emailMsg = new PasswordHasBeenResetEmail($user, $_SERVER['REMOTE_ADDR'], $forwardedFor);
204
        $emailProvider = EmailProvider::getInstance();
205
        if($emailProvider->sendEmail($emailMsg) === false)
206
        {
207
            throw new \Exception('Unable to send password reset email!');
208
        }
209
    }
210
211
    protected function exceptionCodeToHttpCode($e)
212
    {
213
        if($e->getCode() === 3)
214
        {
215
            return 401;
216
        }
217
        return 500;
218
    }
219
220
    protected function getUser($request, $uid, $payload)
221
    {
222
        $this->user = $request->getAttribute('user');
223
        if($this->user === false)
224
        {
225
            if(isset($payload->hash))
226
            {
227
                $auth = AuthProvider::getInstance();
228
                $this->user = $auth->getUserByResetHash($payload->hash);
229
                return $this->user;
230
            }
231
            return false;
232
        }
233
        return $this->getUserByUID($request, $uid);
234
    }
235
236
    public function editUser($request, $response, $args)
237
    {
238
        $uid = 'me';
239
        if(isset($args['uid']))
240
        {
241
            $uid = $args['uid'];
242
        }
243
        $obj = $request->getParsedBody();
244
        $user = $this->getUser($request, $uid, $obj);
245
        if($user === false)
246
        {
247
            return $response->withStatus(404);
248
        }
249
        try
250
        {
251
            if(isset($obj->old_uid))
252
            {
253
                unset($obj->old_uid);
254
            }
255
            $user->editUser($obj);
256
        }
257
        catch(\Exception $e)
258
        {
259
            return $response->withJson($e, exceptionCodeToHttpCode($e));
260
        }
261
        if($this->userIsMe($request, $uid))
262
        {
263
            \FlipSession::setUser($user);
264
        }
265
        if(isset($obj->password))
266
        {
267
            $this->sendPasswordResetEmail($user);
268
        }
269
        return $response->withJson(array('success'=>true));
270
    }
271
272
    public function deleteUser($request, $response, $args)
273
    {
274
        $uid = 'me';
275
        if(isset($args['uid']))
276
        {
277
            $uid = $args['uid'];
278
        }
279
        $user = false;
0 ignored issues
show
Unused Code introduced by
$user is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
280
        if($this->validateIsAdmin($request, true) === false && $this->userIsMe($request, $uid))
281
        {
282
            $user = $this->user;
283
        }
284
        else
285
        {
286
            $auth = AuthProvider::getInstance();
287
            $filter = new \Data\Filter("uid eq $uid");
288
            $user = $auth->getUsersByFilter($filter);
289
            if(empty($user))
290
            {
291
                $user = false;
292
            }
293
            else
294
            {
295
                $user = $user[0];
296
            }
297
        }
298
        if($user === false)
299
        {
300
            return $response->withStatus(404);
301
        }
302
        return $response->withJson($user->delete());
303
    }
304
305
    public function listGroupsForUser($request, $response, $args)
306
    {
307
        $uid = 'me';
308
        if(isset($args['uid']))
309
        {
310
            $uid = $args['uid'];
311
        }
312
        $this->validateLoggedIn($request);
313
        $user = $this->getUserByUID($request, $uid);
314
        if($user === false)
315
        {
316
            return $response->withStatus(404);
317
        }
318
        $groups = $user->getGroups();
319
        if($groups === false)
320
        {
321
            $groups = array();
322
        }
323
        return $response->withJson($groups);
324
    }
325
326
    public function linkUser($request, $response, $args)
327
    {
328
        $uid = 'me';
329
        if(isset($args['uid']))
330
        {
331
            $uid = $args['uid'];
332
        }
333
        $this->validateLoggedIn($request);
334
        $obj = $request->getParsedBody();
335
        if($this->userIsMe($request, $uid))
336
        {
337
            $this->user->addLoginProvider($obj->provider);
338
            AuthProvider::getInstance()->impersonateUser($this->user);
339
        }
340
        else if($this->user->isInGroupNamed("LDAPAdmins"))
341
        {
342
            $user = AuthProvider::getInstance()->getUser($uid);
343
            if($user === false)
344
            {
345
                return $response->withStatus(404);
346
            }
347
            $user->addLoginProvider($obj->provider);
348
        }
349
        else
350
        {
351
            return $response->withStatus(404);
352
        }
353
        return $response->withJson(array('success'=>true));
354
    }
355
356
    protected function getAllUsersByFilter($filter, &$pending)
357
    {
358
        $auth = AuthProvider::getInstance();
359
        $user = $auth->getUsersByFilter($filter);
360 View Code Duplication
        if($user !== false && isset($user[0]))
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
361
        {
362
            $pending = false;
363
            return $user[0];
364
        }
365
        $user = $auth->getPendingUsersByFilter($filter);
366 View Code Duplication
        if($user !== false && isset($user[0]))
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
367
        {
368
            $pending = true;
369
            return $user[0];
370
        }
371
        return false;
372
    }
373
374
    public function checkEmailAvailable($request, $response)
375
    {
376
        $params = $request->getQueryParams();
377
        $email = false;
378
        if(isset($params['email']))
379
        {
380
            $email = $params['email'];
381
        }
382
        if($email === false)
383
        {
384
            return $response->withStatus(400);
385
        }
386
        if(filter_var($email, FILTER_VALIDATE_EMAIL) === false || strpos($email, '@') === false)
387
        {
388
            return $response->withJson(false);
389
        }
390
        if(strstr($email, '+') !== false)
391
        {
392
            //Remove everything between the + and the @
393
            $begining = strpos($email, '+');
394
            $end = strpos($email, '@');
395
            $to_delete = substr($email, $begining, $end - $begining);
396
            $email = str_replace($to_delete, '', $email);
397
        }
398
        $filter = new \Data\Filter('mail eq '.$email);
399
        $pending = false;
400
        $user = $this->getAllUsersByFilter($filter, $pending);
401
        if($user === false)
402
        {
403
            return $response->withJson(true);
404
        }
405
        return $response->withJson(array('res'=>false, 'email'=>$user->mail, 'pending'=>$pending));
406
    }
407
408
    public function checkUidAvailable($request, $response)
409
    {
410
        $params = $request->getQueryParams();
411
        $uid = false;
412
        if(isset($params['uid']))
413
        {
414
            $uid = $params['uid'];
415
        }
416
        if($uid === false)
417
        {
418
            return $response->withStatus(400);
419
        }
420
        if(strpos($uid, '=') !== false || strpos($uid, ',') !== false)
421
        {
422
            return $response->withJson(false);
423
        }
424
        $filter = new \Data\Filter('uid eq '.$uid);
425
        $pending = false;
426
        $user = $this->getAllUsersByFilter($filter, $pending);
427
        if($user === false)
428
        {
429
            return $response->withJson(true);
430
        }
431
        return $response->withJson(array('res'=>false, 'uidl'=>$user->uid, 'pending'=>$pending));
432
    }
433
434
    public function resetUserPassword($request, $response, $args)
435
    {
436
        $uid = false;
0 ignored issues
show
Unused Code introduced by
$uid is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
437
        if(isset($args['uid']))
438
        {
439
            $uid = $args['uid'];
440
        }
441
        else
442
        {
443
            return $response->withStatus(400);
444
        }
445
        $auth = AuthProvider::getInstance();
446
        $users = $auth->getUsersByFilter(new \Data\Filter('uid eq '.$uid));
447
        if($users === false || !isset($users[0]))
448
        {
449
            return $response->withStatus(404);
450
        }
451
        $email_msg = new PasswordResetEmail($users[0]);
452
        $email_provider = EmailProvider::getInstance();
453
        if($email_provider->sendEmail($email_msg) === false)
454
        {
455
            throw new \Exception('Unable to send email!');
456
        }
457
        return $response->withJson(true);
458
    }
459
460
    public function remindUid($request, $response)
461
    {
462
        $params = $request->getQueryParams();
463
        $email = false;
464
        if(isset($params['email']))
465
        {
466
            $email = $params['email'];
467
        }
468
        if($email === false)
469
        {
470
            return $response->withStatus(400);
471
        }
472
        if(filter_var($email, FILTER_VALIDATE_EMAIL) === false)
473
        {
474
            return $response->withStatus(400);
475
        }
476
        $auth = AuthProvider::getInstance();
477
        $users = $auth->getUsersByFilter(new \Data\Filter('mail eq '.$email));
478
        if($users === false || !isset($users[0]))
479
        {
480
            return $response->withStatus(404);
481
        }
482
        $email_msg = new UIDForgotEmail($users[0]);
483
        $email_provider = EmailProvider::getInstance();
484
        if($email_provider->sendEmail($email_msg) === false)
485
        {
486
            throw new \Exception('Unable to send email!');
487
        }
488
    }
489
}
490
/* vim: set tabstop=4 shiftwidth=4 expandtab: */
491