|
1
|
|
|
<?php |
|
2
|
|
|
/****************************************************************************** |
|
3
|
|
|
* Wikipedia Account Creation Assistance tool * |
|
4
|
|
|
* * |
|
5
|
|
|
* All code in this file is released into the public domain by the ACC * |
|
6
|
|
|
* Development Team. Please see team.json for a list of contributors. * |
|
7
|
|
|
******************************************************************************/ |
|
8
|
|
|
|
|
9
|
|
|
namespace Waca\Pages; |
|
10
|
|
|
|
|
11
|
|
|
use Waca\DataObjects\User; |
|
12
|
|
|
use Waca\Exceptions\ApplicationLogicException; |
|
13
|
|
|
use Waca\PdoDatabase; |
|
14
|
|
|
use Waca\Security\SecurityConfiguration; |
|
15
|
|
|
use Waca\SessionAlert; |
|
16
|
|
|
use Waca\Tasks\InternalPageBase; |
|
17
|
|
|
use Waca\WebRequest; |
|
18
|
|
|
|
|
19
|
|
|
class PageForgotPassword extends InternalPageBase |
|
20
|
|
|
{ |
|
21
|
|
|
/** |
|
22
|
|
|
* Main function for this page, when no specific actions are called. |
|
23
|
|
|
* |
|
24
|
|
|
* This is the forgotten password reset form |
|
25
|
|
|
* @category Security-Critical |
|
26
|
|
|
*/ |
|
27
|
|
|
protected function main() |
|
28
|
|
|
{ |
|
29
|
|
|
if (WebRequest::wasPosted()) { |
|
30
|
|
|
$this->validateCSRFToken(); |
|
31
|
|
|
$username = WebRequest::postString('username'); |
|
32
|
|
|
$email = WebRequest::postEmail('email'); |
|
33
|
|
|
$database = $this->getDatabase(); |
|
34
|
|
|
|
|
35
|
|
View Code Duplication |
if ($username === null || trim($username) === "" || $email === null || trim($email) === "") { |
|
|
|
|
|
|
36
|
|
|
throw new ApplicationLogicException("Both username and email address must be specified!"); |
|
37
|
|
|
} |
|
38
|
|
|
|
|
39
|
|
|
$user = User::getByUsername($username, $database); |
|
40
|
|
|
$this->sendResetMail($user, $email); |
|
41
|
|
|
|
|
42
|
|
|
SessionAlert::success('<strong>Your password reset request has been completed.</strong> Please check your e-mail.'); |
|
43
|
|
|
|
|
44
|
|
|
$this->redirect('login'); |
|
45
|
|
|
} |
|
46
|
|
|
else { |
|
47
|
|
|
$this->assignCSRFToken(); |
|
48
|
|
|
$this->setTemplate('forgot-password/forgotpw.tpl'); |
|
49
|
|
|
} |
|
50
|
|
|
} |
|
51
|
|
|
|
|
52
|
|
|
/** |
|
53
|
|
|
* Sends a reset email if the user is authenticated |
|
54
|
|
|
* |
|
55
|
|
|
* @param User|boolean $user The user located from the database, or false. Doesn't really matter, since we do the |
|
56
|
|
|
* check anyway within this method and silently skip if we don't have a user. |
|
57
|
|
|
* @param string $email The provided email address |
|
58
|
|
|
*/ |
|
59
|
|
|
private function sendResetMail($user, $email) |
|
60
|
|
|
{ |
|
61
|
|
|
// If the user isn't found, or the email address is wrong, skip sending the details silently. |
|
62
|
|
|
if (!$user instanceof User) { |
|
63
|
|
|
return; |
|
64
|
|
|
} |
|
65
|
|
|
|
|
66
|
|
|
if (strtolower($user->getEmail()) === strtolower($email)) { |
|
67
|
|
|
$clientIp = $this->getXffTrustProvider() |
|
68
|
|
|
->getTrustedClientIp(WebRequest::remoteAddress(), WebRequest::forwardedAddress()); |
|
69
|
|
|
|
|
70
|
|
|
$this->assign("user", $user); |
|
71
|
|
|
$this->assign("hash", $user->getForgottenPasswordHash()); |
|
72
|
|
|
$this->assign("remoteAddress", $clientIp); |
|
73
|
|
|
|
|
74
|
|
|
$emailContent = $this->fetchTemplate('forgot-password/reset-mail.tpl'); |
|
75
|
|
|
|
|
76
|
|
|
$this->getEmailHelper()->sendMail($user->getEmail(), "", $emailContent); |
|
77
|
|
|
} |
|
78
|
|
|
} |
|
79
|
|
|
|
|
80
|
|
|
/** |
|
81
|
|
|
* Entry point for the reset action |
|
82
|
|
|
* |
|
83
|
|
|
* This is the reset password part of the form. |
|
84
|
|
|
* @category Security-Critical |
|
85
|
|
|
*/ |
|
86
|
|
|
protected function reset() |
|
87
|
|
|
{ |
|
88
|
|
|
$si = WebRequest::getString('si'); |
|
89
|
|
|
$id = WebRequest::getString('id'); |
|
90
|
|
|
|
|
91
|
|
|
if ($si === null || trim($si) === "" || $id === null || trim($id) === "") { |
|
92
|
|
|
throw new ApplicationLogicException("Link not valid, please ensure it has copied correctly"); |
|
93
|
|
|
} |
|
94
|
|
|
|
|
95
|
|
|
$database = $this->getDatabase(); |
|
96
|
|
|
$user = $this->getResettingUser($id, $database, $si); |
|
97
|
|
|
|
|
98
|
|
|
// Dual mode |
|
99
|
|
|
if (WebRequest::wasPosted()) { |
|
100
|
|
|
$this->validateCSRFToken(); |
|
101
|
|
|
try { |
|
102
|
|
|
$this->doReset($user); |
|
103
|
|
|
} |
|
104
|
|
|
catch (ApplicationLogicException $ex) { |
|
105
|
|
|
SessionAlert::error($ex->getMessage()); |
|
106
|
|
|
$this->redirect('forgotPassword', 'reset', array('si' => $si, 'id' => $id)); |
|
107
|
|
|
|
|
108
|
|
|
return; |
|
109
|
|
|
} |
|
110
|
|
|
} |
|
111
|
|
|
else { |
|
112
|
|
|
$this->assignCSRFToken(); |
|
113
|
|
|
$this->assign('user', $user); |
|
114
|
|
|
$this->setTemplate('forgot-password/forgotpwreset.tpl'); |
|
115
|
|
|
} |
|
116
|
|
|
} |
|
117
|
|
|
|
|
118
|
|
|
/** |
|
119
|
|
|
* Gets the user resetting their password from the database, or throwing an exception if that is not possible. |
|
120
|
|
|
* |
|
121
|
|
|
* @param integer $id The ID of the user to retrieve |
|
122
|
|
|
* @param PdoDatabase $database The database object to use |
|
123
|
|
|
* @param string $si The reset hash provided |
|
124
|
|
|
* |
|
125
|
|
|
* @return User |
|
126
|
|
|
* @throws ApplicationLogicException |
|
127
|
|
|
*/ |
|
128
|
|
|
private function getResettingUser($id, $database, $si) |
|
129
|
|
|
{ |
|
130
|
|
|
$user = User::getById($id, $database); |
|
131
|
|
|
|
|
132
|
|
|
if ($user === false || $user->getForgottenPasswordHash() !== $si || $user->isCommunityUser()) { |
|
133
|
|
|
throw new ApplicationLogicException("User not found"); |
|
134
|
|
|
} |
|
135
|
|
|
|
|
136
|
|
|
return $user; |
|
137
|
|
|
} |
|
138
|
|
|
|
|
139
|
|
|
/** |
|
140
|
|
|
* Performs the setting of the new password |
|
141
|
|
|
* |
|
142
|
|
|
* @param User $user The user to set the password for |
|
143
|
|
|
* |
|
144
|
|
|
* @throws ApplicationLogicException |
|
145
|
|
|
*/ |
|
146
|
|
|
private function doReset(User $user) |
|
147
|
|
|
{ |
|
148
|
|
|
$pw = WebRequest::postString('pw'); |
|
149
|
|
|
$pw2 = WebRequest::postString('pw2'); |
|
150
|
|
|
|
|
151
|
|
|
if ($pw !== $pw2) { |
|
152
|
|
|
throw new ApplicationLogicException('Passwords do not match!'); |
|
153
|
|
|
} |
|
154
|
|
|
|
|
155
|
|
|
$user->setPassword($pw); |
|
156
|
|
|
$user->save(); |
|
157
|
|
|
|
|
158
|
|
|
SessionAlert::success('You may now log in!'); |
|
159
|
|
|
$this->redirect('login'); |
|
160
|
|
|
} |
|
161
|
|
|
|
|
162
|
|
|
/** |
|
163
|
|
|
* Sets up the security for this page. If certain actions have different permissions, this should be reflected in |
|
164
|
|
|
* the return value from this function. |
|
165
|
|
|
* |
|
166
|
|
|
* If this page even supports actions, you will need to check the route |
|
167
|
|
|
* |
|
168
|
|
|
* @return SecurityConfiguration |
|
169
|
|
|
* @category Security-Critical |
|
170
|
|
|
*/ |
|
171
|
|
|
protected function getSecurityConfiguration() |
|
172
|
|
|
{ |
|
173
|
|
|
return $this->getSecurityManager()->configure()->asPublicPage(); |
|
174
|
|
|
} |
|
175
|
|
|
} |
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.
You can also find more detailed suggestions in the “Code” section of your repository.