Issues (214)

Security Analysis    not enabled

This project does not seem to handle request data directly as such no vulnerable execution paths were found.

  Cross-Site Scripting
Cross-Site Scripting enables an attacker to inject code into the response of a web-request that is viewed by other users. It can for example be used to bypass access controls, or even to take over other users' accounts.
  File Exposure
File Exposure allows an attacker to gain access to local files that he should not be able to access. These files can for example include database credentials, or other configuration files.
  File Manipulation
File Manipulation enables an attacker to write custom data to files. This potentially leads to injection of arbitrary code on the server.
  Object Injection
Object Injection enables an attacker to inject an object into PHP code, and can lead to arbitrary code execution, file exposure, or file manipulation attacks.
  Code Injection
Code Injection enables an attacker to execute arbitrary code on the server.
  Response Splitting
Response Splitting can be used to send arbitrary responses.
  File Inclusion
File Inclusion enables an attacker to inject custom files into PHP's file loading mechanism, either explicitly passed to include, or for example via PHP's auto-loading mechanism.
  Command Injection
Command Injection enables an attacker to inject a shell command that is execute with the privileges of the web-server. This can be used to expose sensitive data, or gain access of your server.
  SQL Injection
SQL Injection enables an attacker to execute arbitrary SQL code on your database server gaining access to user data, or manipulating user data.
  XPath Injection
XPath Injection enables an attacker to modify the parts of XML document that are read. If that XML document is for example used for authentication, this can lead to further vulnerabilities similar to SQL Injection.
  LDAP Injection
LDAP Injection enables an attacker to inject LDAP statements potentially granting permission to run unauthorized queries, or modify content inside the LDAP tree.
  Header Injection
  Other Vulnerability
This category comprises other attack vectors such as manipulating the PHP runtime, loading custom extensions, freezing the runtime, or similar.
  Regex Injection
Regex Injection enables an attacker to execute arbitrary code in your PHP process.
  XML Injection
XML Injection enables an attacker to read files on your local filesystem including configuration files, or can be abused to freeze your web-server process.
  Variable Injection
Variable Injection enables an attacker to overwrite program variables with custom data, and can lead to further vulnerabilities.
Unfortunately, the security analysis is currently not available for your project. If you are a non-commercial open-source project, please contact support to gain access.

Member.php (4 issues)

Upgrade to new PHP Analysis Engine

These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more

1
<?php
2
3
/**
4
 *  _   __ __ _____ _____ ___  ____  _____
5
 * | | / // // ___//_  _//   ||  __||_   _|
6
 * | |/ // /(__  )  / / / /| || |     | |
7
 * |___//_//____/  /_/ /_/ |_||_|     |_|
8
 * @link https://vistart.me/
9
 * @copyright Copyright (c) 2016 - 2017 vistart
10
 * @license https://vistart.me/license/
11
 */
12
13
namespace rhosocial\organization;
14
15
use rhosocial\base\models\models\BaseBlameableModel;
16
use rhosocial\user\rbac\Item;
17
use rhosocial\user\rbac\Role;
18
use rhosocial\user\User;
19
use rhosocial\organization\rbac\roles\DepartmentAdmin;
20
use rhosocial\organization\rbac\roles\DepartmentCreator;
21
use rhosocial\organization\rbac\roles\OrganizationAdmin;
22
use rhosocial\organization\rbac\roles\OrganizationCreator;
23
use rhosocial\organization\queries\OrganizationQuery;
24
use rhosocial\organization\queries\MemberQuery;
25
use Yii;
26
use yii\base\InvalidCallException;
27
use yii\base\InvalidParamException;
28
use yii\base\InvalidValueException;
29
use yii\db\IntegrityException;
30
31
/**
32
 * Organization member.
33
 *
34
 * @property string $organization_guid
35
 * @property string $user_guid store guid of user who represents this member.
36
 * @property string $nickname
37
 * @property string $role
38
 * @property string $position
39
 * @property string $description
40
 * 
41
 * @property string $department_guid
42
 * @property string $member_guid
43
 * @property Organization $organization
44
 * @property User $memberUser
45
 *
46
 * @version 1.0
47
 * @author vistart <[email protected]>
48
 */
49
class Member extends BaseBlameableModel
50
{
51
    public $createdByAttribute = 'organization_guid';
52
    public $updatedByAttribute = false;
53
    public $hostClass = Organization::class;
54
55
    public $memberAttribute = 'user_guid';
56
    public $memberUserClass = User::class;
57
    public $contentAttribute = 'nickname';
58
    public $searchClass = MemberSearch::class;
59
    private $noInitMemberUser;
60
    /**
61
     * @return User
62
     */
63 50
    public function getNoInitMemberUser()
64
    {
65 50
        if (!$this->noInitMemberUser) {
66 50
            $class = $this->memberUserClass;
67 50
            $this->noInitMemberUser = $class::buildNoInitModel();
68
        }
69 50
        return $this->noInitMemberUser;
70
    }
71
72
    /**
73
     * @return null|MemberSearch
74
     */
75
    public function getSearchModel()
76
    {
77
        $class = $this->searchClass;
78
        if (empty($class) || !class_exists($class)) {
79
            return null;
80
        }
81
        return new $class;
82
    }
83
84
    /**
85
     * @inheritdoc
86
     */
87 51
    public function init()
88
    {
89 51
        if (!is_string($this->queryClass)) {
90 51
            $this->queryClass = MemberQuery::class;
91
        }
92 51
        if ($this->skipInit) {
93 51
            return;
94
        }
95 50
        parent::init();
96 50
    }
97
98
    public $descriptionAttribute = 'description';
99
100 50
    public function getMemberUserRules()
101
    {
102
        return [
103 50
            [$this->memberAttribute, 'required'],
104 50
            [$this->memberAttribute, 'string', 'max' => 36],
105
        ];
106
    }
107
108 50
    public function getMemberRoleRules()
109
    {
110
        return [
111 50
            ['role', 'string', 'max' => 255],
112
        ];
113
    }
114
115 50
    public function getMemberPositionRules()
116
    {
117
        return [
118 50
            ['position', 'default', 'value' => ''],
119
            ['position', 'string', 'max' => 255],
120
        ];
121
    }
122
123
    /**
124
     * Set member user.
125
     * @param User|string|integer $user
126
     */
127 50
    public function setMemberUser($user)
128
    {
129 50
        $class = $this->memberUserClass;
130 50
        if (is_numeric($user)) {
131
            $user = $class::find()->id($user)->one();
132
        }
133 50
        if ($user instanceof $class) {
134 50
            $user = $user->getGUID();
135
        }
136 50
        $this->{$this->memberAttribute} = $user;
137 50
    }
138
139 50
    public function getMemberUser()
140
    {
141 50
        return $this->hasOne($this->memberUserClass, [$this->getNoInitMemberUser()->guidAttribute => $this->memberAttribute]);
142
    }
143
144
    /**
145
     * Get Organization Query.
146
     * Alias of `getHost` method.
147
     * @return OrganizationQuery
148
     */
149 43
    public function getOrganization()
150
    {
151 43
        return $this->getHost();
152
    }
153
154
    /**
155
     * Set Organization.
156
     * @param BaseOrganization $organization
157
     * @return boolean
158
     */
159 50
    public function setOrganization($organization)
160
    {
161 50
        return $this->setHost($organization);
162
    }
163
164
    /**
165
     * Assign role.
166
     * The setting role operation will not take effect immediately. You should
167
     * wrap this method and the subsequent save operations together into a
168
     * transaction, in order to ensure data cosistency.
169
     * @param Role $role
170
     * @return boolean
171
     */
172 50
    public function assignRole($role)
173
    {
174 50
        $user = $this->memberUser;
175 50
        if (!$user) {
176
            throw new InvalidValueException('Invalid User');
177
        }
178 50
        if ($role instanceof Item) {
179 17
            $role = $role->name;
180
        }
181 50
        $assignment = Yii::$app->authManager->getAssignment($role, $user);
182 50
        if (!$assignment) {
183 50
            $assignment = Yii::$app->authManager->assign($role, $user->getGUID());
0 ignored issues
show
$assignment 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...
184
        }
185 50
        return $this->setRole($role);
0 ignored issues
show
$role is of type string, but the function expects a object<rhosocial\user\rbac\Role>|null.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
186
    }
187
188
    /**
189
     * Assign administrator.
190
     * @return boolean
191
     * @throws \Exception
192
     * @throws IntegrityException
193
     */
194 17
    public function assignAdministrator()
195
    {
196 17
        $host = $this->organization;
197
        /* @var $host Organization */
198 17
        if ($this->isCreator()) {
199
            throw new InvalidCallException(Yii::t('organization', 'The user is already a creator.'));
200
        }
201 17
        if ($this->isAdministrator()) {
202
            throw new InvalidCallException(Yii::t('organization', 'The user is already an administrator.'));
203
        }
204 17
        $role = null;
205 17
        if ($host->type == Organization::TYPE_ORGANIZATION) {
206 17
            $role = new OrganizationAdmin();
207 10
        } elseif ($host->type == Organization::TYPE_DEPARTMENT) {
208 10
            $role = new DepartmentAdmin();
209
        }
210 17
        $transaction = Yii::$app->db->beginTransaction();
211
        try {
212 17
            $this->assignRole($role);
0 ignored issues
show
It seems like $role defined by null on line 204 can also be of type null; however, rhosocial\organization\Member::assignRole() does only seem to accept object<rhosocial\user\rbac\Role>, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
213 17
            if (!$this->save()) {
214
                throw new IntegrityException(Yii::t('organization', 'Failed to assign administrator.'));
215
            }
216 17
            $transaction->commit();
217
        } catch (\Exception $ex) {
218
            $transaction->rollBack();
219
            Yii::error($ex->getMessage(), __METHOD__);
220
            throw $ex;
221
        }
222 17
        return true;
223
    }
224
225
    /**
226
     * Set role.
227
     * @param Role $role
228
     * @return boolean
229
     */
230 50
    public function setRole($role = null)
231
    {
232 50
        if (empty($role)) {
233 20
            $role = '';
234
        }
235 50
        if ($role instanceof Item) {
236
            $role = $role->name;
237
        }
238 50
        $this->role = $role;
239 50
        return true;
240
    }
241
242
    /**
243
     * Revoke role.
244
     * @param Role $role
245
     * @throws InvalidParamException
246
     * @throws IntegrityException
247
     * @throws \Exception
248
     * @return boolean
249
     */
250 20
    public function revokeRole($role)
251
    {
252 20
        $user = $this->memberUser;
253 20
        if (!$user) {
254
            throw new InvalidValueException('Invalid User');
255
        }
256 20
        if ($role instanceof Item) {
257 1
            $role = $role->name;
258
        }
259 20
        $transaction = Yii::$app->db->beginTransaction();
260
        try {
261 20
            $assignment = Yii::$app->authManager->getAssignment($role, $user);
262 20
            if ($assignment) {
263 20
                $count = (int)($user->getOfMembers()->role($role)->count());
264 20
                if ($count <= 1) {
265 18
                    Yii::$app->authManager->revoke($role, $user);
266
                }
267
            }
268 20
            $this->setRole();
269 20
            if (!$this->save()) {
270
                throw new IntegrityException('Save failed.');
271
            }
272 20
            $transaction->commit();
273
        } catch (\Exception $ex) {
274
            $transaction->rollBack();
275
            Yii::error($ex->getMessage(), __METHOD__);
276
            throw $ex;
277
        }
278 20
        return true;
279
    }
280
281
    /**
282
     * Revoke administrator.
283
     * @return boolean
284
     * @throws IntegrityException
285
     * @throws \Exception
286
     */
287 1
    public function revokeAdministrator()
288
    {
289 1
        $host = $this->organization;
290
        /* @var $host Organization */
291 1
        if ($this->isCreator()) {
292
            throw new InvalidCallException(Yii::t('organization', 'The user is already a creator.'));
293
        }
294 1
        if (!$this->isAdministrator()) {
295
            throw new InvalidCallException(Yii::t('organization', 'The user is not administrator yet.'));
296
        }
297 1
        $role = null;
298 1
        if ($host->type == Organization::TYPE_ORGANIZATION) {
299 1
            $role = new OrganizationAdmin();
300 1
        } elseif ($host->type == Organization::TYPE_DEPARTMENT) {
301 1
            $role = new DepartmentAdmin();
302
        }
303 1
        $transaction = Yii::$app->db->beginTransaction();
304
        try {
305 1
            $this->revokeRole($role);
0 ignored issues
show
It seems like $role defined by null on line 297 can also be of type null; however, rhosocial\organization\Member::revokeRole() does only seem to accept object<rhosocial\user\rbac\Role>, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
306 1
            if (!$this->save()) {
307
                throw new IntegrityException("Failed to revoke administrator.");
308
            }
309 1
            $transaction->commit();
310
        } catch (\Exception $ex) {
311
            $transaction->rollBack();
312
            Yii::error($ex->getMessage(), __METHOD__);
313
            throw $ex;
314
        }
315 1
        return true;
316
    }
317
318 50
    public function rules()
319
    {
320 50
        return array_merge($this->getMemberUserRules(), $this->getMemberRoleRules(), $this->getMemberPositionRules(), parent::rules());
321
    }
322
323
    /**
324
     * @inheritdoc
325
     */
326 51
    public static function tableName()
327
    {
328 51
        return '{{%organization_member}}';
329
    }
330
331
    /**
332
     * Find.
333
     * Friendly to IDE.
334
     * @return MemberQuery
335
     */
336 51
    public static function find()
337
    {
338 51
        return parent::find();
339
    }
340
341
    /**
342
     * @inheritdoc
343
     */
344 1
    public function attributeLabels()
345
    {
346
        return [
347 1
            $this->guidAttribute => Yii::t('user', 'GUID'),
348 1
            $this->idAttribute => Yii::t('user', 'ID'),
349 1
            $this->createdByAttribute => Yii::t('organization', 'Organization GUID'),
350 1
            $this->memberAttribute => Yii::t('organization', 'User GUID'),
351 1
            $this->contentAttribute => Yii::t('user', 'Nickname'),
352 1
            'role' => Yii::t('organization', 'Role'),
353 1
            'position' => Yii::t('organization', 'Member Position'),
354 1
            $this->descriptionAttribute => Yii::t('organization', 'Description'),
355 1
            $this->ipAttribute => Yii::t('user', 'IP Address'),
356 1
            $this->ipTypeAttribute => Yii::t('user', 'IP Address Type'),
357 1
            $this->createdAtAttribute => Yii::t('organization', 'Join Time'),
358 1
            $this->updatedAtAttribute => Yii::t('user', 'Last Updated Time'),
359
        ];
360
    }
361
362
    /**
363
     * @return bool
364
     */
365 18
    public function isDepartmentAdministrator()
366
    {
367 18
        return $this->role == (new DepartmentAdmin)->name;
368
    }
369
370
    /**
371
     * @return bool
372
     */
373 34
    public function isDepartmentCreator()
374
    {
375 34
        return $this->role == (new DepartmentCreator)->name;
376
    }
377
378
    /**
379
     * @return bool
380
     */
381 18
    public function isOrganizationAdministrator()
382
    {
383 18
        return $this->role == (new OrganizationAdmin)->name;
384
    }
385
386
    /**
387
     * @return bool
388
     */
389 34
    public function isOrganizationCreator()
390
    {
391 34
        return $this->role == (new OrganizationCreator)->name;
392
    }
393
394
    /**
395
     * Check whether current member is administrator.
396
     * @return boolean
397
     */
398 18
    public function isAdministrator()
399
    {
400 18
        return $this->isDepartmentAdministrator() || $this->isOrganizationAdministrator();
401
    }
402
403
    /**
404
     * Check whether current member is creator.
405
     * @return boolean
406
     */
407 34
    public function isCreator()
408
    {
409 34
        return $this->isDepartmentCreator() || $this->isOrganizationCreator();
410
    }
411
412
    /**
413
     * We think it a `member` if `role` property is empty.
414
     * @return boolean
415
     */
416 2
    public function isOnlyMember()
417
    {
418 2
        return empty($this->role);
419
    }
420
421
    const SCENARIO_UPDATE = 'update';
422
    const SCENARIO_ADMIN_UPDATE = 'admin_update';
423
424 50
    public function scenarios()
425
    {
426 50
        return array_merge(parent::scenarios(), [
427 50
            self::SCENARIO_UPDATE => [$this->contentAttribute,],
428
        ], [
429 50
            self::SCENARIO_ADMIN_UPDATE => [$this->contentAttribute, 'position', $this->descriptionAttribute],
430
        ]);
431
    }
432
}
433