Completed
Branch fix/scruitinizer (38ecac)
by Patrick
02:45
created

UsersAPI::listUsers()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 17
Code Lines 11

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 2
eloc 11
nc 2
nop 3
dl 0
loc 17
rs 9.4285
c 0
b 0
f 0
1
<?php
2
class UsersAPI extends Http\Rest\RestAPI
3
{
4
    protected $user;
5
6
    public function setup($app)
7
    {
8
        $app->get('[/]', array($this, 'listUsers'));
9
        $app->post('[/]', array($this, 'createUser'));
10
        $app->get('/{uid}[/]', array($this, 'showUser'));
11
        $app->patch('/{uid}[/]', array($this, 'editUser'));
12
        $app->delete('/{uid}[/]', array($this, 'deleteUser'));
13
        $app->get('/{uid}/groups[/]', array($this, 'listGroupsForUser'));
14
        $app->post('/{uid}/Actions/link[/]', array($this, 'linkUser'));
15
        $app->post('/{uid}/Actions/reset_pass[/]', array($this, 'resetUserPassword'));
16
        $app->post('/Actions/check_email_available[/]', array($this, 'checkEmailAvailable'));
17
        $app->post('/Actions/check_uid_available[/]', array($this, 'checkUidAvailable'));
18
        $app->post('/Actions/remind_uid[/]', array($this, 'remindUid'));
19
    }
20
21 View Code Duplication
    public function validateIsAdmin($request, $nonFatal = false)
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...
22
    {
23
        $this->user = $request->getAttribute('user');
24
        if($this->user === false)
25
        {
26
            throw new Exception('Must be logged in', \Http\Rest\ACCESS_DENIED);
27
        }
28
        if(!$this->user->isInGroupNamed('LDAPAdmins'))
29
        {
30
            if($nonFatal)
31
            {
32
                return false;
33
            }
34
            throw new Exception('Must be Admin', \Http\Rest\ACCESS_DENIED);
35
        }
36
        return true;
37
    }
38
39
    public function listUsers($request, $response, $args)
0 ignored issues
show
Unused Code introduced by
The parameter $args is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
40
    {
41
        $users = false;
0 ignored issues
show
Unused Code introduced by
$users 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...
42
        $odata = $request->getAttribute('odata', new \ODataParams(array()));
43
        if($this->validateIsAdmin($request, true) === false)
44
        {
45
            $users = array($this->user);
46
            $users = $odata->filterArrayPerSelect($users);
47
        }
48
        else
49
        {
50
            $auth = AuthProvider::getInstance();
51
            $users = $auth->getUsersByFilter($odata->filter, $odata->select, $odata->top, $odata->skip, 
52
                                             $odata->orderby);
53
        }
54
        return $response->withJson($users);
55
    }
56
57
    protected function validateCanCreateUser($proposedUser, $auth, &$message)
58
    {
59
        $user = $auth->getUsersByFilter(new \Data\Filter('mail eq '.$proposedUser->mail));
60 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...
61
        {
62
            $message = 'Email already exists!';
63
            return false;
64
        }
65
        $user = $auth->getUsersByFilter(new \Data\Filter('uid eq '.$proposedUser->uid));
66 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...
67
        {
68
            $message = 'Username already exists!';
69
            return false;
70
        }
71
        return true;
72
    }
73
74 View Code Duplication
    protected function validEmail($email)
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...
75
    {
76
        if(filter_var($email) === false)
77
        {
78
            return false;
79
        }
80
        $pos = strpos($email, '@');
81
        if($pos === false)
82
        {
83
            return false;
84
        }
85
        $domain = substr($email, $pos + 1);
86
        if(checkdnsrr($domain, 'MX') === false)
87
        {
88
            return false;
89
        }
90
        return true;
91
    }
92
93
    public function createUser($request, $response, $args)
0 ignored issues
show
Unused Code introduced by
The parameter $args is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
94
    {
95
        $this->user = $request->getAttribute('user');
96
        //This one is different. If they are logged in fail...
97
        if($this->user !== false)
98
        {
99
            return $response->withStatus(404);
100
        }
101
        $obj = $request->getParsedBody();
102
        if(!isset($obj->captcha))
103
        {
104
            return $response->withStatus(401);
105
        }
106
        $captcha = FlipSession::getVar('captcha');
107
        if($captcha === false)
108
        {
109
            return $response->withStatus(401);
110
        }
111
        if(!$captcha->is_answer_right($obj->captcha))
112
        {
113
            return $response->withJson(array('res'=>false, 'message'=>'Incorrect answer to CAPTCHA!'), 412);
114
        }
115
        $auth = AuthProvider::getInstance();
116
        $message = false;
117
        if($this->validateCanCreateUser($obj, $auth, $message) === false)
118
        {
119
            return $response->withJson(array('res'=>false, 'message'=>$message), 412);
120
        }
121 View Code Duplication
        else if($this->validEmail($obj->mail) === false)
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...
122
        {
123
            return $response->withJson(array('res'=>false, 'message'=>'Invalid Email Address!'));
124
        }
125
        $ret = $auth->createPendingUser($obj);
126 View Code Duplication
        if($ret == false)
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...
127
        {
128
            return $response->withJson(array('res'=>false, 'message'=>'Failed to save user registration!'), 500);
129
        }
130
        return $response->withJson($ret);
131
    }
132
133
    protected function userIsMe($request, $uid)
134
    {
135
        $this->user = $request->getAttribute('user');
136
        return ($uid === 'me' || ($this->user !== false && $uid === $this->user->uid));
137
    }
138
139 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...
140
    {
141
        if($this->userIsMe($request, $uid))
142
        {
143
            return $this->user;
144
        }
145
        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...
146
        {
147
            $auth = \AuthProvider::getInstance();
148
            $filter = new \Data\Filter("uid eq $uid");
149
            $users = $auth->getUsersByFilter($filter);
150
            if($users !== false && isset($users[0]))
151
            {
152
                return $users[0];
153
            }
154
        }
155
        return false;
156
    }
157
158 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...
159
    {
160
        if($this->userIsMe($request, $uid))
161
        {
162
            return $this->user;
163
        }
164
        if($this->user->isInGroupNamed('LDAPAdmins'))
165
        {
166
            $auth = \AuthProvider::getInstance();
167
            $filter = new \Data\Filter("uid eq $uid");
168
            $users = $auth->getUsersByFilter($filter);
169
            if($users !== false && isset($users[0]))
170
            {
171
                return $users[0];
172
            }
173
        }
174
        return false;
175
    }
176
177
    public function showUser($request, $response, $args)
178
    {
179
        $uid = $args['uid'];
180
        $user = $request->getAttribute('user');
181
        if($user === false)
182
        {
183
            if($_SERVER['SERVER_ADDR'] === $_SERVER['REMOTE_ADDR'])
184
            {
185
                $user = \AuthProvider::getInstance()->getUsersByFilter(new \Data\Filter("uid eq $uid"));
186
                if($user === false || !isset($user[0]))
187
                {
188
                    return $response->withStatus(404);
189
                }
190
                return $response->withJson($user[0]);
191
            } 
192
            return $response->withStatus(401);
193
        }
194
        $user = $this->getUserByUIDReadOnly($request, $uid);
195
        if($user === false)
196
        {
197
            return $response->withStatus(404);
198
        }
199
        if(!is_object($user) && isset($user[0]))
200
        {
201
            $user = $user[0];
202
        }
203
        if($request->getAttribute('format') === 'vcard')
204
        {
205
            $response = $response->withHeader('Content-Type', 'text/x-vCard');
206
            $response->getBody()->write($user->getVcard());
207
            return $response;
208
        }
209
        return $response->withJson($user);
210
    }
211
212
    protected function sendPasswordResetEmail($user)
213
    {
214
        $forwardedFor = false;
215
        if(isset($_SERVER['HTTP_X_FORWARDED_FOR']))
216
        {
217
            $forwardedFor = $_SERVER['HTTP_X_FORWARDED_FOR'];
218
        }
219
        $emailMsg = new PasswordHasBeenResetEmail($user, $_SERVER['REMOTE_ADDR'], $forwardedFor);
220
        $emailProvider = EmailProvider::getInstance();
221
        if($emailProvider->sendEmail($emailMsg) === false)
222
        {
223
            throw new \Exception('Unable to send password reset email!');
224
        }
225
    }
226
227
    protected function exceptionCodeToHttpCode($e)
228
    {
229
        if($e->getCode() === 3)
230
        {
231
            return 401;
232
        }
233
        return 500;
234
    }
235
236
    protected function getUser($request, $uid, $payload)
237
    {
238
        $this->user = $request->getAttribute('user');
239
        if($this->user === false)
240
        {
241
            if(isset($payload->hash))
242
            {
243
                $auth = AuthProvider::getInstance();
244
                $this->user = $auth->getUserByResetHash($payload->hash);
245
                return $this->user;
246
            }
247
            return false;
248
        }
249
        return $this->getUserByUID($request, $uid);
250
    }
251
252
    public function editUser($request, $response, $args)
253
    {
254
        $uid = 'me';
255
        if(isset($args['uid']))
256
        {
257
            $uid = $args['uid'];
258
        }
259
        $obj = $request->getParsedBody();
260
        $user = $this->getUser($request, $uid, $obj);
261
        if($user === false)
262
        {
263
            return $response->withStatus(404);
264
        }
265
        try
266
        {
267
            if(isset($obj->old_uid))
268
            {
269
                unset($obj->old_uid);
270
            }
271
            $user->editUser($obj);
272
        }
273
        catch(\Exception $e)
274
        {
275
            return $response->withJson($e, exceptionCodeToHttpCode($e));
276
        }
277
        if($this->userIsMe($request, $uid))
278
        {
279
            \FlipSession::setUser($user);
280
        }
281
        if(isset($obj->password))
282
        {
283
            $this->sendPasswordResetEmail($user);
284
        }
285
        return $response->withJson(array('success'=>true));
286
    }
287
288
    public function deleteUser($request, $response, $args)
289
    {
290
        $uid = 'me';
291
        if(isset($args['uid']))
292
        {
293
            $uid = $args['uid'];
294
        }
295
        $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...
296
        if($this->validateIsAdmin($request, true) === false && $this->userIsMe($request, $uid))
297
        {
298
            $user = $this->user;
299
        }
300
        else
301
        {
302
            $auth = AuthProvider::getInstance();
303
            $filter = new \Data\Filter("uid eq $uid");
304
            $user = $auth->getUsersByFilter($filter);
305
            if(empty($user))
306
            {
307
                $user = false;
308
            }
309
            else
310
            {
311
                $user = $user[0];
312
            }
313
        }
314
        if($user === false)
315
        {
316
            return $response->withStatus(404);
317
        }
318
        return $response->withJson($user->delete());
319
    }
320
321
    public function listGroupsForUser($request, $response, $args)
322
    {
323
        $uid = 'me';
324
        if(isset($args['uid']))
325
        {
326
            $uid = $args['uid'];
327
        }
328
        $this->validateLoggedIn($request);
329
        $user = $this->getUserByUID($request, $uid);
330
        if($user === false)
331
        {
332
            return $response->withStatus(404);
333
        }
334
        $groups = $user->getGroups();
335
        if($groups === false)
336
        {
337
            $groups = array();
338
        }
339
        return $response->withJson($groups);
340
    }
341
342
    public function linkUser($request, $response, $args)
343
    {
344
        $uid = 'me';
345
        if(isset($args['uid']))
346
        {
347
            $uid = $args['uid'];
348
        }
349
        $this->validateLoggedIn($request);
350
        $obj = $request->getParsedBody();
351
        if($this->userIsMe($request, $uid))
352
        {
353
            $this->user->addLoginProvider($obj->provider);
354
            AuthProvider::getInstance()->impersonateUser($this->user);
355
        }
356
        else if($this->user->isInGroupNamed("LDAPAdmins"))
357
        {
358
            $user = AuthProvider::getInstance()->getUser($uid);
359
            if($user === false)
360
            {
361
                return $response->withStatus(404);
362
            }
363
            $user->addLoginProvider($obj->provider);
364
        }
365
        else
366
        {
367
            return $response->withStatus(404);
368
        }
369
        return $response->withJson(array('success'=>true));
370
    }
371
372
    protected function getAllUsersByFilter($filter, &$pending)
373
    {
374
        $auth = AuthProvider::getInstance();
375
        $user = $auth->getUsersByFilter($filter);
376 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...
377
        {
378
            $pending = false;
379
            return $user[0];
380
        }
381
        $user = $auth->getPendingUsersByFilter($filter);
382 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...
383
        {
384
            $pending = true;
385
            return $user[0];
386
        }
387
        return false;
388
    }
389
390
    public function checkEmailAvailable($request, $response, $args)
0 ignored issues
show
Unused Code introduced by
The parameter $args is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
391
    {
392
        $params = $request->getQueryParams();
393
        $email = false;
394
        if(isset($params['email']))
395
        {
396
            $email = $params['email'];
397
        }
398
        if($email === false)
399
        {
400
            return $response->withStatus(400);
401
        }
402
        if(filter_var($email, FILTER_VALIDATE_EMAIL) === false || strpos($email, '@') === false)
403
        {
404
            return $response->withJson(false);
405
        }
406
        if(strstr($email, '+') !== false)
407
        {
408
            //Remove everything between the + and the @
409
            $begining = strpos($email, '+');
410
            $end = strpos($email, '@');
411
            $to_delete = substr($email, $begining, $end - $begining);
412
            $email = str_replace($to_delete, '', $email);
413
        }
414
        $filter = new \Data\Filter('mail eq '.$email);
415
        $pending = false;
416
        $user = $this->getAllUsersByFilter($filter, $pending);
417
        if($user === false)
418
        {
419
            return $response->withJson(true);
420
        }
421
        return $response->withJson(array('res'=>false, 'email'=>$user->mail, 'pending'=>$pending));
422
    }
423
424
    public function checkUidAvailable($request, $response, $args)
0 ignored issues
show
Unused Code introduced by
The parameter $args is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
425
    {
426
        $params = $request->getQueryParams();
427
        $uid = false;
428
        if(isset($params['uid']))
429
        {
430
            $uid = $params['uid'];
431
        }
432
        if($uid === false)
433
        {
434
            return $response->withStatus(400);
435
        }
436
        if(strpos($uid, '=') !== false || strpos($uid, ',') !== false)
437
        {
438
            return $response->withJson(false);
439
        }
440
        $filter = new \Data\Filter('uid eq '.$uid);
441
        $pending = false;
442
        $user = $this->getAllUsersByFilter($filter, $pending);
443
        if($user === false)
444
        {
445
            return $response->withJson(true);
446
        }
447
        return $response->withJson(array('res'=>false, 'uidl'=>$user->uid, 'pending'=>$pending));
448
    }
449
450
    public function resetUserPassword($request, $response, $args)
451
    {
452
        $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...
453
        if(isset($args['uid']))
454
        {
455
            $uid = $args['uid'];
456
        }
457
        else
458
        {
459
            return $response->withStatus(400);
460
        }
461
        $auth = AuthProvider::getInstance();
462
        $users = $auth->getUsersByFilter(new \Data\Filter('uid eq '.$uid));
463
        if($users === false || !isset($users[0]))
464
        {
465
            return $response->withStatus(404);
466
        }
467
        $email_msg = new PasswordResetEmail($users[0]);
468
        $email_provider = EmailProvider::getInstance();
469
        if($email_provider->sendEmail($email_msg) === false)
470
        {
471
            throw new \Exception('Unable to send email!');
472
        }
473
        return $response->withJson(true);
474
    }
475
476
    public function remindUid($request, $response, $args)
0 ignored issues
show
Unused Code introduced by
The parameter $args is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
477
    {
478
        $params = $request->getQueryParams();
479
        $email = false;
480
        if(isset($params['email']))
481
        {
482
            $email = $params['email'];
483
        }
484
        if($email === false)
485
        {
486
            return $response->withStatus(400);
487
        }
488
        if(filter_var($email, FILTER_VALIDATE_EMAIL) === false)
489
        {
490
            return $response->withStatus(400);
491
        }
492
        $auth = AuthProvider::getInstance();
493
        $users = $auth->getUsersByFilter(new \Data\Filter('mail eq '.$email));
494
        if($users === false || !isset($users[0]))
495
        {
496
            return $response->withStatus(404);
497
        }
498
        $email_msg = new UIDForgotEmail($users[0]);
499
        $email_provider = EmailProvider::getInstance();
500
        if($email_provider->sendEmail($email_msg) === false)
501
        {
502
            throw new \Exception('Unable to send email!');
503
        }
504
    }
505
}
506
/* vim: set tabstop=4 shiftwidth=4 expandtab: */
507