2 title=><?_ml .title _ml?>
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()) {
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";
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";
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";
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'}
76 return LJ::bad_input($ML{'.captcha.invalid'}) unless $result->{'is_valid'} eq '1';
78 return LJ::bad_input($ML{'.captcha.invalid'});
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'})
89 my ($title, $msg) = @_;
90 if ($title && ! $msg) {
92 $title = $ML{'Error'};
94 return "<?h1 $title h1?>\n<?p $msg p?>";
97 if ($u->{'journaltype'} eq 'Y') {
98 return $err->( $ML{'.error.syndicated'} );
101 if ($u->{'journaltype'} eq 'C' && !$u->has_password) {
102 # community with no password
103 return $err->( $ML{'.error.commnopassword'} );
106 if ($u->is_expunged) {
107 return $err->( $ML{'.error.purged'} );
110 if ($u->is_renamed) {
111 return $err->( $ML{'.error.renamed'} );
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'} );
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'} );
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');
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}",
154 $body .= "\n\n" .BML::ml('/lostinfo_do.bml.lostpasswordmail.part3',
155 { 'remoteip' => BML::get_remote_host() . " (" . BML::get_remote_ip() . ")" });
159 my $data = $u->get_email_data($email);
160 LJ::User::UserlogRecord::PasswordResetRequest->create( $u,
162 'email_state' => $data->{'email_state'},
163 'time' => $data->{'time'},
168 'from' => $LJ::DONOTREPLY_EMAIL,
169 'fromname' => $LJ::SITENAME,
170 'charset' => $encoding,
171 'subject' => $subject,
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 '';
184 return "<?h1 $ML{'/lostinfo_do.bml.password_mailed.title'} h1?>\n" .
185 "<?p $ML{'/lostinfo_do.bml.password_mailed.text'} p?>" . $add_message;
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'}
198 return LJ::bad_input($ML{'.captcha.invalid'}) unless $result->{'is_valid'} eq '1';
200 return LJ::bad_input($ML{'.captcha.invalid'});
205 my $email = LJ::trim($POST{'email_u'});
206 return LJ::bad_input($ML{'.error.no_email'})
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};
223 return LJ::bad_input(BML::ml('/lostinfo_do.bml.error.no_usernames_for_email',
224 { 'address' => LJ::ehtml($email) || 'none' }))
227 # we have valid usernames, build email 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";
240 'from' => $LJ::DONOTREPLY_EMAIL,
241 'fromname' => $LJ::SITENAME,
242 'charset' => 'utf-8',
243 'subject' => "Lost Username",
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?>";
251 # post, but they didn't press a button?
252 return $ML{'error.nobutton'};
257 post: htdocs/lostinfo.bml