Compare commits

...

5 Commits

Author SHA1 Message Date
c35dd3f3fb
feat: add incomplete user profile warning
All checks were successful
continuous-integration/drone/push Build is passing
2023-02-14 11:56:13 +08:00
a483cc598b
feat(super_manage): submission_frequency config 2023-02-14 11:36:10 +08:00
0f3099bbe5
chore: update mail template 2023-02-14 11:18:47 +08:00
62e25fe1ea
feat: tinyfilemanager use uoj csrf 2023-02-14 10:59:44 +08:00
47167a5c7a
fix(problem/manage/data): csrf token 2023-02-14 10:52:19 +08:00
9 changed files with 149 additions and 141 deletions

View File

@ -51,7 +51,7 @@ function handleLoginPost() {
<ul>
<li>请求 IP: {$remote_addr}</li>
<li>转发源 IP:{$http_x_forwarded_for} </li>
<li>转发源 IP: {$http_x_forwarded_for} </li>
<li>用户代理: {$user_agent}</li>
</ul>

View File

@ -63,6 +63,8 @@ function echoFilePre($file_name) {
// 上传数据
if ($_POST['problem_data_file_submit'] == 'submit') {
crsf_defend();
if ($_FILES["problem_data_file"]["error"] > 0) {
$errmsg = "Error: " . $_FILES["problem_data_file"]["error"];
UOJResponse::message('<div>' . HTML::escape($errmsg) . '</div><a href="">返回</a>');
@ -625,6 +627,7 @@ if ($problem['hackable']) {
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<form action="" method="post" enctype="multipart/form-data" role="form">
<?= HTML::hiddenToken() ?>
<div class="modal-body">
<label class="form-label" for="problem_data_file">上传 zip 文件</label>
<input class="form-control" type="file" name="problem_data_file" id="problem_data_file" accept=".zip">

View File

@ -38,6 +38,10 @@ $tabs_info = [
'name' => '图床管理',
'url' => "/super_manage/image_hosting",
],
'meta' => [
'name' => 'OJ 基础设置',
'url' => "/super_manage/meta",
],
];
if (!isset($tabs_info[$cur_tab])) {
@ -1068,6 +1072,41 @@ if ($cur_tab == 'index') {
]);
};
$change_user_image_total_size_limit_form->runAtServer();
} elseif ($cur_tab == 'meta') {
$submission_frequency = UOJContext::getMeta('submission_frequency');
$submission_frequency_form = new UOJForm('submission_frequency');
$submission_frequency_form->addSelect('submission_frequency_interval', [
'label' => '时间间隔',
'options' => [
'PT1S' => '1 秒',
'PT10S' => '10 秒',
'PT1M' => '1 分钟',
'PT10M' => '10 分钟',
'PT30M' => '30 分钟',
'PT1H' => '1 小时',
],
'default_value' => $submission_frequency['interval'],
]);
$submission_frequency_form->addInput('submission_frequency_limit', [
'label' => '最大提交次数',
'help' => '在时间间隔内最多允许提交的次数。',
'default_value' => $submission_frequency['limit'],
'validator_php' => function ($x, &$vdata) {
if (!validateUInt($x)) {
return '不合法';
}
$vdata['limit'] = (int)$x;
return '';
},
]);
$submission_frequency_form->handle = function (&$vdata) {
UOJContext::setMeta('submission_frequency', [
'interval' => UOJRequest::post('submission_frequency_interval'),
'limit' => $vdata['limit'],
]);
};
$submission_frequency_form->succ_href = UOJContext::requestPath() . '#submission-frequency';
$submission_frequency_form->runAtServer();
}
?>
@ -1463,21 +1502,6 @@ if ($cur_tab == 'index') {
</div>
</div>
</div>
<script>
$(document).ready(function() {
// Javascript to enable link to tab
var hash = location.hash.replace(/^#/, '');
if (hash) {
bootstrap.Tab.jQueryInterface.call($('.nav-tabs a[href="#' + hash + '"]'), 'show').blur();
}
// Change hash for page-reload
$('.nav-tabs a').on('shown.bs.tab', function(e) {
window.location.hash = e.target.hash;
});
});
</script>
<?php elseif ($cur_tab === 'submissions') : ?>
<?php if (!isset($_GET['judging'])) : ?>
<div>
@ -1660,9 +1684,48 @@ EOD;
<?php $change_user_image_total_size_limit_form->printHTML() ?>
</div>
</div>
<?php elseif ($cur_tab == 'meta') : ?>
<div class="card mt-3 mt-md-0">
<div class="card-header">
<ul class="nav nav-tabs card-header-tabs">
<li class="nav-item">
<a class="nav-link active" href="#submission-frequency" data-bs-toggle="tab" data-bs-target="#submission-frequency">提交频次限制</a>
</li>
</ul>
</div>
<div class="card-body">
<div class="tab-content">
<div class="tab-pane active" id="submission-frequency">
<div class="row">
<div class="col-md-6">
<?php $submission_frequency_form->printHTML() ?>
</div>
<div class="col-md-6">
此处可以设置用户的提交频次限制。请注意,过于严格的限制会导致用户无法正常提交题目。默认限制为 1 秒内最多提交 1 次。
</div>
</div>
</div>
</div>
</div>
</div>
<?php endif ?>
</div>
<!-- end right col -->
</div>
<script>
$(document).ready(function() {
// Javascript to enable link to tab
var hash = location.hash.replace(/^#/, '');
if (hash) {
bootstrap.Tab.jQueryInterface.call($('.nav-tabs a[href="#' + hash + '"]'), 'show').blur();
}
// Change hash for page-reload
$('.nav-tabs a').on('shown.bs.tab', function(e) {
window.location.hash = e.target.hash;
});
});
</script>
<?php echoUOJPageFooter() ?>

View File

@ -98,11 +98,6 @@ if (defined('FM_EMBED')) {
restore_error_handler();
}
//Genrating CSRF Token
if (empty($_SESSION['token'])) {
$_SESSION['token'] = bin2hex(random_bytes(32));
}
if (empty($auth_users)) {
$use_auth = false;
}
@ -124,7 +119,6 @@ defined('FM_SELF_URL') || define('FM_SELF_URL', HTML::url('?'));
// logout
if (isset($_GET['logout'])) {
unset($_SESSION[FM_SESSION_ID]['logged']);
unset( $_SESSION['token']);
fm_redirect(FM_SELF_URL);
}
@ -175,11 +169,11 @@ if ($ip_ruleset != 'OFF') {
if ($use_auth) {
if (isset($_SESSION[FM_SESSION_ID]['logged'], $auth_users[$_SESSION[FM_SESSION_ID]['logged']])) {
// Logged
} elseif (isset($_POST['fm_usr'], $_POST['fm_pwd'], $_POST['token'])) {
} elseif (isset($_POST['fm_usr'], $_POST['fm_pwd'], $_POST['_token'])) {
// Logging In
sleep(1);
if(function_exists('password_verify')) {
if (isset($auth_users[$_POST['fm_usr']]) && isset($_POST['fm_pwd']) && password_verify($_POST['fm_pwd'], $auth_users[$_POST['fm_usr']]) && verifyToken($_POST['token'])) {
if (isset($auth_users[$_POST['fm_usr']]) && isset($_POST['fm_pwd']) && password_verify($_POST['fm_pwd'], $auth_users[$_POST['fm_usr']]) && crsf_check()) {
$_SESSION[FM_SESSION_ID]['logged'] = $_POST['fm_usr'];
fm_set_msg(lng('You are logged in'));
fm_redirect(FM_ROOT_URL);
@ -230,7 +224,7 @@ if ($use_auth) {
<div class="mb-3">
<?php fm_show_message(); ?>
</div>
<input type="hidden" name="token" value="<?php echo htmlentities($_SESSION['token']); ?>" />
<?= HTML::hiddenToken() ?>
<div class="mb-3">
<button type="submit" class="btn btn-success btn-block w-100 mt-4" role="button">
<?php echo lng('Login'); ?>
@ -306,11 +300,8 @@ unset($p, $use_auth, $iconv_input_encoding, $use_highlightjs, $highlightjs_style
/*************************** ACTIONS ***************************/
// Handle all AJAX Request
if ((isset($_SESSION[FM_SESSION_ID]['logged'], $auth_users[$_SESSION[FM_SESSION_ID]['logged']]) || !FM_USE_AUTH) && isset($_POST['ajax'], $_POST['token']) && !FM_READONLY) {
if(!verifyToken($_POST['token'])) {
header('HTTP/1.0 401 Unauthorized');
die("Invalid Token.");
}
if ((isset($_SESSION[FM_SESSION_ID]['logged'], $auth_users[$_SESSION[FM_SESSION_ID]['logged']]) || !FM_USE_AUTH) && isset($_POST['ajax'], $_POST['_token']) && !FM_READONLY) {
crsf_defend();
//search : get list of files from the current folder
if(isset($_POST['type']) && $_POST['type']=="search") {
@ -515,9 +506,9 @@ if ((isset($_SESSION[FM_SESSION_ID]['logged'], $auth_users[$_SESSION[FM_SESSION_
}
// Delete file / folder
if (isset($_GET['del'], $_POST['token']) && !FM_READONLY) {
if (isset($_GET['del'], $_POST['_token']) && !FM_READONLY) {
$del = str_replace( '/', '', fm_clean_path( $_GET['del'] ) );
if ($del != '' && $del != '..' && $del != '.' && verifyToken($_POST['token'])) {
if ($del != '' && $del != '..' && $del != '.' && crsf_check()) {
$path = FM_ROOT_PATH;
if (FM_PATH != '') {
$path .= '/' . FM_PATH;
@ -537,10 +528,10 @@ if (isset($_GET['del'], $_POST['token']) && !FM_READONLY) {
}
// Create a new file/folder
if (isset($_POST['newfilename'], $_POST['newfile'], $_POST['token']) && !FM_READONLY) {
if (isset($_POST['newfilename'], $_POST['newfile'], $_POST['_token']) && !FM_READONLY) {
$type = urldecode($_POST['newfile']);
$new = str_replace( '/', '', fm_clean_path( strip_tags( $_POST['newfilename'] ) ) );
if (fm_isvalid_filename($new) && $new != '' && $new != '..' && $new != '.' && verifyToken($_POST['token'])) {
if (fm_isvalid_filename($new) && $new != '' && $new != '..' && $new != '.' && crsf_check()) {
$path = FM_ROOT_PATH;
if (FM_PATH != '') {
$path .= '/' . FM_PATH;
@ -643,11 +634,8 @@ if (isset($_GET['copy'], $_GET['finish']) && !FM_READONLY) {
}
// Mass copy files/ folders
if (isset($_POST['file'], $_POST['copy_to'], $_POST['finish'], $_POST['token']) && !FM_READONLY) {
if(!verifyToken($_POST['token'])) {
fm_set_msg(lng('Invalid Token.'), 'error');
}
if (isset($_POST['file'], $_POST['copy_to'], $_POST['finish'], $_POST['_token']) && !FM_READONLY) {
crsf_defend();
// from
$path = FM_ROOT_PATH;
@ -710,10 +698,9 @@ if (isset($_POST['file'], $_POST['copy_to'], $_POST['finish'], $_POST['token'])
}
// Rename
if (isset($_POST['rename_from'], $_POST['rename_to'], $_POST['token']) && !FM_READONLY) {
if(!verifyToken($_POST['token'])) {
fm_set_msg("Invalid Token.", 'error');
}
if (isset($_POST['rename_from'], $_POST['rename_to'], $_POST['_token']) && !FM_READONLY) {
crsf_defend();
// old name
$old = urldecode($_POST['rename_from']);
$old = fm_clean_path($old);
@ -741,10 +728,8 @@ if (isset($_POST['rename_from'], $_POST['rename_to'], $_POST['token']) && !FM_RE
}
// Download
if (isset($_GET['dl'], $_POST['token'])) {
if(!verifyToken($_POST['token'])) {
fm_set_msg("Invalid Token.", 'error');
}
if (isset($_GET['dl'], $_POST['_token'])) {
crsf_defend();
$dl = urldecode($_GET['dl']);
$dl = fm_clean_path($dl);
@ -764,8 +749,8 @@ if (isset($_GET['dl'], $_POST['token'])) {
// Upload
if (!empty($_FILES) && !FM_READONLY) {
if(isset($_POST['token'])) {
if(!verifyToken($_POST['token'])) {
if(isset($_POST['_token'])) {
if(!crsf_check()) {
$response = array ('status' => 'error','info' => "Invalid Token.");
echo json_encode($response); exit();
}
@ -892,11 +877,8 @@ if (!empty($_FILES) && !FM_READONLY) {
}
// Mass deleting
if (isset($_POST['group'], $_POST['delete'], $_POST['token']) && !FM_READONLY) {
if(!verifyToken($_POST['token'])) {
fm_set_msg(lng("Invalid Token."), 'error');
}
if (isset($_POST['group'], $_POST['delete'], $_POST['_token']) && !FM_READONLY) {
crsf_defend();
$path = FM_ROOT_PATH;
if (FM_PATH != '') {
@ -927,11 +909,8 @@ if (isset($_POST['group'], $_POST['delete'], $_POST['token']) && !FM_READONLY) {
}
// Pack files zip, tar
if (isset($_POST['group'], $_POST['token']) && (isset($_POST['zip']) || isset($_POST['tar'])) && !FM_READONLY) {
if(!verifyToken($_POST['token'])) {
fm_set_msg(lng("Invalid Token."), 'error');
}
if (isset($_POST['group'], $_POST['_token']) && (isset($_POST['zip']) || isset($_POST['tar'])) && !FM_READONLY) {
crsf_defend();
$path = FM_ROOT_PATH;
$ext = 'zip';
@ -989,11 +968,9 @@ if (isset($_POST['group'], $_POST['token']) && (isset($_POST['zip']) || isset($_
}
// Unpack zip, tar
if (isset($_POST['unzip'], $_POST['token']) && !FM_READONLY) {
if (isset($_POST['unzip'], $_POST['_token']) && !FM_READONLY) {
if(!verifyToken($_POST['token'])) {
fm_set_msg(lng("Invalid Token."), 'error');
}
crsf_defend();
$unzip = urldecode($_POST['unzip']);
$unzip = fm_clean_path($unzip);
@ -1057,11 +1034,9 @@ if (isset($_POST['unzip'], $_POST['token']) && !FM_READONLY) {
}
// Change Perms (not for Windows)
if (isset($_POST['chmod'], $_POST['token']) && !FM_READONLY && !FM_IS_WIN) {
if (isset($_POST['chmod'], $_POST['_token']) && !FM_READONLY && !FM_IS_WIN) {
if(!verifyToken($_POST['token'])) {
fm_set_msg(lng("Invalid Token."), 'error');
}
crsf_defend();
$path = FM_ROOT_PATH;
if (FM_PATH != '') {
@ -1195,7 +1170,7 @@ if (isset($_GET['upload']) && !FM_READONLY) {
<form action="<?php echo htmlspecialchars(FM_SELF_URL) . '?p=' . fm_enc(FM_PATH) ?>" class="dropzone card-tabs-container" id="fileUploader" enctype="multipart/form-data">
<input type="hidden" name="p" value="<?php echo fm_enc(FM_PATH) ?>">
<input type="hidden" name="fullpath" id="fullpath" value="<?php echo fm_enc(FM_PATH) ?>">
<input type="hidden" name="token" value="<?php echo $_SESSION['token']; ?>">
<?= HTML::hiddenToken() ?>
<div class="fallback">
<input name="file" type="file" multiple/>
</div>
@ -1205,7 +1180,7 @@ if (isset($_GET['upload']) && !FM_READONLY) {
<form id="js-form-url-upload" class="row row-cols-lg-auto g-3 align-items-center" onsubmit="return upload_from_url(this);" method="POST" action="">
<input type="hidden" name="type" value="upload" aria-label="hidden" aria-hidden="true">
<input type="url" placeholder="URL" name="uploadurl" required class="form-control" style="width: 80%">
<input type="hidden" name="token" value="<?php echo $_SESSION['token']; ?>">
<?= HTML::hiddenToken() ?>
<button type="submit" class="btn btn-primary ms-3"><?php echo lng('Upload') ?></button>
<div class="lds-facebook"><div></div><div></div><div></div></div>
</form>
@ -1284,7 +1259,7 @@ if (isset($_POST['copy']) && !FM_READONLY) {
<p class="custom-checkbox custom-control"><input type="checkbox" name="move" value="1" id="js-move-files" class="custom-control-input"><label for="js-move-files" class="custom-control-label ms-2"> <?php echo lng('Move') ?></label></p>
<p>
<b><a href="?p=<?php echo urlencode(FM_PATH) ?>" class="btn btn-outline-danger"><i class="fa fa-times-circle"></i> <?php echo lng('Cancel') ?></a></b>&nbsp;
<input type="hidden" name="token" value="<?php echo $_SESSION['token']; ?>">
<?= HTML::hiddenToken() ?>
<button type="submit" class="btn btn-success"><i class="fa fa-check-circle"></i> <?php echo lng('Copy') ?></button>
</p>
</form>
@ -1581,7 +1556,7 @@ if (isset($_GET['view'])) {
</p>
<div class="d-flex align-items-center mb-3">
<form method="post" class="d-inline ms-2" action="?p=<?php echo urlencode(FM_PATH) ?>&amp;dl=<?php echo urlencode($file) ?>">
<input type="hidden" name="token" value="<?php echo $_SESSION['token']; ?>">
<?= HTML::hiddenToken() ?>
<button type="submit" class="btn btn-link text-decoration-none fw-bold p-0"><i class="fa fa-cloud-download"></i> <?php echo lng('Download') ?></button> &nbsp;
</form>
<b class="ms-2"><a href="<?php echo fm_enc($file_url) ?>" target="_blank"><i class="fa fa-external-link-square"></i> <?php echo lng('Open') ?></a></b>
@ -1591,12 +1566,12 @@ if (isset($_GET['view'])) {
$zip_name = pathinfo($file_path, PATHINFO_FILENAME);
?>
<form method="post" class="d-inline ms-2">
<input type="hidden" name="token" value="<?php echo $_SESSION['token']; ?>">
<?= HTML::hiddenToken() ?>
<input type="hidden" name="unzip" value="<?php echo urlencode($file); ?>">
<button type="submit" class="btn btn-link text-decoration-none fw-bold p-0" style="font-size: 14px;"><i class="fa fa-check-circle"></i> <?php echo lng('UnZip') ?></button>
</form>&nbsp;
<form method="post" class="d-inline ms-2">
<input type="hidden" name="token" value="<?php echo $_SESSION['token']; ?>">
<?= HTML::hiddenToken() ?>
<input type="hidden" name="unzip" value="<?php echo urlencode($file); ?>">
<input type="hidden" name="tofolder" value="1">
<button type="submit" class="btn btn-link text-decoration-none fw-bold p-0" style="font-size: 14px;" data-bs-toggle="tooltip" data-bs-title="UnZip to <?php echo fm_enc($zip_name) ?>"><i class="fa fa-check-circle"></i> <?php echo lng('UnZipToFolder') ?></button>
@ -1832,7 +1807,7 @@ if (isset($_GET['chmod']) && !FM_READONLY && !FM_IS_WIN) {
</table>
<p>
<input type="hidden" name="token" value="<?php echo $_SESSION['token']; ?>">
<?= HTML::hiddenToken() ?>
<b><a href="?p=<?php echo urlencode(FM_PATH) ?>" class="btn btn-outline-primary"><i class="fa fa-times-circle"></i> <?php echo lng('Cancel') ?></a></b>&nbsp;
<button type="submit" class="btn btn-success"><i class="fa fa-check-circle"></i> <?php echo lng('Change') ?></button>
</p>
@ -1860,7 +1835,7 @@ $tableTheme = (FM_THEME == "dark") ? "text-white bg-dark table-dark" : "bg-white
<form action="" method="post" class="pt-3">
<input type="hidden" name="p" value="<?php echo fm_enc(FM_PATH) ?>">
<input type="hidden" name="group" value="1">
<input type="hidden" name="token" value="<?php echo $_SESSION['token']; ?>">
<?= HTML::hiddenToken() ?>
<div class="table-responsive">
<table class="table table-bordered table-hover table-sm <?php echo $tableTheme; ?>" id="main-table">
<thead class="thead-white">
@ -2069,19 +2044,6 @@ fm_show_footer();
// Functions
/**
* Verify CSRF TOKEN and remove after cerify
* @param string $token
* @return bool
*/
function verifyToken($token)
{
if (hash_equals($_SESSION['token'], $token)) {
return true;
}
return false;
}
/**
* Delete file or folder (recursively)
* @param string $path
@ -3507,7 +3469,7 @@ $isStickyNavBar = $sticky_navbar ? 'navbar-fixed' : 'navbar-normal';
<?= HTML::css_link('/css/highlightjs.github.min.css?v=11.6.0-20221005') ?>
<?= HTML::js_src('/js/highlightjs.min.js?v=11.6.0-20221005') ?>
<?php endif; ?>
<script type="text/javascript">window.csrf = '<?php echo $_SESSION['token']; ?>';</script>
<script type="text/javascript">window.csrf = '<?= crsf_token() ?>';</script>
<style>
html { -moz-osx-font-smoothing: grayscale; -webkit-font-smoothing: antialiased; text-rendering: optimizeLegibility; height: 100%; scroll-behavior: smooth;}
*,*::before,*::after { box-sizing: border-box;}
@ -3682,7 +3644,7 @@ $isStickyNavBar = $sticky_navbar ? 'navbar-fixed' : 'navbar-normal';
<input type="text" name="newfilename" id="newfilename" value="" class="form-control" placeholder="<?php echo lng('Enter here...') ?>" required>
</div>
<div class="modal-footer">
<input type="hidden" name="token" value="<?php echo $_SESSION['token']; ?>">
<?= HTML::hiddenToken() ?>
<button type="button" class="btn btn-outline-primary" data-bs-dismiss="modal"><i class="fa fa-times-circle"></i> <?php echo lng('Cancel') ?></button>
<button type="submit" class="btn btn-success"><i class="fa fa-check-circle"></i> <?php echo lng('CreateNow') ?></button>
</div>
@ -3723,7 +3685,7 @@ $isStickyNavBar = $sticky_navbar ? 'navbar-fixed' : 'navbar-normal';
<h5 class="mb-3"><?php echo lng('Are you sure want to rename?') ?></h5>
<p class="mb-1">
<input type="text" name="rename_to" id="js-rename-to" class="form-control" placeholder="<?php echo lng('Enter new file name') ?>" required>
<input type="hidden" name="token" value="<?php echo $_SESSION['token']; ?>">
<?= HTML::hiddenToken() ?>
<input type="hidden" name="rename_from" id="js-rename-from">
</p>
</div>
@ -3746,7 +3708,7 @@ $isStickyNavBar = $sticky_navbar ? 'navbar-fixed' : 'navbar-normal';
</div>
<div class="modal-footer flex-nowrap p-0">
<button type="button" class="btn btn-lg btn-link fs-6 text-decoration-none col-6 m-0 rounded-0 border-end" data-bs-dismiss="modal"><?php echo lng('Cancel') ?></button>
<input type="hidden" name="token" value="<?php echo $_SESSION['token']; ?>">
<?= HTML::hiddenToken() ?>
<button type="submit" class="btn btn-lg btn-link fs-6 text-decoration-none col-6 m-0 rounded-0" data-bs-dismiss="modal"><strong><?php echo lng('Okay') ?></strong></button>
</div>
</form>
@ -3811,7 +3773,7 @@ $isStickyNavBar = $sticky_navbar ? 'navbar-fixed' : 'navbar-normal';
a.setAttribute("method", "POST"), a.setAttribute("action", "");
var o = document.createElement("textarea");
o.setAttribute("type", "textarea"), o.setAttribute("name", "savedata");
let cx = document.createElement("input"); cx.setAttribute("type", "hidden");cx.setAttribute("name", "token");cx.setAttribute("value", window.csrf);
let cx = document.createElement("input"); cx.setAttribute("type", "hidden");cx.setAttribute("name", "_token");cx.setAttribute("value", window.csrf);
var c = document.createTextNode(n);
o.appendChild(c), a.appendChild(o), a.appendChild(cx), document.body.appendChild(a), a.submit()
}

View File

@ -36,8 +36,10 @@ function crsf_defend() {
}
function submission_frequency_check() {
$submission_frequency = UOJContext::getMeta('submission_frequency');
$recent = clone UOJTime::$time_now;
$recent->sub(new DateInterval("PT1S"));
$recent->sub(new DateInterval($submission_frequency['interval']));
$num = DB::selectCount([
"select count(*) from submissions",
"where", [
@ -45,54 +47,10 @@ function submission_frequency_check() {
["submit_time", ">=", $recent->format('Y-m-d H:i:s')]
]
]);
if ($num >= 1) {
if ($num >= max(1, $submission_frequency['limit'])) {
return false;
}
// use the implementation below if OJ is under attack
/*
// 1
$recent = clone UOJTime::$time_now;
$recent->sub(new DateInterval("PT3S"));
$num = DB::selectCount([
"select count(*) from submissions",
"where", [
"submitter" => Auth::id(),
["submit_time", ">=", $recent->format('Y-m-d H:i:s')]
]
]);
if ($num >= 1) {
return false;
}
// 2
$recent = clone UOJTime::$time_now;
$recent->sub(new DateInterval("PT1M"));
$num = DB::selectCount([
"select count(*) from submissions",
"where", [
"submitter" => Auth::id(),
["submit_time", ">=", $recent->format('Y-m-d H:i:s')]
]
]);
if ($num >= 6) {
return false;
}
// 3
$recent = clone UOJTime::$time_now;
$recent->sub(new DateInterval("PT30M"));
$num = DB::selectCount([
"select count(*) from submissions",
"where", [
"submitter" => Auth::id(),
["submit_time", ">=", $recent->format('Y-m-d H:i:s')]
]
]);
if ($num >= 30) {
return false;
}
*/
return true;
}

View File

@ -30,6 +30,10 @@ class Auth {
return false;
}
if (!isset($myUser[$name])) {
return false;
}
return $myUser[$name];
}

View File

@ -36,6 +36,10 @@ class UOJContext {
'upload_image' => true,
],
],
'submission_frequency' => [
'interval' => 'PT1S',
'limit' => 1,
],
];
public static $data = [
@ -156,6 +160,7 @@ class UOJContext {
"select value from meta",
"where", ['name' => $name]
]);
if ($value === null) {
return self::$meta_default[$name];
} else {
@ -165,6 +170,7 @@ class UOJContext {
public static function setMeta($name, $value) {
$value = json_encode($value);
return DB::update([
"insert into meta", DB::bracketed_fields(['name', 'value', 'updated_at']),
"values", DB::tuple([$name, $value, DB::now()]),

File diff suppressed because one or more lines are too long

View File

@ -4,6 +4,18 @@ $parsedown = HTML::parsedown(['username_with_color' => true]);
?>
<?php if (Auth::check()) : ?>
<?php if (!Auth::property('email')) : ?>
<div class="alert alert-warning d-flex align-items-center mb-2" role="alert">
<div class="flex-shrink-0 me-3">
<i class="fs-4 bi bi-exclamation-triangle-fill"></i>
</div>
<div>
<div class="fw-bold mb-2">请完善个人资料</div>
<div class="small">您还没有填写您的电子邮件地址,请前往 <a href="/user/<?= Auth::id() ?>/edit">个人资料编辑</a> 页面补全信息,以便接收最新的安全和功能通知。</div>
</div>
</div>
<?php endif ?>
<?php if (!isset($groups_hidden)) : ?>
<?php $groups = UOJGroup::queryGroupsOfUser(Auth::user()); ?>
<?php if (!empty($groups)) : ?>