Passed
Push — master ( c0a3a7...3b84a4 )
by Jeroen
58:51
created

mod/uservalidationbyemail/start.php (1 issue)

1
<?php
2
/**
3
 * Email user validation plugin.
4
 * Non-admin accounts are invalid until their email address is confirmed.
5
 *
6
 * @package Elgg.Core.Plugin
7
 * @subpackage UserValidationByEmail
8
 */
9
10
/**
11
 * User validation by email init
12
 *
13
 * @return void
14
 */
15
function uservalidationbyemail_init() {
16
17 31
	require_once dirname(__FILE__) . '/lib/functions.php';
18
19
	// Register page handler to validate users
20
	// This doesn't need to be an action because security is handled by the validation codes.
21 31
	elgg_register_page_handler('uservalidationbyemail', 'uservalidationbyemail_page_handler');
22
23
	// mark users as unvalidated and disable when they register
24 31
	elgg_register_plugin_hook_handler('register', 'user', 'uservalidationbyemail_disable_new_user');
25
26
	// forward to uservalidationbyemail/emailsent page after register
27 31
	elgg_register_plugin_hook_handler('response', 'action:register', 'uservalidationbyemail_after_registration_url');
28
29
	// canEdit override to allow not logged in code to disable a user
30 31
	elgg_register_plugin_hook_handler('permissions_check', 'user', 'uservalidationbyemail_allow_new_user_can_edit');
31
32
	// prevent users from logging in if they aren't validated
33 31
	register_pam_handler('uservalidationbyemail_check_auth_attempt', "required");
34
35
	// prevent the engine from logging in users via login()
36 31
	elgg_register_event_handler('login:before', 'user', 'uservalidationbyemail_check_manual_login');
37
38
	// make admin users always validated
39 31
	elgg_register_event_handler('make_admin', 'user', 'uservalidationbyemail_validate_new_admin_user');
40
41
	// register Walled Garden public pages
42 31
	elgg_register_plugin_hook_handler('public_pages', 'walled_garden', 'uservalidationbyemail_public_pages');
43
44
	// admin interface to manually validate users
45 31
	elgg_register_menu_item('page', [
46 31
		'name' => 'users:unvalidated',
47 31
		'text' => elgg_echo('admin:users:unvalidated'),
48 31
		'href' => 'admin/users/unvalidated',
49 31
		'section' => 'administer',
50 31
		'parent_name' => 'users',
51 31
		'context' => 'admin',
52
	]);
53
	
54 31
	elgg_extend_view('admin.css', 'uservalidationbyemail/css');
55 31
}
56
57
/**
58
 * Disables a user upon registration
59
 *
60
 * @param string $hook   'register'
61
 * @param string $type   'user'
62
 * @param bool   $value  current return value
63
 * @param array  $params supplied params
64
 *
65
 * @return void
66
 */
67
function uservalidationbyemail_disable_new_user($hook, $type, $value, $params) {
68
	
69
	$user = elgg_extract('user', $params);
70
	// no clue what's going on, so don't react.
71
	if (!$user instanceof ElggUser) {
72
		return;
73
	}
74
75
	// another plugin is requesting that registration be terminated
76
	// no need for uservalidationbyemail
77
	if (!$value) {
78
		return;
79
	}
80
81
	// has the user already been validated?
82
	if ($user->isValidated()) {
83
		return;
84
	}
85
86
	// disable user to prevent showing up on the site
87
	// set context so our canEdit() override works
88
	elgg_push_context('uservalidationbyemail_new_user');
89
	$hidden_entities = access_show_hidden_entities(true);
90
91
	// Don't do a recursive disable.  Any entities owned by the user at this point
92
	// are products of plugins that hook into create user and might need
93
	// access to the entities.
94
	// @todo That ^ sounds like a specific case...would be nice to track it down...
95
	$user->disable('uservalidationbyemail_new_user', false);
96
97
	// set user as unvalidated and send out validation email
98
	$user->setValidationStatus(false);
99
	uservalidationbyemail_request_validation($user->guid);
100
101
	elgg_pop_context();
102
	access_show_hidden_entities($hidden_entities);
103
}
104
105
/**
106
 * Override the URL to be forwarded after registration
107
 *
108
 * @param string                     $hook   'response'
109
 * @param string                     $type   'action:register'
110
 * @param \Elgg\Http\ResponseBuilder $value  Current response
111
 * @param array                      $params Additional params
112
 *
113
 * @return void|\Elgg\Http\ResponseBuilder
114
 */
115
function uservalidationbyemail_after_registration_url($hook, $type, $value, $params) {
116
	$session = elgg_get_session();
117
	$email = $session->get('emailsent', '');
118
	if ($email) {
119
		$value->setForwardURL(elgg_normalize_url('uservalidationbyemail/emailsent'));
120
		return $value;
121
	}
122
}
123
124
/**
125
 * Override the canEdit() call for if we're in the context of registering a new user.
126
 *
127
 * @param string $hook   'permissions_check'
128
 * @param string $type   'user'
129
 * @param bool   $value  current return value
130
 * @param array  $params supplied params
131
 *
132
 * @return void|true
133
 */
134
function uservalidationbyemail_allow_new_user_can_edit($hook, $type, $value, $params) {
135
	
136
	// $params['user'] is the user to check permissions for.
137
	// we want the entity to check, which is a user.
138 92
	$user = elgg_extract('entity', $params);
139 92
	if (!($user instanceof ElggUser)) {
140
		return;
141
	}
142
143 92
	$context = elgg_get_context();
144 92
	if ($context == 'uservalidationbyemail_new_user' || $context == 'uservalidationbyemail_validate_user') {
145
		return true;
146
	}
147 92
}
148
149
/**
150
 * Checks if an account is validated
151
 *
152
 * @param array $credentials The username and password
153
 *
154
 * @return void
155
 */
156
function uservalidationbyemail_check_auth_attempt($credentials) {
157
158 9
	if (!isset($credentials['username'])) {
159 2
		return;
160
	}
161
162 7
	$username = $credentials['username'];
163
164
	// See if the user exists and isn't validated
165 7
	$access_status = access_show_hidden_entities(true);
166
	
167
	// check if logging in with email address
168 7
	if (strpos($username, '@') !== false) {
169
		$users = get_user_by_email($username);
170
		if ($users) {
171
			$username = $users[0]->username;
172
		}
173
	}
174
175 7
	$user = get_user_by_username($username);
176 7
	if ($user && isset($user->validated) && !$user->validated) {
177
		// show an error and resend validation email
178
		uservalidationbyemail_request_validation($user->guid);
179
		access_show_hidden_entities($access_status);
180
		throw new LoginException(elgg_echo('uservalidationbyemail:login:fail'));
181
	}
182
183 7
	access_show_hidden_entities($access_status);
184 7
}
185
186
/**
187
 * Checks sent passed validation code and user guids and validates the user.
188
 *
189
 * @param array $page URL segments
190
 *
191
 * @return bool
192
 */
193
function uservalidationbyemail_page_handler($page) {
194
	
195
	switch ($page[0]) {
196
		case 'confirm':
197
			echo elgg_view_resource("uservalidationbyemail/confirm");
198
			return true;
199
		case 'emailsent':
200
			echo elgg_view_resource("uservalidationbyemail/emailsent");
201
			return true;
202
		default:
203
			forward('', '404');
204
			return false;
205
	}
206
}
207
208
/**
209
 * Make sure any admin users are automatically validated
210
 *
211
 * @param string   $event 'make_admin'
212
 * @param string   $type  'user'
213
 * @param ElggUser $user  the user
214
 *
215
 * @return void
216
 */
217
function uservalidationbyemail_validate_new_admin_user($event, $type, $user) {
218 6
	if ($user instanceof ElggUser && !$user->isValidated()) {
0 ignored issues
show
Bug Best Practice introduced by Jeroen Dalsem
The expression $user->isValidated() of type null|boolean is loosely compared to false; this is ambiguous if the boolean can be false. You might want to explicitly use !== null instead.

If an expression can have both false, and null as possible values. It is generally a good practice to always use strict comparison to clearly distinguish between those two values.

$a = canBeFalseAndNull();

// Instead of
if ( ! $a) { }

// Better use one of the explicit versions:
if ($a !== null) { }
if ($a !== false) { }
if ($a !== null && $a !== false) { }
Loading history...
219 6
		$user->setValidationStatus(true, 'admin_user');
220
	}
221 6
}
222
223
/**
224
 * Registers public pages to allow in the case walled garden has been enabled
225
 *
226
 * @param string $hook         'public_pages'
227
 * @param string $type         'walled_garden'
228
 * @param array  $return_value current return value
229
 * @param mixed  $params       supplied params
230
 *
231
 * @return array
232
 */
233
function uservalidationbyemail_public_pages($hook, $type, $return_value, $params) {
234
	$return_value[] = 'uservalidationbyemail/confirm';
235
	$return_value[] = 'uservalidationbyemail/emailsent';
236
	return $return_value;
237
}
238
239
/**
240
 * Prevent a manual code login with login()
241
 *
242
 * @param string   $event 'login:before'
243
 * @param string   $type  'user'
244
 * @param ElggUser $user  the user
245
 *
246
 * @return void
247
 *
248
 * @throws LoginException
249
 */
250
function uservalidationbyemail_check_manual_login($event, $type, $user) {
251
	
252 5
	$access_status = access_show_hidden_entities(true);
253
	
254 5
	if (($user instanceof ElggUser) && !$user->isEnabled() && !$user->validated) {
255
		// send new validation email
256
		uservalidationbyemail_request_validation($user->getGUID());
257
		
258
		// restore hidden entities settings
259
		access_show_hidden_entities($access_status);
260
		
261
		// throw error so we get a nice error message
262
		throw new LoginException(elgg_echo('uservalidationbyemail:login:fail'));
263
	}
264
265 5
	access_show_hidden_entities($access_status);
266 5
}
267
268
return function() {
269 18
	elgg_register_event_handler('init', 'system', 'uservalidationbyemail_init');
270
};
271