LJSUP-17669: Login.bml form refactoring
[livejournal.git] / htdocs / lostinfo.bml
blobbd1c44e62fda3e569f77a530b5a8b92494434bbe
1 <?page
2 title=><?_ml .title _ml?>
3 body<=
4 <?_code
6     use strict;
7     use vars qw(%POST $headextra);
9     $headextra = LJ::need_res('stc/restore.css');
11     use Class::Autouse qw( Captcha::reCAPTCHA );
12     use POSIX qw(strftime);
14     LJ::set_active_crumb('lostinfo');
16     return LJ::server_down_html() if $LJ::SERVER_DOWN;
18     # no post action, just show query form
19     unless (LJ::did_post()) {
20         my $ret;
22 #        $ret .= "<?h1 $ML{'.title'} h1?>\n";
23         $ret .= "<?h1 $ML{'.recaptcha.title'} h1?>\n";
25         $ret .= "<form action='lostinfo.bml' method='post'>\n";
27         if (LJ::is_enabled("recaptcha")) {
28             my $c = Captcha::reCAPTCHA->new;
29             $ret .= $c->get_options_setter({ theme => 'white', lang => BML::get_language() });
30             $ret .= $c->get_html( LJ::conf_test($LJ::RECAPTCHA{public_key}), '', $LJ::IS_SSL ) . "<br />\n";
31         }
34         $ret .= "<?h1 $ML{'.lostpassword.title'} h1?>\n";
35         $ret .= "<?p $ML{'.lostpassword.text'} p?>\n";
37         $ret .= "<div class='form-basic form-fix'>\n";
38         $ret .= "<fieldset><label>$ML{'.enter_username'}</label>\n";
39         $ret .= LJ::html_text({ 'name' => 'user', 'id' => 'userlost', 'size' => 30, 'maxlength' => 15 }) . "</fieldset>\n";
40         $ret .= "<fieldset><label>$ML{'.enter_email_optional'}</label>\n";
41         $ret .= LJ::html_text({ 'name' => 'email_p', 'size' => 30, 'maxlength' => 50 }) . "</fieldset>\n";
42         $ret .= "<div class='btn-set'>\n";
43         $ret .= LJ::html_submit('lostpass', $ML{'.btn.proceed'}, { id => 'lostpass' }) . "</div>\n";
44         $ret .= "</div>\n";
46         $ret .= "<?h1 $ML{'.lostusername.title'} h1?>\n";
47         $ret .= "<?p $ML{'.lostusername.text'} p?>\n";
48         $ret .= "<div class='form-basic form-fix'>\n";
49         $ret .= "<fieldset><label>$ML{'.enter_email'}</label>\n";
50         $ret .= LJ::html_text({ 'name' => 'email_u', 'id' => 'email_u', 'size' => 30, 'maxlength' => 50 }) . "</fieldset>\n";
51         $ret .= "<div class='btn-set'>\n";
52         $ret .= LJ::html_submit('lostuser', $ML{'.btn.proceed'}, { id => 'lostuser' }) . "</div>\n";
53         $ret .= "</div>\n";
55         $ret .= "</form>\n";
57         return $ret;
58     }
60     # we have a post action
62     # note: some lostinfo_do.bml translation strings are used below
63     # because the code was once in lostinfo_do.bml, but later
64     # was merged into this file
66     if ($POST{'lostpass'}) {
68         if (LJ::is_enabled("recaptcha")) {
69             if ($POST{recaptcha_response_field}) {
70                 my $c = Captcha::reCAPTCHA->new;
71                 my $result = $c->check_answer(
72                     LJ::conf_test($LJ::RECAPTCHA{private_key}), $ENV{'REMOTE_ADDR'},
73                     $POST{'recaptcha_challenge_field'}, $POST{'recaptcha_response_field'}
74                 );
76                 return LJ::bad_input($ML{'.captcha.invalid'}) unless $result->{'is_valid'} eq '1';
77             } else {
78                 return LJ::bad_input($ML{'.captcha.invalid'});
79             }
80         }
82         my $email = LJ::trim($POST{'email_p'});
84         my $u = LJ::load_user($POST{'user'});
85         return LJ::bad_input($ML{'error.username_notfound'})
86             unless $u;
88         my $err = sub {
89             my ($title, $msg) = @_;
90             if ($title && ! $msg) {
91                 $msg = $title;
92                 $title = $ML{'Error'};
93             }
94             return "<?h1 $title h1?>\n<?p $msg p?>";
95         };
97         if ($u->{'journaltype'} eq 'Y') {
98             return $err->( $ML{'.error.syndicated'} );
99         }
101         if ($u->{'journaltype'} eq 'C' && !$u->has_password) {
102             # community with no password
103             return $err->( $ML{'.error.commnopassword'} );
104         }
106         if ($u->is_expunged) {
107             return $err->( $ML{'.error.purged'} );
108         }
110         if ($u->is_renamed) {
111             return $err->( $ML{'.error.renamed'} );
112         }
114         return LJ::bad_input($ML{'.error.toofrequent'}) unless LJ::rate_log($u, "lostinfo", 1);
116         # Check to see if they are banned from sending a password
117         if (LJ::sysban_check('lostpassword', $u->{'user'})) {
118             LJ::sysban_note($u->{'userid'}, "Password retrieval blocked based on user",
119                             { 'user' => $u->{'user'} });
120             return $err->( $ML{'Sorry'}, $ML{'.error.sysbanned'} );
121         }
123         if (LJ::sysban_check('lostpassword_email', $email)) {
124             LJ::sysban_note($u->{'userid'}, "Password retrieval blocked based on email",
125                             { 'email' => $email });
126             return $err->( $ML{'Sorry'}, $ML{'.error.sysbannedemail'} );
127         }
129         # check if this email address can receive password reminders
130         $email ||= $u->email_raw;
132         return LJ::bad_input($ML{'/lostinfo_do.bml.error1.text'})
133             unless $u->can_reset_password_using_email($email);
135         # email address is okay, build email body
136         my $encoding = 'utf-8';
137         my $subject = $ML{'/lostinfo_do.bml.lostpasswordmail.subject'};
139         if ($LJ::BLOCKED_PASSWORD_EMAIL && $email =~ /$LJ::BLOCKED_PASSWORD_EMAIL/) {
140             return LJ::bad_input('Invalid email');
141         }
143         my $body;
145         # register an auth action for them to reset their password
146         my $aa = LJ::register_authaction($u->{'userid'}, "reset_password", $email);
147         $body = BML::ml('/lostinfo_do.bml.lostpasswordmail.reset', {
148                             lostinfolink => "$LJ::SITEROOT/lostinfo.bml",
149                             sitename => $LJ::SITENAME,
150                             username => $u->{user},
151                             emailadr => $u->email_raw,
152                             resetlink => "$LJ::SITEROOT/changepassword.bml?auth=$aa->{aaid}.$aa->{authcode}",
153                         } );
154         $body .= "\n\n" .BML::ml('/lostinfo_do.bml.lostpasswordmail.part3',
155                          { 'remoteip' => BML::get_remote_host() . " (" . BML::get_remote_ip() . ")" });
156         $body .= "\n\n";
159         my $data = $u->get_email_data($email);
160         LJ::User::UserlogRecord::PasswordResetRequest->create( $u,
161             'email'       => $email,
162             'email_state' => $data->{'email_state'},
163             'time'        => $data->{'time'},
164         );
166         LJ::send_mail({
167             'to' => $email,
168             'from' => $LJ::DONOTREPLY_EMAIL,
169             'fromname' => $LJ::SITENAME,
170             'charset' => $encoding,
171             'subject' => $subject,
172             'body' => $body,
173         }) or die "Error: couldn't send email";
175         my $add_message = '';
177         unless ($LJ::DISABLED{'secret_question'}) {
178             my ($redir, $ml_key, $param) = LJ::run_hook('use_secret', $u);
179             return BML::redirect($redir) if $redir ne '';
181             $add_message = "<?p " . BML::ml($ml_key, { datetime => strftime("%d.%m.%Y %H:%M", gmtime($param)) } ) . " p?>" if $ml_key ne '';
182         }
184         return "<?h1 $ML{'/lostinfo_do.bml.password_mailed.title'} h1?>\n" .
185                "<?p $ML{'/lostinfo_do.bml.password_mailed.text'} p?>" . $add_message;
186     }
188     if ($POST{'lostuser'}) {
190         if (LJ::is_enabled("recaptcha")) {
191             if ($POST{recaptcha_response_field}) {
192                 my $c = Captcha::reCAPTCHA->new;
193                 my $result = $c->check_answer(
194                     LJ::conf_test($LJ::RECAPTCHA{private_key}), $ENV{'REMOTE_ADDR'},
195                     $POST{'recaptcha_challenge_field'}, $POST{'recaptcha_response_field'}
196                 );
198                 return LJ::bad_input($ML{'.captcha.invalid'}) unless $result->{'is_valid'} eq '1';
199             } else {
200                 return LJ::bad_input($ML{'.captcha.invalid'});
201             }
202         }
204         my $sendto = "";
205         my $email = LJ::trim($POST{'email_u'});
206         return LJ::bad_input($ML{'.error.no_email'})
207             unless $email;
209         my @users;
210         my $dbr = LJ::get_db_reader();
211         my $sth = $dbr->prepare("SELECT userid FROM email WHERE email=?");
212         $sth->execute($email);
213         while (my ($uid) = $sth->fetchrow_array) {
214             my $u = LJ::load_userid($uid);
215             next unless $u && $u->{clusterid};  # not purged
217             # As the idea is to limit spam to one e-mail address, if any of their username's are
218             # over the limit, then don't send them any more e-mail.
219             return LJ::bad_input($ML{'.error.toofrequent'}) unless LJ::rate_log($u, "lostinfo", 1);
220             push @users, $u->{user};
221         }
223         return LJ::bad_input(BML::ml('/lostinfo_do.bml.error.no_usernames_for_email',
224                                      { 'address' => LJ::ehtml($email) || 'none' }))
225             unless @users;
227         # we have valid usernames, build email body
228         my $body;
229         $body .= "This is your requested username reminder from $LJ::SITENAME.  ";
230         $body .= "Below are the usernames you have registered for the email address $email:\n\n";
232         $body .= "          $_\n" foreach @users;
234         $body .= "\nThis information was requested on the website from " . BML::get_remote_host() .
235                  " (" . BML::get_remote_ip() . ").\n\n";
236         $body .= "Regards,\n$LJ::SITENAME Team\n\n$LJ::SITEROOT/\n";
238         LJ::send_mail({
239             'to' => $email,
240             'from' => $LJ::DONOTREPLY_EMAIL,
241             'fromname' => $LJ::SITENAME,
242             'charset' => 'utf-8',
243             'subject' => "Lost Username",
244             'body' => $body,
245         }) or die "Error: couldn't send email";
247         return "<?h1 $ML{'/lostinfo_do.bml.username_mailed.title'} h1?>\n" .
248                "<?p $ML{'/lostinfo_do.bml.username_mailed.text'} p?>";
249     }
251     # post, but they didn't press a button?
252     return $ML{'error.nobutton'};
254 _code?>
255 <=body
256 page?><?_c <LJDEP>
257 post: htdocs/lostinfo.bml
258 </LJDEP> _c?>