PageRenderTime 42ms CodeModel.GetById 14ms RepoModel.GetById 1ms app.codeStats 0ms

/protected/vendor/nenad/yii2-password-strength/StrengthValidator.php

https://gitlab.com/I-NOZex/quiz
PHP | 388 lines | 222 code | 45 blank | 121 comment | 31 complexity | dc0aafa98159f4cebbd6d0bf798b60fe MD5 | raw file
  1. <?php
  2. namespace nenad\passwordStrength;
  3. use yii\base\InvalidConfigException;
  4. use yii\helpers\Html;
  5. use yii\helpers\Json;
  6. use Yii;
  7. /**
  8. * StrengthValidator validates if the attribute value matches a specified
  9. * set of password strength rules. It builds over the Yii StringValidator.
  10. */
  11. class StrengthValidator extends \yii\validators\Validator
  12. {
  13. //-- The valid preset constants --//
  14. const SIMPLE = 'simple';
  15. const NORMAL = 'normal';
  16. const FAIR = 'fair';
  17. const MEDIUM = 'medium';
  18. const STRONG = 'strong';
  19. const RESET = 'reset'; // used for password reset
  20. //-- The available rule constants --//
  21. const RULE_MIN = 'min';
  22. const RULE_MAX = 'max';
  23. const RULE_LEN = 'length';
  24. const RULE_USER = 'hasUser';
  25. const RULE_EMAIL = 'hasEmail';
  26. const RULE_LOW = 'lower';
  27. const RULE_UP = 'upper';
  28. const RULE_NUM = 'digit';
  29. const RULE_SPL = 'special';
  30. /**
  31. * @var boolean check whether password contains the username
  32. */
  33. public $hasUser = true;
  34. /**
  35. * @var boolean check whether password contains an email string
  36. */
  37. public $hasEmail = true;
  38. /**
  39. * @var int minimum number of characters. If not set, defaults to 4.
  40. */
  41. public $min = 4;
  42. /**
  43. * @var int maximum length. If not set, it means no maximum length limit.
  44. */
  45. public $max;
  46. /**
  47. * @var int specifies the exact length that the value should be of
  48. */
  49. public $length;
  50. /**
  51. * @var int minimal number of lower case characters
  52. */
  53. public $lower = 2;
  54. /**
  55. * @var int minimal number of upper case characters
  56. */
  57. public $upper = 2;
  58. /**
  59. * @var int minimal number of numeric digit characters
  60. */
  61. public $digit = 2;
  62. /**
  63. * @var int minimal number of special characters
  64. */
  65. public $special = 2;
  66. /**
  67. * @var string the name of the username attribute
  68. */
  69. public $userAttribute = 'username';
  70. /**
  71. * @var string user-defined error message used when the value is not a string
  72. */
  73. public $strError;
  74. /**
  75. * @var string user-defined error message used when the length of the value is smaller than [[min]].
  76. */
  77. public $minError;
  78. /**
  79. * @var string user-defined error message used when the length of the value is greater than [[max]].
  80. */
  81. public $maxError;
  82. /**
  83. * @var string user-defined error message used when the length of the value is not equal to [[length]].
  84. */
  85. public $lengthError;
  86. /**
  87. * @var string user-defined error message used when [[hasUser]] is true and value contains the username
  88. */
  89. public $hasUserError;
  90. /**
  91. * @var string user-defined error message used [[hasEmail]] is true and value contains an email
  92. */
  93. public $hasEmailError;
  94. /**
  95. * @var string user-defined error message used when value contains less than [[lower]] characters
  96. */
  97. public $lowerError;
  98. /**
  99. * @var string user-defined error message used when value contains less than [[upper]] characters
  100. */
  101. public $upperError;
  102. /**
  103. * @var string user-defined error message used when value contains less than [[digit]] characters
  104. */
  105. public $digitError;
  106. /**
  107. * @var string user-defined error message used when value contains more than [[special]] characters
  108. */
  109. public $specialError;
  110. /**
  111. * @var string preset - one of the preset constants,
  112. * @see $_presets
  113. * If this is not null, the preset parameters will override
  114. * the validator level params
  115. */
  116. public $preset;
  117. /**
  118. * @var string presets configuration source file
  119. * defaults to [[presets.php]] in the current directory
  120. */
  121. public $presetsSource;
  122. /**
  123. * @var array the target strength rule requirements that will
  124. * be evaluated for displaying the strength meter
  125. */
  126. public $strengthTarget = [
  127. 'min' => 8,
  128. 'lower' => 3,
  129. 'upper' => 3,
  130. 'digit' => 3,
  131. 'special' => 3,
  132. ];
  133. /**
  134. * @var array the the internalization configuration for this widget
  135. */
  136. public $i18n = [];
  137. /**
  138. * @var array the list of inbuilt presets and their parameter settings
  139. */
  140. private $_presets;
  141. /**
  142. * @var array the default rule settings
  143. */
  144. private static $_rules = [
  145. self::RULE_MIN => [
  146. 'msg' => '{attribute} should contain at least {n, plural, one{one character} other{# characters}} ({found} found)!',
  147. 'int' => true
  148. ],
  149. self::RULE_MAX => [
  150. 'msg' => '{attribute} should contain at most {n, plural, one{one character} other{# characters}} ({found} found)!',
  151. 'int' => true
  152. ],
  153. self::RULE_LEN => [
  154. 'msg' => '{attribute} should contain exactly {n, plural, one{one character} other{# characters}} ({found} found)!',
  155. 'int' => true
  156. ],
  157. self::RULE_USER => [
  158. 'msg' => '{attribute} cannot contain the username',
  159. 'bool' => true
  160. ],
  161. self::RULE_EMAIL => [
  162. 'msg' => '{attribute} cannot contain an email address',
  163. 'match' => '/^([\w\!\#$\%\&\'\*\+\-\/\=\?\^\`{\|\}\~]+\.)*[\w\!\#$\%\&\'\*\+\-\/\=\?\^\`{\|\}\~]+@((((([a-z0-9]{1}[a-z0-9\-]{0,62}[a-z0-9]{1})|[a-z])\.)+[a-z]{2,6})|(\d{1,3}\.){3}\d{1,3}(\:\d{1,5})?)$/i',
  164. 'bool' => true
  165. ],
  166. self::RULE_LOW => [
  167. 'msg' => '{attribute} should contain at least {n, plural, one{one lower case character} other{# lower case characters}} ({found} found)!',
  168. 'match' => '![a-z]!',
  169. 'int' => true
  170. ],
  171. self::RULE_UP => [
  172. 'msg' => '{attribute} should contain at least {n, plural, one{one upper case character} other{# upper case characters}} ({found} found)!',
  173. 'match' => '![A-Z]!',
  174. 'int' => true
  175. ],
  176. self::RULE_NUM => [
  177. 'msg' => '{attribute} should contain at least {n, plural, one{one numeric character} other{# numeric characters}} ({found} found)!',
  178. 'match' => '![\d]!',
  179. 'int' => true
  180. ],
  181. self::RULE_SPL => [
  182. 'msg' => '{attribute} should contain at least {n, plural, one{one special character} other{# special characters}} ({found} found)!',
  183. 'match' => '![\W]!',
  184. 'int' => true
  185. ]
  186. ];
  187. /**
  188. * Initialize the validator component
  189. */
  190. public function init()
  191. {
  192. parent::init();
  193. Yii::setAlias('@pwdstrength', dirname(__FILE__));
  194. if (empty($this->i18n)) {
  195. $this->i18n = [
  196. 'class' => 'yii\i18n\PhpMessageSource',
  197. 'basePath' => '@pwdstrength/messages'
  198. ];
  199. }
  200. Yii::$app->i18n->translations['pwdstrength'] = $this->i18n;
  201. $this->applyPreset();
  202. $this->checkParams();
  203. $this->setRuleMessages();
  204. }
  205. /**
  206. * Sets the rule message for each rule
  207. */
  208. protected function setRuleMessages()
  209. {
  210. if ($this->strError === null) {
  211. $this->strError = Yii::t('pwdstrength', '{attribute} must be a string');
  212. }
  213. foreach (self::$_rules as $rule => $setup) {
  214. $param = "{$rule}Error";
  215. if ($this->$rule !== null) {
  216. $message = (!isset($this->$param) || $this->$param === null) ? $setup['msg'] : $this->$param;
  217. $this->$param = Yii::t('pwdstrength', $message, ['n' => $this->$rule]);
  218. }
  219. }
  220. }
  221. /**
  222. * Apply preset parameter if set
  223. *
  224. * @return void
  225. * @throws InvalidConfigException if [[preset]] value is invalid.
  226. */
  227. protected function applyPreset()
  228. {
  229. if (!isset($this->preset)) {
  230. return;
  231. }
  232. if (!isset($this->presetsSource)) {
  233. $this->presetsSource = __DIR__ . '/presets.php';
  234. }
  235. $this->_presets = require($this->presetsSource);
  236. if (array_key_exists($this->preset, $this->_presets)) {
  237. foreach ($this->_presets[$this->preset] As $param => $value) {
  238. $this->$param = $value;
  239. }
  240. } else {
  241. throw new InvalidConfigException("Invalid preset '{$this->preset}'.");
  242. }
  243. }
  244. /**
  245. * Validates the provided parameters for valid data type
  246. * and the right threshold for 'max' chars.
  247. *
  248. * @throws InvalidConfigException if validation is invalid
  249. */
  250. protected function checkParams()
  251. {
  252. foreach (self::$_rules as $rule => $setup) {
  253. if (isset($this->$rule) && !empty($setup['int']) && $setup['int'] &&
  254. (!is_int($this->$rule) || $this->$rule < 0)
  255. ) {
  256. throw new InvalidConfigException("The property '{$rule}' must be a positive integer.");
  257. }
  258. if (isset($this->$rule) && !empty($setup['bool']) && $setup['bool'] &&
  259. !is_bool($this->$rule)
  260. ) {
  261. throw new InvalidConfigException("The property '{$rule}' must be either true or false.");
  262. }
  263. }
  264. if (isset($this->max)) {
  265. $chars = $this->lower + $this->upper + $this->digit + $this->special;
  266. if ($chars > $this->max) {
  267. throw new InvalidConfigException("Total number of required characters {$chars} is greater than maximum allowed {$this->max}. Validation is impossible!");
  268. }
  269. }
  270. }
  271. /**
  272. * Validation of the attribute
  273. *
  274. * @param Model $object
  275. * @param string $attribute
  276. */
  277. public function validateAttribute($object, $attribute)
  278. {
  279. $value = $object->$attribute;
  280. if (!is_string($value)) {
  281. $this->addError($object, $attribute, $this->strError);
  282. return;
  283. }
  284. $label = $object->getAttributeLabel($attribute);
  285. $username = $object[$this->userAttribute];
  286. $temp = [];
  287. foreach (self::$_rules as $rule => $setup) {
  288. $param = "{$rule}Error";
  289. if ($rule === self::RULE_USER && $this->hasUser && strpos($value, $username) > 0) {
  290. $this->addError($object, $attribute, $this->$param, ['attribute' => $label]);
  291. } elseif ($rule === self::RULE_EMAIL && $this->hasEmail && preg_match($setup['match'], $value, $matches)) {
  292. $this->addError($object, $attribute, $this->$param, ['attribute' => $label]);
  293. } elseif (!empty($setup['match']) && $rule !== self::RULE_EMAIL && $rule !== self::RULE_USER) {
  294. $count = preg_match_all($setup['match'], $value, $temp);
  295. if ($count < $this->$rule) {
  296. $this->addError($object, $attribute, $this->$param, [
  297. 'attribute' => $label,
  298. 'found' => $count
  299. ]);
  300. }
  301. } else {
  302. $length = strlen($value);
  303. $test = false;
  304. if ($rule === self::RULE_LEN) {
  305. $test = ($length !== $this->$rule);
  306. } elseif ($rule === self::RULE_MIN) {
  307. $test = ($length < $this->$rule);
  308. } elseif ($rule === self::RULE_MAX) {
  309. $test = ($length > $this->$rule);
  310. }
  311. if ($this->$rule !== null && $test) {
  312. $this->addError($object, $attribute, $this->$param, [
  313. 'attribute' => $label . ' (' . $rule . ' , ' . $this->$rule . ')',
  314. 'found' => $length
  315. ]);
  316. }
  317. }
  318. }
  319. }
  320. /**
  321. * Client validation
  322. *
  323. * @param Model $model
  324. * @param string $attribute
  325. * @param View $view
  326. * @return string javascript method
  327. */
  328. public function clientValidateAttribute($model, $attribute, $view)
  329. {
  330. $label = $model->getAttributeLabel($attribute);
  331. $options = ['strError' => Html::encode(Yii::t('pwdstrength', $this->message, ['attribute' => $label]))];
  332. $options['userField'] = '#' . Html::getInputId($model, $this->userAttribute);
  333. foreach (self::$_rules as $rule => $setup) {
  334. $param = "{$rule}Error";
  335. if ($this->$rule !== null) {
  336. $options[$rule] = $this->$rule;
  337. $options[$param] = Html::encode(Yii::t('pwdstrength', $this->$param, ['attribute' => $label]));
  338. }
  339. }
  340. StrengthValidatorAsset::register($view);
  341. return "kvStrengthValidator.validate(value, messages, " . Json::encode($options) . ");";
  342. }
  343. }