-
Notifications
You must be signed in to change notification settings - Fork 0
/
genpass.module
340 lines (298 loc) · 13.2 KB
/
genpass.module
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
<?php
use Drupal\Core\Form\ConfigFormBase;
define('GENPASS_REQUIRED', 0);
define('GENPASS_OPTIONAL', 1);
define('GENPASS_RESTRICTED', 2);
define('GENPASS_DISPLAY_NONE', 0);
define('GENPASS_DISPLAY_ADMIN', 1);
define('GENPASS_DISPLAY_USER', 2);
define('GENPASS_DISPLAY_BOTH', 3);
/**
* Implements of hook_init().
*/
function genpass_page_attachments(array &$attachments) {
$attachments['#attached']['library'][] = 'genpass/genpass.libraries.yml';
}
/**
* Defines default characters allowed for passwords.
*/
function _GENPASS_REQUIRED_entropy() {
return 'abcdefghjkmnpqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ23456789!#$%&()*+,-./:;<=>?@[]^_{|}~';
}
/**
* Generate a new password using the preferred password generation algorithm.
*
* @return a fresh password.
*/
function genpass_generate() {
return \Drupal::moduleHandler()->invoke(genpass_algorithm_module(), 'password');
}
/**
* Generate a new password using genpass's internal password generation
* algorithm.
* Based on the original D6 user_password function (with more characters)
*
* @return a fresh password according to the settings made in /admin/user/settings
*
* @see genpass_form_alter()
*/
function genpass_password() {
$pass = '';
$length = \Drupal::config('genpass.settings')->get('genpass_length');
$allowable_characters = \Drupal::config('genpass.settings')->get('genpass_entropy');
// Zero-based count of characters in the allowable list:
$len = strlen($allowable_characters) - 1;
// Loop the number of times specified by $length.
for ($i = 0; $i < $length; $i++) {
// Each iteration, pick a random character from the
// allowable string and append it to the password:
$pass .= $allowable_characters[mt_rand(0, $len)];
}
return $pass;
}
/**
* Helper function to find a item in the user form, since its position
* within the form-array depends on the profile module (account-category).
*/
function &_genpass_get_form_item(&$form, $field) {
if (isset($form['account'][$field])) {
return $form['account'][$field];
}
else {
return $form[$field];
}
}
/**
* Implements hook_form_alter().
*/
function genpass_form_alter(&$form, \Drupal\Core\Form\FormStateInterface $form_state, $form_id) {
switch ($form_id) {
// User admin settings form at admin/config/people/accounts
case 'user_admin_settings':
$form['registration_cancellation']['genpass_mode'] = array(
'#type' => 'radios',
'#title' => t('Password handling'),
'#default_value' => \Drupal::config('genpass.settings')->get('genpass_mode'),
'#options' => array(
GENPASS_REQUIRED => t('Users <strong>must</strong> enter a password on registration. This is disabled if e-mail verification is enabled above.'),
GENPASS_OPTIONAL => t('Users <strong>may</strong> enter a password on registration. If left empty, a random password will be generated. This always applies when an administer is creating the account.'),
GENPASS_RESTRICTED => t('Users <strong>cannot</strong> enter a password on registration; a random password will be generated. This always applies for the regular user registration form if e-mail verification is enabled above.'),
),
'#description' => t('Choose a password handling mode for new users.'),
);
$form['registration_cancellation']['genpass_length'] = array(
'#type' => 'textfield',
'#title' => t('Generated password length'),
'#default_value' => \Drupal::config('genpass.settings')->get('genpass_length'),
'#size' => 2,
'#maxlength' => 2,
'#description' => t('Set the length of generated passwords here. Allowed range: 5 to 32.'),
);
$form['registration_cancellation']['genpass_entropy'] = array(
'#type' => 'textfield',
'#title' => t('Generated password entropy'),
'#size' => 100,
'#default_value' => \Drupal::config('genpass.settings')->get('genpass_entropy'),
'#description' => t('Give a list of possible characters for a generated password. Note that the list must contain at least X different characters where X is defined by the length you have given above.'),
);
// Provide a selection mechanism to choose the preferred algorithm for
// generating passwords. Any module which implements hook_password() is
// displayed here.
$form['registration_cancellation']['genpass_algorithm'] = array(
'#type' => 'radios',
'#title' => t('Password generation algorithm'),
'#default_value' => genpass_algorithm_module(),
'#options' => genpass_add_samples(genpass_algorithm_modules()),
'#description' => t('If third party modules define a password generation algorithm, you can select which one to use. Note that algorithms other than genpass will ignore the preferred entropy and password length. The currently selected algorithm produced the password @pw.', array('@pw' => genpass_generate())),
);
$form['registration_cancellation']['genpass_display'] = array(
'#type' => 'radios',
'#title' => t('Generated password display'),
'#default_value' => \Drupal::config('genpass.settings')->get('genpass_display'),
'#options' => array(
GENPASS_DISPLAY_NONE => t('Do not display.'),
GENPASS_DISPLAY_ADMIN => t('Display when site administrators create new user accounts.'),
GENPASS_DISPLAY_USER => t('Display when users create their own accounts.'),
GENPASS_DISPLAY_BOTH => t('Display to both site administrators and users.'),
),
'#description' => t('Whether or not the generated password should display after a user account is created.'),
);
$form['#validate'][] = 'genpass_user_admin_settings_validate';
// Move the "When cancelling a user account" field down.
$form['registration_cancellation']['user_cancel_method']['#weight'] = 1;
//$form['actions']['submit']['#submit'][] = 'genpass_user_admin_settings_submit';
$form['#submit'][] = 'genpass_user_admin_settings_submit';
break;
// User registration form at admin/people/create
case 'user_register_form':
$mode = \Drupal::config('genpass.settings')->get('genpass_mode');
// Add validation function, where password may get set
$form['#validate'][] = 'genpass_register_validate';
// Administrator is creating the user
$current_path = \Drupal::service('path.current')->getPath();
if ($current_path == 'admin/user/user/create') {
// Switch to optional mode
$mode = GENPASS_OPTIONAL;
// Help avoid obvious consequence of password being optional
$notify_item =& _genpass_get_form_item($form, 'notify');
$notify_item['#description'] = t('This is recommended when auto-generating the password; otherwise, neither you nor the new user will know the password.');
}
// Pass mode to validation function
$form['genpass_mode'] = array(
'#type' => 'value',
'#value' => $mode,
);
$pass_item =& _genpass_get_form_item($form, 'pass');
switch ($mode) {
// If password is optional, don't require it, and give the user an
// indication of what will happen if left blank
case GENPASS_OPTIONAL:
$pass_item['#required'] = FALSE;
$pass_item['#description'] = (empty($pass_item['#description']) ? '' : $pass_item['#description'] . ' ') . t('If left blank, a password will be generated for you.');
break;
// If password is restricted, remove access
case GENPASS_RESTRICTED:
$pass_item['#access'] = FALSE;
$pass_item['#required'] = FALSE;
break;
}
break;
}
}
/**
* Salvataggio delle nuove impostazioni del FORM
*/
function genpass_user_admin_settings_submit($form, \Drupal\Core\Form\FormStateInterface $form_state) {
\Drupal::configFactory()->getEditable('genpass.settings')
->set('genpass_length', $form_state->getValue('genpass_length'))
->set('genpass_mode', $form_state->getValue('genpass_mode'))
->set('genpass_display', $form_state->getValue('genpass_display'))
->set('genpass_entropy', $form_state->getValue('genpass_entropy'))
->set('genpass_algorithm', $form_state->getValue('genpass_algorithm'))
->save();
}
/**
* User settings validation.
*/
function genpass_user_admin_settings_validate($form, \Drupal\Core\Form\FormStateInterface &$form_state) {
// Validate length of password
$length = $form_state->getValue('genpass_length');
if (!is_numeric($length) || $length < 5 || $length > 32) {
$form_state->setErrorByName('genpass_length', t('The length of a generated password must be between 5 and 32.'));
return;
}
$entropy = $form_state->getValue('genpass_entropy');
// Validate allowed characters
$chars = array_unique(preg_split('//', $entropy, -1, PREG_SPLIT_NO_EMPTY));
if (count($chars) < $length) {
$form_state->setErrorByName('genpass_entropy', t('The list of possible characters is not long or unique enough.'));
return;
}
return $form;
}
/**
* User registration validation.
*/
function genpass_register_validate($form, \Drupal\Core\Form\FormStateInterface &$form_state) {
if (empty($form_state->getValue('pass') && !$form_state->getErrors())) {
// Generate and set password
$pass = genpass_generate();
$pass_item =& _genpass_get_form_item($form, 'pass');
$form_state->setValueForElement($pass_item, $pass);
$display = Drupal::config('genpass.settings')->get('genpass_display');
// Administrator created the user.
$current_path = \Drupal::service('path.current')->getPath();
if ($current_path == 'admin/people/create') {
$message = t('Since you did not provide a password, it was generated automatically for this account.');
if (in_array($display, array(GENPASS_DISPLAY_ADMIN, GENPASS_DISPLAY_BOTH))) {
$message .= ' ' . t('The password is: <strong class="genpass-password">@password</strong>', array('@password' => $pass));
}
}
// Optional - User did not provide password, so it was generated
elseif ($form_state->getValue('genpass_mode') == GENPASS_OPTIONAL) {
$message = t('Since you did not provide a password, it was generated for you.');
if (in_array($display, array(GENPASS_DISPLAY_USER, GENPASS_DISPLAY_BOTH))) {
$message .= ' ' . t('Your password is: <strong class="genpass-password">@password</strong>', array('@password' => $pass));
}
}
// Restricted - User was forced to receive a generated password
elseif ($form_state->getValue('genpass_mode') == GENPASS_RESTRICTED && in_array($display, array(GENPASS_DISPLAY_USER, GENPASS_DISPLAY_BOTH))) {
$message = t('The following password was generated for you: <strong class="genpass-password">@password</strong>', array('@password' => $pass));
}
if (!empty($message)) {
drupal_set_message($message);
}
}
return $form;
}
/**
* Return an array of all modules which implement hook_password.
*
* @return array of module names.
*/
function genpass_algorithm_modules() {
// Fetch a list of all modules which implement the password generation hook.
// To be in this list, a module must implement a hook, and return random
// passwords as strings.
$return = array();
foreach (\Drupal::moduleHandler()->getImplementations('password') as $module) {
$return[$module] = $module;
}
return $return;
}
/**
* Return the currently activated module for generating passwords. Does some
* validation to make sure the variable contains a valid module name.
*
* @return the name of the module whose implementation of hook_password is
* currently the preferred implementation.
*/
function genpass_algorithm_module() {
$modules = genpass_algorithm_modules();
$module = \Drupal::config('genpass.settings')->get('genpass_algorithm');
if (in_array($module, array_keys($modules))) {
return $module;
}
else {
return 'genpass';
}
}
/**
* Adds some sample passwords to each module in an array.
*/
function genpass_add_samples($array) {
$return = array();
foreach ($array as $module => $name) {
$return[$module] = $module . ' (' . t('examples') . ': <strong>' . htmlentities(Drupal::moduleHandler()->invoke($module, 'password')) . '</strong>, <strong>' . htmlentities(Drupal::moduleHandler()->invoke($module, 'password')) . '</strong>)';
}
return $return;
}
/**
* Implements hook_token_info().
*/
function genpass_token_info() {
$info['tokens']['user']['password'] = array(
'name' => t('User password'),
'description' => t('Provides user password. May be used only during registration.'),
);
return $info;
}
/**
* Implements hook_tokens().
*/
function genpass_tokens($type, $tokens, array $data, array $options, \Drupal\Core\Render\BubbleableMetadata $bubbleable_metadata) {
$replacements = array();
foreach ($tokens as $name => $value) {
if ($name == 'password') {
if (isset($data['user']) && isset($data['user']->password)) {
$replacements['[user:password]'] = $data['user']->password;
$replacements['[account:password]'] = $data['user']->password;
}
elseif (isset($data['user']) && !isset($data['user']->password)) {
$replacements['[user:password]'] = t('Your password');
$replacements['[account:password]'] = t('Your password');
}
}
}
return $replacements;
}