feat: reset_password
All checks were successful
continuous-integration/drone/push Build is passing

This commit is contained in:
Baoshuo Ren 2023-01-15 20:01:37 +08:00
parent 4226b25e91
commit e43444e02d
Signed by: baoshuo
GPG Key ID: 00CB9680AB29F51A
2 changed files with 199 additions and 127 deletions

View File

@ -1,9 +1,15 @@
<?php <?php
requirePHPLib('form'); requirePHPLib('form');
$forgot_form = new UOJBs4Form('forgot'); use Gregwar\Captcha\PhraseBuilder;
$forgot_form->addInput('username', 'text', '用户名', '',
function($username, &$vdata) { $forgot_form = new UOJBs4Form('forgot');
$forgot_form->addInput(
'username',
'text',
'用户名',
'',
function ($username, &$vdata) {
if (!validateUsername($username)) { if (!validateUsername($username)) {
return '用户名不合法'; return '用户名不合法';
} }
@ -14,46 +20,96 @@
return ''; return '';
}, },
null null
); );
$forgot_form->handle = function(&$vdata) { $forgot_form->appendHTML(<<<EOD
<div id="div-captcha" class="form-group">
<label for="input-captcha" class="col-sm-2 control-label">验证码</label>
<div class="col-sm-3" style="max-width: 60%">
<input type="text" class="form-control" id="input-captcha" name="captcha" placeholder="请输入验证码" maxlength="20" style="display: inline-block; width: 12em;" />
<div style="display: inline-block; margin-left: 8px; position: relative; top: -2px; cursor: pointer;">
<img id="captcha" src="" />
</div>
<span class="help-block" id="help-captcha" style="display: block"></span>
</div>
</div>
EOD);
$forgot_form->handle = function (&$vdata) {
$user = $vdata['user']; $user = $vdata['user'];
$password = $user["password"]; $password = $user["password"];
if (!isset($_SESSION['phrase']) || !PhraseBuilder::comparePhrases($_SESSION['phrase'], $_POST['captcha'])) {
becomeMsgPage('验证码错误!');
}
if (!$user['email']) {
becomeMsgPage('用户未填写邮件地址,请联系管理员重置!');
}
$oj_name = UOJConfig::$data['profile']['oj-name']; $oj_name = UOJConfig::$data['profile']['oj-name'];
$oj_name_short = UOJConfig::$data['profile']['oj-name-short']; $oj_name_short = UOJConfig::$data['profile']['oj-name-short'];
$sufs = base64url_encode($user['username'] . "." . md5($user['username'] . "+" . $password)); $check_code = md5($user['username'] . "+" . $password . '+' . UOJTime::$time_now_str);
$url = HTML::url("/reset-password", array('params' => array('p' => $sufs))); $sufs = base64url_encode($user['username'] . "." . $check_code);
$url = HTML::url("/reset-password", ['params' => ['p' => $sufs]]);
$oj_url = HTML::url('/');
$name = $user['username'];
if ($user['realname']) {
$name .= ' (' . $user['realname'] . ')';
}
$html = <<<EOD $html = <<<EOD
<base target="_blank" /> <base target="_blank" />
<p>{$user['username']}您好,</p> <p>{$name} 您好,</p>
<p>您刚刚启用了{$oj_name_short}密码找回功能,请进入下面的链接重设您的密码:</p>
<p><a href="$url">$url</a></p>
<p>{$oj_name}</p>
<style type="text/css"> <p>您最近告知我们需要重置您在 {$oj_name_short} 上账号的密码。请访问以下链接:<a href="{$url}">{$url}</a> (如果无法点击链接,请试着复制链接并粘贴至浏览器中打开。)</p>
body{font-size:14px;font-family:arial,verdana,sans-serif;line-height:1.666;padding:0;margin:0;overflow:auto;white-space:normal;word-wrap:break-word;min-height:100px} <p>如果您没有请求重置密码,则忽略此信息。该链接将在 72 小时后自动过期失效。</p>
pre {white-space:pre-wrap;white-space:-moz-pre-wrap;white-space:-pre-wrap;white-space:-o-pre-wrap;word-wrap:break-word}
</style> <p>{$oj_name}</p>
<p><a href="{$oj_url}">{$oj_url}</a></p>
EOD; EOD;
$mailer = UOJMail::noreply(); $mailer = UOJMail::noreply();
$mailer->addAddress($user['email'], $user['username']); $mailer->addAddress($user['email'], $user['username']);
$mailer->Subject = $oj_name_short."密码找回"; $mailer->Subject = $oj_name_short . " 密码找回";
$mailer->msgHTML($html); $mailer->msgHTML($html);
if (!$mailer->send()) { if (!$mailer->send()) {
error_log($mailer->ErrorInfo); error_log($mailer->ErrorInfo);
becomeMsgPage('<div class="text-center"><h2>邮件发送失败,请重试 <span class="glyphicon glyphicon-remove"></span></h2></div>'); becomeMsgPage('<div class="text-center"><h2>邮件发送失败,请重试</h2></div>');
} else { } else {
becomeMsgPage('<div class="text-center"><h2>邮件发送成功 <span class="glyphicon glyphicon-ok"></span></h2></div>'); DB::update([
} "update user_info",
}; "set", [
$forgot_form->submit_button_config['align'] = 'offset'; 'extra' => DB::json_set('extra', '$.reset_password_check_code', $check_code, '$.reset_password_time', UOJTime::$time_now_str),
],
"where", [
"username" => $user['username'],
],
]);
$forgot_form->runAtServer(); becomeMsgPage('<div class="text-center"><h2>邮件发送成功,请检查收件箱!</h2><span>如果邮件未出现在收件箱中,请检查垃圾箱。</span></div>');
?> }
};
$forgot_form->submit_button_config['align'] = 'offset';
$forgot_form->runAtServer();
?>
<?php echoUOJPageHeader('找回密码') ?> <?php echoUOJPageHeader('找回密码') ?>
<h2 class="page-header">找回密码</h2> <h2 class="page-header">找回密码</h2>
<h4>请输入需要找回密码的用户名:</h4> <h4>请输入需要找回密码的用户名:</h4>
<?php $forgot_form->printHTML(); ?> <?php $forgot_form->printHTML(); ?>
<script>
function refreshCaptcha() {
var timestamp = new Date().getTime();
$("#captcha").attr("src", "/captcha" + '?' + timestamp);
}
$(document).ready(function() {
refreshCaptcha();
$("#captcha").click(function(e) {
refreshCaptcha();
});
});
</script>
<?php echoUOJPageFooter() ?> <?php echoUOJPageFooter() ?>

View File

@ -1,39 +1,55 @@
<?php <?php
if (!isset($_GET['p'])) { if (!isset($_GET['p'])) {
become404Page(); become404Page();
} }
function resetPassword() {
list($username, $check_code) = explode('.', base64url_decode($_GET['p'])); list($username, $check_code) = explode('.', base64url_decode($_GET['p']));
$user = UOJUser::query($username);
if (!$user) become404Page();
if (!isset($check_code) || strlen($check_code) != 32) become404Page();
$extra = UOJUser::getExtra($user);
if ($check_code !== $extra['reset_password_check_code']) {
become404Page();
}
if (UOJTime::str2time($extra['reset_password_time'])->add(new DateInterval('P3D')) < UOJTime::$time_now) {
becomeMsgPage('链接已过期');
}
function resetPassword() {
global $user;
if (!isset($_POST['newPW']) || !validatePassword($_POST['newPW'])) { if (!isset($_POST['newPW']) || !validatePassword($_POST['newPW'])) {
return '操作失败,无效密码'; return '操作失败,无效密码';
} }
if (!isset($username) || !validateUsername($username)) {
return '不明错误';
}
if (!isset($check_code)) {
return '不明错误';
}
$newPW = $_POST['newPW']; $newPW = $_POST['newPW'];
$user = UOJUser::query($username);
if ($user == null) {
return '不明错误';
}
if ($check_code !== md5($user['username'] . '+' . $user['password'])) {
return '不明错误';
}
$newPW = getPasswordToStore($newPW, $user['username']); $newPW = getPasswordToStore($newPW, $user['username']);
DB::update("update user_info set password = '$newPW' where username = '{$user['username']}'");
DB::update([
"update user_info",
"set", [
"password" => $newPW,
"extra" => DB::json_remove('extra', '$.reset_password_check_code', '$.reset_password_time'),
],
"where", [
"username" => $user['username'],
],
]);
return 'ok'; return 'ok';
} }
if (isset($_POST['reset'])) { if (isset($_POST['reset'])) {
die(resetPassword()); die(resetPassword());
} }
?> ?>
<?php <?php
$REQUIRE_LIB['dialog'] = ''; $REQUIRE_LIB['dialog'] = '';
$REQUIRE_LIB['md5'] = ''; $REQUIRE_LIB['md5'] = '';
?> ?>
<?php echoUOJPageHeader('更改密码') ?> <?php echoUOJPageHeader('更改密码') ?>
<h2 class="page-header">更改密码</h2> <h2 class="page-header">更改密码</h2>
<form id="form-reset" class="form-horizontal"> <form id="form-reset" class="form-horizontal">
@ -53,40 +69,40 @@
</form> </form>
<script type="text/javascript"> <script type="text/javascript">
function validateResetPwPost() { function validateResetPwPost() {
var ok = true; var ok = true;
ok &= getFormErrorAndShowHelp('password', validateSettingPassword); ok &= getFormErrorAndShowHelp('password', validateSettingPassword);
return ok; return ok;
} }
$(document).ready(function() { $(document).ready(function() {
$('#form-reset').submit(function(e) { $('#form-reset').submit(function(e) {
if (!validateResetPwPost()) { if (!validateResetPwPost()) {
return false; return false;
} }
$.post(<?= json_encode($_SERVER['REQUEST_URI']) ?>, { $.post(<?= json_encode($_SERVER['REQUEST_URI']) ?>, {
reset : '', reset: '',
newPW : md5($('#input-password').val(), "<?= getPasswordClientSalt() ?>") newPW: md5($('#input-password').val(), "<?= getPasswordClientSalt() ?>")
}, function(res) { }, function(res) {
if (res == 'ok') { if (res == 'ok') {
BootstrapDialog.show({ BootstrapDialog.show({
title : '提示', title: '提示',
message : '密码更改成功', message: '密码更改成功',
type : BootstrapDialog.TYPE_SUCCESS, type: BootstrapDialog.TYPE_SUCCESS,
buttons: [{ buttons: [{
label: '好的', label: '好的',
action: function(dialog) { action: function(dialog) {
dialog.close(); dialog.close();
} }
}], }],
onhidden : function(dialog) { onhidden: function(dialog) {
window.location.href = '/login'; window.location.href = '/login';
} }
}); });
} else { } else {
BootstrapDialog.show({ BootstrapDialog.show({
title : '提示', title: '提示',
message : res, message: res,
type : BootstrapDialog.TYPE_DANGER, type: BootstrapDialog.TYPE_DANGER,
buttons: [{ buttons: [{
label: '好的', label: '好的',
action: function(dialog) { action: function(dialog) {
@ -98,6 +114,6 @@ $(document).ready(function() {
}); });
return false; return false;
}); });
}); });
</script> </script>
<?php echoUOJPageFooter() ?> <?php echoUOJPageFooter() ?>