]> git.mxchange.org Git - quix0rs-gnu-social.git/blob - actions/recoverpassword.php
c9813bcd08b678b4d2a4a40bd8db8107cb096cc5
[quix0rs-gnu-social.git] / actions / recoverpassword.php
1 <?php
2 /*
3  * Laconica - a distributed open-source microblogging tool
4  * Copyright (C) 2008, Controlez-Vous, Inc.
5  *
6  * This program is free software: you can redistribute it and/or modify
7  * it under the terms of the GNU Affero General Public License as published by
8  * the Free Software Foundation, either version 3 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU Affero General Public License for more details.
15  *
16  * You should have received a copy of the GNU Affero General Public License
17  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
18  */
19
20 if (!defined('LACONICA')) { exit(1); }
21
22 # You have 24 hours to claim your password
23
24 define(MAX_RECOVERY_TIME, 24 * 60 * 60);
25
26 class RecoverpasswordAction extends Action {
27
28     function handle($args) {
29         parent::handle($args);
30         if (common_logged_in()) {
31                         $this->client_error(_('You are already logged in!'));
32             return;
33         } else if ($_SERVER['REQUEST_METHOD'] == 'POST') {
34                 if ($this->arg('recover')) {
35                 $this->recover_password();
36             } else if ($this->arg('reset')) {
37                 $this->reset_password();
38                         } else {
39                                 $this->client_error(_('Unexpected form submission.'));
40                         }
41                 } else {
42                         if ($this->trimmed('code')) {
43                         $this->check_code();
44                 } else {
45                         $this->show_form();
46                         }
47                 }
48         }
49
50         function check_code() {
51
52                 $code = $this->trimmed('code');
53                 $confirm = Confirm_address::staticGet('code', $code);
54
55                 if (!$confirm) {
56                         $this->client_error(_('No such recovery code.'));
57                         return;
58                 }
59                 if ($confirm->address_type != 'recover') {
60                         $this->client_error(_('Not a recovery code.'));
61                         return;
62                 }
63
64                 $user = User::staticGet($confirm->user_id);
65
66                 if (!$user) {
67                         $this->server_error(_('Recovery code for unknown user.'));
68                         return;
69                 }
70
71                 $touched = strtotime($confirm->modified);
72                 $email = $confirm->address;
73
74                 # Burn this code
75
76                 $result = $confirm->delete();
77
78                 if (!$result) {
79                         common_log_db_error($confirm, 'DELETE', __FILE__);
80                         common_server_error(_('Error with confirmation code.'));
81                         return;
82                 }
83
84                 # These should be reaped, but for now we just check mod time
85                 # Note: it's still deleted; let's avoid a second attempt!
86
87                 if ((time() - $touched) > MAX_RECOVERY_TIME) {
88                         common_log(LOG_WARNING, 
89                                            'Attempted redemption on recovery code ' .
90                                            'that is ' . $touched . ' seconds old. ');
91                         $this->client_error(_('This confirmation code is too old. ' .
92                                                'Please start again.'));
93                         return;
94                 }
95
96                 # If we used an outstanding confirmation to send the email,
97                 # it's been confirmed at this point.
98
99                 if (!$user->email) {
100                         $orig = clone($user);
101                         $user->email = $email;
102                         $result = $user->updateKeys($orig);
103                         if (!$result) {
104                                 common_log_db_error($user, 'UPDATE', __FILE__);
105                                 $this->server_error(_('Could not update user with confirmed email address.'));
106                                 return;
107                         }
108                 }
109
110                 # Success!
111
112                 $this->set_temp_user($user);
113                 $this->show_password_form();
114         }
115
116         function set_temp_user(&$user) {
117                 common_ensure_session();
118                 $_SESSION['tempuser'] = $user->id;
119         }
120
121         function get_temp_user() {
122                 common_ensure_session();
123                 $user_id = $_SESSION['tempuser'];
124                 if ($user_id) {
125                         $user = User::staticGet($user_id);
126                 }
127                 return $user;
128         }
129
130         function clear_temp_user() {
131                 common_ensure_session();
132                 unset($_SESSION['tempuser']);
133         }
134
135         function show_top($msg=NULL) {
136                 if ($msg) {
137             common_element('div', 'error', $msg);
138                 } else {
139                         common_element('div', 'instructions',
140                                                    _('If you\'ve forgotten or lost your' .
141                                                       ' password, you can get a new one sent to' .
142                                                       ' the email address you have stored ' .
143                                                       ' in your account.'));
144                 }
145         }
146
147         function show_password_top($msg=NULL) {
148                 if ($msg) {
149             common_element('div', 'error', $msg);
150                 } else {
151                         common_element('div', 'instructions',
152                                                    _('You\'ve been identified. Enter a ' .
153                                                       ' new password below. '));
154                 }
155         }
156
157         function show_form($msg=NULL) {
158
159                 common_show_header(_('Recover password'), NULL,
160                 $msg, array($this, 'show_top'));
161
162                 common_element_start('form', array('method' => 'post',
163                                                                                    'id' => 'recoverpassword',
164                                                                                    'action' => common_local_url('recoverpassword')));
165                 common_input('nicknameoremail', _('Nickname or email'),
166                                          $this->trimmed('nicknameoremail'),
167                              _('Your nickname on this server, ' .
168                                 'or your registered email address.'));
169                 common_submit('recover', _('Recover'));
170                 common_element_end('form');
171                 common_show_footer();
172         }
173
174         function show_password_form($msg=NULL) {
175
176                 common_show_header(_('Reset password'), NULL,
177                 $msg, array($this, 'show_password_top'));
178
179                 common_element_start('form', array('method' => 'post',
180                                                                                    'id' => 'recoverpassword',
181                                                                                    'action' => common_local_url('recoverpassword')));
182                 common_hidden('token', common_session_token());
183                 common_password('newpassword', _('New password'),
184                                                 _('6 or more characters, and don\'t forget it!'));
185                 common_password('confirm', _('Confirm'),
186                                                 _('Same as password above'));
187                 common_submit('reset', _('Reset'));
188                 common_element_end('form');
189                 common_show_footer();
190         }
191
192         function recover_password() {
193                 $nore = $this->trimmed('nicknameoremail');
194                 if (!$nore) {
195                         $this->show_form(_('Enter a nickname or email address.'));
196                         return;
197                 }
198
199                 $user = User::staticGet('email', common_canonical_email($nore));
200
201                 if (!$user) {
202                         $user = User::staticGet('nickname', common_canonical_nickname($nore));
203                 }
204
205                 # See if it's an unconfirmed email address
206
207                 if (!$user) {
208                         $confirm_email = Confirm_address::staticGet('address', common_canonical_email($nore));
209                         if ($confirm_email && $confirm_email->address_type == 'email') {
210                                 $user = User::staticGet($confirm_email->user_id);
211                         }
212                 }
213
214                 if (!$user) {
215                         $this->show_form(_('No user with that email address or username.'));
216                         return;
217                 }
218
219                 # Try to get an unconfirmed email address if they used a user name
220
221                 if (!$user->email && !$confirm_email) {
222                         $confirm_email = Confirm_address::staticGet('user_id', $user->id);
223                         if ($confirm_email && $confirm_email->address_type != 'email') {
224                                 # Skip non-email confirmations
225                                 $confirm_email = NULL;
226                         }
227                 }
228
229                 if (!$user->email && !$confirm_email) {
230                         $this->client_error(_('No registered email address for that user.'));
231                         return;
232                 }
233
234                 # Success! We have a valid user and a confirmed or unconfirmed email address
235
236                 $confirm = new Confirm_address();
237                 $confirm->code = common_confirmation_code(128);
238                 $confirm->address_type = 'recover';
239                 $confirm->user_id = $user->id;
240                 $confirm->address = (isset($user->email)) ? $user->email : $confirm_email->address;
241
242                 if (!$confirm->insert()) {
243                         common_log_db_error($confirm, 'INSERT', __FILE__);
244                         $this->server_error(_('Error saving address confirmation.'));
245                         return;
246                 }
247
248                 $body = "Hey, $user->nickname.";
249                 $body .= "\n\n";
250                 $body .= 'Someone just asked for a new password ' .
251                          'for this account on ' . common_config('site', 'name') . '.';
252                 $body .= "\n\n";
253                 $body .= 'If it was you, and you want to confirm, use the URL below:';
254                 $body .= "\n\n";
255                 $body .= "\t".common_local_url('recoverpassword',
256                                                                    array('code' => $confirm->code));
257                 $body .= "\n\n";
258                 $body .= 'If not, just ignore this message.';
259                 $body .= "\n\n";
260                 $body .= 'Thanks for your time, ';
261                 $body .= "\n";
262                 $body .= common_config('site', 'name');
263                 $body .= "\n";
264
265                 mail_to_user($user, _('Password recovery requested'), $body, $confirm->address);
266
267                 common_show_header(_('Password recovery requested'));
268                 common_element('p', NULL,
269                                _('Instructions for recovering your password ' .
270                                   'have been sent to the email address registered to your ' .
271                                   'account.'));
272                 common_show_footer();
273         }
274
275         function reset_password() {
276
277                 # CSRF protection
278                 $token = $this->trimmed('token');
279                 if (!$token || $token != common_session_token()) {
280                         $this->show_form(_('There was a problem with your session token. Try again, please.'));
281                         return;
282                 }
283
284                 $user = $this->get_temp_user();
285
286                 if (!$user) {
287                         $this->client_error(_('Unexpected password reset.'));
288                         return;
289                 }
290
291                 $newpassword = $this->trimmed('newpassword');
292                 $confirm = $this->trimmed('confirm');
293
294                 if (!$newpassword || strlen($newpassword) < 6) {
295                         $this->show_password_form(_('Password must be 6 chars or more.'));
296                         return;
297                 }
298                 if ($newpassword != $confirm) {
299                         $this->show_password_form(_('Password and confirmation do not match.'));
300                         return;
301                 }
302
303                 # OK, we're ready to go
304
305                 $original = clone($user);
306
307                 $user->password = common_munge_password($newpassword, $user->id);
308
309                 if (!$user->update($original)) {
310                         common_log_db_error($user, 'UPDATE', __FILE__);
311                         common_server_error(_('Can\'t save new password.'));
312                         return;
313                 }
314
315                 $this->clear_temp_user();
316
317                 if (!common_set_user($user->nickname)) {
318                         common_server_error(_('Error setting user.'));
319                         return;
320                 }
321
322                 common_real_login(true);
323
324                 common_show_header(_('Password saved.'));
325                 common_element('p', NULL, _('New password successfully saved. ' .
326                                              'You are now logged in.'));
327                 common_show_footer();
328         }
329 }