This project does not seem to handle request data directly as such no vulnerable execution paths were found.
include
, or for example
via PHP's auto-loading mechanism.
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 | * This file is part of the 2amigos/yii2-usuario project. |
||
5 | * |
||
6 | * (c) 2amigOS! <http://2amigos.us/> |
||
7 | * |
||
8 | * For the full copyright and license information, please view |
||
9 | * the LICENSE file that was distributed with this source code. |
||
10 | */ |
||
11 | |||
12 | namespace Da\User\Model; |
||
13 | |||
14 | use Da\User\Helper\SecurityHelper; |
||
15 | use Da\User\Query\UserQuery; |
||
16 | use Da\User\Traits\ContainerAwareTrait; |
||
17 | use Da\User\Traits\ModuleAwareTrait; |
||
18 | use Yii; |
||
19 | use yii\base\Exception; |
||
20 | use yii\base\InvalidConfigException; |
||
21 | use yii\base\InvalidParamException; |
||
22 | use yii\base\NotSupportedException; |
||
23 | use yii\behaviors\TimestampBehavior; |
||
24 | use yii\db\ActiveRecord; |
||
25 | use yii\helpers\ArrayHelper; |
||
26 | use yii\web\Application; |
||
27 | use yii\web\IdentityInterface; |
||
28 | |||
29 | /** |
||
30 | * User ActiveRecord model. |
||
31 | * |
||
32 | * @property bool $isAdmin |
||
33 | * @property bool $isBlocked |
||
34 | * @property bool $isConfirmed whether user account has been confirmed or not |
||
35 | * @property bool $gdpr_deleted whether user requested deletion of his account |
||
36 | * @property bool $gdpr_consent whether user has consent personal data processing |
||
37 | * |
||
38 | * Database fields: |
||
39 | * @property int $id |
||
40 | * @property string $username |
||
41 | * @property string $email |
||
42 | * @property string $unconfirmed_email |
||
43 | * @property string $password_hash |
||
44 | * @property string $auth_key |
||
45 | * @property string $auth_tf_key |
||
46 | * @property int $auth_tf_enabled |
||
47 | * @property string $registration_ip |
||
48 | * @property int $confirmed_at |
||
49 | * @property int $blocked_at |
||
50 | * @property int $flags |
||
51 | * @property int $created_at |
||
52 | * @property int $updated_at |
||
53 | * @property int $last_login_at |
||
54 | * @property int $gdpr_consent_date date of agreement of data processing |
||
55 | * @property string $last_login_ip |
||
56 | * @property int $password_changed_at |
||
57 | * @property int $password_age |
||
58 | * Defined relations: |
||
59 | * @property SocialNetworkAccount[] $socialNetworkAccounts |
||
60 | * @property Profile $profile |
||
61 | */ |
||
62 | class User extends ActiveRecord implements IdentityInterface |
||
63 | { |
||
64 | use ModuleAwareTrait; |
||
65 | use ContainerAwareTrait; |
||
66 | |||
67 | // following constants are used on secured email changing process |
||
68 | const OLD_EMAIL_CONFIRMED = 0b01; |
||
69 | const NEW_EMAIL_CONFIRMED = 0b10; |
||
70 | |||
71 | /** |
||
72 | * @var string Plain password. Used for model validation |
||
73 | */ |
||
74 | public $password; |
||
75 | /** |
||
76 | * @var array connected account list |
||
77 | */ |
||
78 | protected $connectedAccounts; |
||
79 | |||
80 | /** |
||
81 | * {@inheritdoc} |
||
82 | * |
||
83 | * @throws InvalidParamException |
||
84 | * @throws InvalidConfigException |
||
85 | * @throws Exception |
||
86 | */ |
||
87 | 16 | public static function tableName() |
|
88 | { |
||
89 | 16 | return '{{%user}}'; |
|
90 | } |
||
91 | |||
92 | /** |
||
93 | * {@inheritdoc} |
||
94 | */ |
||
95 | 3 | public static function findIdentity($id) |
|
96 | { |
||
97 | 3 | return static::findOne($id); |
|
0 ignored issues
–
show
|
|||
98 | } |
||
99 | |||
100 | /** |
||
101 | * @return UserQuery |
||
102 | */ |
||
103 | 16 | public static function find() |
|
104 | { |
||
105 | 16 | return new UserQuery(static::class); |
|
106 | } |
||
107 | |||
108 | /** |
||
109 | * {@inheritdoc} |
||
110 | * |
||
111 | * @throws NotSupportedException |
||
112 | */ |
||
113 | public static function findIdentityByAccessToken($token, $type = null) |
||
114 | { |
||
115 | throw new NotSupportedException('Method "' . __CLASS__ . '::' . __METHOD__ . '" is not implemented.'); |
||
116 | } |
||
117 | |||
118 | /** |
||
119 | * {@inheritdoc} |
||
120 | */ |
||
121 | 10 | public function beforeSave($insert) |
|
122 | { |
||
123 | /** @var SecurityHelper $security */ |
||
124 | 10 | $security = $this->make(SecurityHelper::class); |
|
125 | 10 | if ($insert) { |
|
126 | 7 | $this->setAttribute('auth_key', $security->generateRandomString()); |
|
127 | 7 | if (Yii::$app instanceof Application) { |
|
128 | 7 | $this->setAttribute('registration_ip', $this->module->disableIpLogging ? '127.0.0.1' : Yii::$app->request->getUserIP()); |
|
129 | } |
||
130 | } |
||
131 | |||
132 | 10 | if (!empty($this->password)) { |
|
133 | 10 | $this->setAttribute( |
|
134 | 10 | 'password_hash', |
|
135 | 10 | $security->generatePasswordHash($this->password, $this->getModule()->blowfishCost) |
|
136 | ); |
||
137 | 10 | $this->password_changed_at = time(); |
|
138 | } |
||
139 | |||
140 | 10 | return parent::beforeSave($insert); |
|
141 | } |
||
142 | |||
143 | /** |
||
144 | * @inheritdoc |
||
145 | * |
||
146 | * @throws InvalidConfigException |
||
147 | */ |
||
148 | 10 | public function afterSave($insert, $changedAttributes) |
|
149 | { |
||
150 | 10 | parent::afterSave($insert, $changedAttributes); |
|
151 | |||
152 | 10 | if ($insert && $this->profile === null) { |
|
153 | 7 | $profile = $this->make(Profile::class); |
|
154 | 7 | $profile->link('user', $this); |
|
155 | } |
||
156 | 10 | } |
|
157 | |||
158 | /** |
||
159 | * {@inheritdoc} |
||
160 | */ |
||
161 | 16 | public function behaviors() |
|
162 | { |
||
163 | $behaviors = [ |
||
164 | 16 | TimestampBehavior::class, |
|
165 | ]; |
||
166 | |||
167 | 16 | if ($this->module->enableGdprCompliance) { |
|
168 | 4 | $behaviors['GDPR'] = [ |
|
169 | 'class' => TimestampBehavior::class, |
||
170 | 'createdAtAttribute' => 'gdpr_consent_date', |
||
171 | 'updatedAtAttribute' => false |
||
172 | ]; |
||
173 | } |
||
174 | |||
175 | 16 | return $behaviors; |
|
176 | } |
||
177 | |||
178 | /** |
||
179 | * {@inheritdoc} |
||
180 | */ |
||
181 | 2 | public function attributeLabels() |
|
182 | { |
||
183 | return [ |
||
184 | 2 | 'username' => Yii::t('usuario', 'Username'), |
|
185 | 2 | 'email' => Yii::t('usuario', 'Email'), |
|
186 | 2 | 'registration_ip' => Yii::t('usuario', 'Registration IP'), |
|
187 | 2 | 'unconfirmed_email' => Yii::t('usuario', 'New email'), |
|
188 | 2 | 'password' => Yii::t('usuario', 'Password'), |
|
189 | 2 | 'created_at' => Yii::t('usuario', 'Registration time'), |
|
190 | 2 | 'confirmed_at' => Yii::t('usuario', 'Confirmation time'), |
|
191 | 2 | 'last_login_at' => Yii::t('usuario', 'Last login time'), |
|
192 | 2 | 'last_login_ip' => Yii::t('usuario', 'Last login IP'), |
|
193 | 2 | 'password_changed_at' => Yii::t('usuario', 'Last password change'), |
|
194 | 2 | 'password_age' => Yii::t('usuario', 'Password age'), |
|
195 | ]; |
||
196 | } |
||
197 | |||
198 | /** |
||
199 | * {@inheritdoc} |
||
200 | */ |
||
201 | 9 | public function scenarios() |
|
202 | { |
||
203 | 9 | return ArrayHelper::merge( |
|
204 | 9 | parent::scenarios(), |
|
205 | [ |
||
206 | 9 | 'register' => ['username', 'email', 'password'], |
|
207 | 'connect' => ['username', 'email'], |
||
208 | 'create' => ['username', 'email', 'password'], |
||
209 | 'update' => ['username', 'email', 'password'], |
||
210 | 'settings' => ['username', 'email', 'password'], |
||
211 | ] |
||
212 | ); |
||
213 | } |
||
214 | |||
215 | /** |
||
216 | * {@inheritdoc} |
||
217 | */ |
||
218 | 9 | public function rules() |
|
219 | { |
||
220 | return [ |
||
221 | // username rules |
||
222 | 9 | 'usernameRequired' => ['username', 'required', 'on' => ['register', 'create', 'connect', 'update']], |
|
223 | 'usernameMatch' => ['username', 'match', 'pattern' => '/^[-a-zA-Z0-9_\.@\+]+$/'], |
||
224 | 'usernameLength' => ['username', 'string', 'min' => 3, 'max' => 255], |
||
225 | 'usernameTrim' => ['username', 'trim'], |
||
226 | 'usernameUnique' => [ |
||
227 | 9 | 'username', |
|
228 | 9 | 'unique', |
|
229 | 9 | 'message' => Yii::t('usuario', 'This username has already been taken'), |
|
230 | ], |
||
231 | |||
232 | // email rules |
||
233 | 'emailRequired' => ['email', 'required', 'on' => ['register', 'connect', 'create', 'update']], |
||
234 | 'emailPattern' => ['email', 'email'], |
||
235 | 'emailLength' => ['email', 'string', 'max' => 255], |
||
236 | 'emailUnique' => [ |
||
237 | 9 | 'email', |
|
238 | 9 | 'unique', |
|
239 | 9 | 'message' => Yii::t('usuario', 'This email address has already been taken'), |
|
240 | ], |
||
241 | 'emailTrim' => ['email', 'trim'], |
||
242 | |||
243 | // password rules |
||
244 | 'passwordTrim' => ['password', 'trim'], |
||
245 | 'passwordRequired' => ['password', 'required', 'on' => ['register']], |
||
246 | 'passwordLength' => ['password', 'string', 'min' => 6, 'max' => 72, 'on' => ['register', 'create']], |
||
247 | |||
248 | // two factor auth rules |
||
249 | 'twoFactorSecretTrim' => ['auth_tf_key', 'trim'], |
||
250 | 'twoFactorSecretLength' => ['auth_tf_key', 'string', 'max' => 16], |
||
251 | 'twoFactorEnabledNumber' => ['auth_tf_enabled', 'boolean'] |
||
252 | ]; |
||
253 | } |
||
254 | |||
255 | /** |
||
256 | * {@inheritdoc} |
||
257 | */ |
||
258 | public function validateAuthKey($authKey) |
||
259 | { |
||
260 | return $this->getAttribute('auth_key') === $authKey; |
||
261 | } |
||
262 | |||
263 | /** |
||
264 | * {@inheritdoc} |
||
265 | */ |
||
266 | 9 | public function getId() |
|
267 | { |
||
268 | 9 | return $this->getAttribute('id'); |
|
269 | } |
||
270 | |||
271 | /** |
||
272 | * {@inheritdoc} |
||
273 | */ |
||
274 | 9 | public function getAuthKey() |
|
275 | { |
||
276 | 9 | return $this->getAttribute('auth_key'); |
|
277 | } |
||
278 | |||
279 | /** |
||
280 | * @return bool whether is blocked or not |
||
281 | */ |
||
282 | 4 | public function getIsBlocked() |
|
283 | { |
||
284 | 4 | return $this->blocked_at !== null; |
|
285 | } |
||
286 | |||
287 | /** |
||
288 | * @throws InvalidConfigException |
||
289 | * @return bool whether the user is an admin or not |
||
290 | */ |
||
291 | 2 | public function getIsAdmin() |
|
292 | { |
||
293 | 2 | return $this->getAuth()->isAdmin($this->username); |
|
294 | } |
||
295 | |||
296 | /** |
||
297 | * Returns whether user account has been confirmed or not. |
||
298 | * @return bool whether user account has been confirmed or not |
||
299 | */ |
||
300 | 5 | public function getIsConfirmed() |
|
301 | { |
||
302 | 5 | return $this->confirmed_at !== null; |
|
303 | } |
||
304 | |||
305 | /** |
||
306 | * Checks whether a user has a specific role. |
||
307 | * |
||
308 | * @param string $role |
||
309 | * |
||
310 | * @return bool |
||
311 | */ |
||
312 | public function hasRole($role) |
||
313 | { |
||
314 | return $this->getAuth()->hasRole($this->id, $role); |
||
315 | } |
||
316 | |||
317 | /** |
||
318 | * @throws InvalidConfigException |
||
319 | * @throws InvalidParamException |
||
320 | * @return \yii\db\ActiveQuery |
||
321 | */ |
||
322 | 10 | public function getProfile() |
|
323 | { |
||
324 | 10 | return $this->hasOne($this->getClassMap()->get(Profile::class), ['user_id' => 'id']); |
|
325 | } |
||
326 | |||
327 | /** |
||
328 | * @throws \Exception |
||
329 | * @return SocialNetworkAccount[] social connected accounts [ 'providerName' => socialAccountModel ] |
||
330 | * |
||
331 | */ |
||
332 | public function getSocialNetworkAccounts() |
||
333 | { |
||
334 | if (null === $this->connectedAccounts) { |
||
335 | /** @var SocialNetworkAccount[] $accounts */ |
||
336 | $accounts = $this->hasMany( |
||
337 | $this->getClassMap() |
||
338 | ->get(SocialNetworkAccount::class), |
||
339 | ['user_id' => 'id'] |
||
340 | ) |
||
341 | ->all(); |
||
342 | |||
343 | foreach ($accounts as $account) { |
||
344 | $this->connectedAccounts[$account->provider] = $account; |
||
345 | } |
||
346 | } |
||
347 | |||
348 | return $this->connectedAccounts; |
||
349 | } |
||
350 | |||
351 | /** |
||
352 | * Returns password age in days |
||
353 | * @return integer |
||
354 | */ |
||
355 | public function getPassword_age() |
||
356 | { |
||
357 | if (is_null($this->password_changed_at)) { |
||
358 | return $this->getModule()->maxPasswordAge; |
||
359 | } |
||
360 | $d = new \DateTime("@{$this->password_changed_at}"); |
||
361 | |||
362 | return $d->diff(new \DateTime(), true)->format("%a"); |
||
363 | } |
||
364 | } |
||
365 |
If you return a value from a function or method, it should be a sub-type of the type that is given by the parent type f.e. an interface, or abstract method. This is more formally defined by the Lizkov substitution principle, and guarantees that classes that depend on the parent type can use any instance of a child type interchangably. This principle also belongs to the SOLID principles for object oriented design.
Let’s take a look at an example:
Our function
my_function
expects aPost
object, and outputs the author of the post. The base classPost
returns a simple string and outputting a simple string will work just fine. However, the child classBlogPost
which is a sub-type ofPost
instead decided to return anobject
, and is therefore violating the SOLID principles. If aBlogPost
were passed tomy_function
, PHP would not complain, but ultimately fail when executing thestrtoupper
call in its body.