diff --git a/remote_judger/src/daemon.ts b/remote_judger/src/daemon.ts index bfa52c5..af7dbe8 100644 --- a/remote_judger/src/daemon.ts +++ b/remote_judger/src/daemon.ts @@ -67,8 +67,8 @@ export default async function daemon(config: UOJConfig) { if (config.test_sample_only === 'on') { await request('/submit', { - submit: true, - fetch_new: false, + submit: 1, + fetch_new: 0, id, result: JSON.stringify({ status: 'Judged', @@ -80,6 +80,8 @@ export default async function daemon(config: UOJConfig) { judge_time, }); + await sleep(TIME.second); + continue; } @@ -115,8 +117,8 @@ export default async function daemon(config: UOJConfig) { code = fs.readFileSync(sourceCodePath, 'utf-8'); } catch (e) { await request('/submit', { - submit: true, - fetch_new: false, + submit: 1, + fetch_new: 0, id, result: JSON.stringify({ status: 'Judged', @@ -135,6 +137,8 @@ export default async function daemon(config: UOJConfig) { fs.removeSync(tmpdir); + await sleep(TIME.second); + continue; } @@ -152,8 +156,8 @@ export default async function daemon(config: UOJConfig) { ); } catch (err) { await request('/submit', { - submit: true, - fetch_new: false, + submit: 1, + fetch_new: 0, id, result: JSON.stringify({ status: 'Judged', @@ -172,6 +176,8 @@ export default async function daemon(config: UOJConfig) { } fs.removeSync(tmpdir); + + await sleep(TIME.second); } } catch (err) { logger.error(err.message); diff --git a/remote_judger/src/vjudge.ts b/remote_judger/src/vjudge.ts index 50d611f..f34440a 100644 --- a/remote_judger/src/vjudge.ts +++ b/remote_judger/src/vjudge.ts @@ -98,8 +98,8 @@ class VJudge { ) { const next = async payload => { return await this.request('/submit', { - 'update-status': true, - fetch_new: false, + 'update-status': 1, + fetch_new: 0, id, status: payload.status || @@ -110,8 +110,8 @@ class VJudge { const end = async payload => { if (payload.error) { return await this.request('/submit', { - submit: true, - fetch_new: false, + submit: 1, + fetch_new: 0, id, result: JSON.stringify({ status: 'Judged', @@ -128,8 +128,8 @@ class VJudge { } return await this.request('/submit', { - submit: true, - fetch_new: false, + submit: 1, + fetch_new: 0, id, result: JSON.stringify({ status: 'Judged', diff --git a/web/app/controllers/subdomain/api/remote_judge/custom_account_validator.php b/web/app/controllers/subdomain/api/remote_judge/custom_account_validator.php new file mode 100644 index 0000000..f655b20 --- /dev/null +++ b/web/app/controllers/subdomain/api/remote_judge/custom_account_validator.php @@ -0,0 +1,86 @@ +setUserAgent(UOJRemoteProblem::USER_AGENT); +$res = false; + +function validateLuogu($response) { + $response = json_decode(json_encode($response), true); + + return $response['currentTemplate'] !== 'AuthLogin'; +} + +if ($type == 'luogu') { + $curl->setFollowLocation(); + $curl->setCookie('_uid', UOJRequest::post('_uid', 'is_string', '')); + $curl->setCookie('__client_id', UOJRequest::post('__client_id', 'is_string', '')); + + retry_loop(function () use (&$curl, &$res) { + $curl->get(UOJRemoteProblem::$providers['luogu']['url'] . '/user/setting?_contentOnly=1'); + + if ($curl->error) { + return false; + } + + if ($curl->responseHeaders['Content-Type'] == 'text/html') { + $sec = $curl->getResponseCookie('sec'); + + if ($sec) { + $curl->setCookie('sec', $sec); + $curl->get(UOJRemoteProblem::$providers['luogu']['url'] . '/user/setting?_contentOnly=1'); + + if ($curl->responseHeaders['Content-Type'] == 'application/json') { + $res = validateLuogu($curl->response); + + return true; + } + + return false; + } + + return false; + } else if ($curl->responseHeaders['Content-Type'] == 'application/json') { + $res = validateLuogu($curl->response); + + return true; + } + + return false; + }, 3); + + die(json_encode(['ok' => $res === true])); +} else if ($type == 'codeforces') { + $curl->setFollowLocation(); + $curl->setCookie('JSESSIONID', UOJRequest::post('JSESSIONID', 'is_string', '')); + + retry_loop(function () use (&$curl, &$res) { + $curl->get(UOJRemoteProblem::$providers['codeforces']['url'] . '/enter'); + + if ($curl->error) { + return false; + } + + if (str_starts_with($curl->responseHeaders['Content-Type'], 'text/html')) { + if (str_contains($curl->response, 'Login into Codeforces')) { + return false; + } + + if (strlen($curl->response) < 1000 && str_contains($curl->response, 'Redirecting...')) { + return false; + } + + $res = true; + + return true; + } + + return false; + }, 3); +} else { + UOJResponse::page406(); +} + +die(json_encode(['ok' => $res === true])); diff --git a/web/app/controllers/subdomain/api/route.php b/web/app/controllers/subdomain/api/route.php new file mode 100644 index 0000000..ae169a7 --- /dev/null +++ b/web/app/controllers/subdomain/api/route.php @@ -0,0 +1,12 @@ + UOJConfig::$data['web']['main']['host'], + ], + function () { + Route::post("/api/remote_judge/custom_account_validator", '/subdomain/api/remote_judge/custom_account_validator.php'); + } + ); +}); diff --git a/web/app/models/UOJForm.php b/web/app/models/UOJForm.php index 963a640..b6d2c51 100644 --- a/web/app/models/UOJForm.php +++ b/web/app/models/UOJForm.php @@ -665,7 +665,12 @@ class UOJForm { EOD; } else { echo <<form_name}").addClass('disabled'); + if (ok) { + $("#button-submit-{$this->form_name}").addClass('disabled'); + $(this).submit(function () { + return false; + }); + } return ok; EOD; } diff --git a/web/index.php b/web/index.php index 6e29eca..0953945 100644 --- a/web/index.php +++ b/web/index.php @@ -5,6 +5,7 @@ require $_SERVER['DOCUMENT_ROOT'] . '/app/libs/uoj-lib.php'; require UOJContext::documentRoot().'/app/route.php'; require UOJContext::documentRoot().'/app/controllers/subdomain/blog/route.php'; +require UOJContext::documentRoot().'/app/controllers/subdomain/api/route.php'; include UOJContext::documentRoot().'/app/controllers'.call_user_func(function() { $route = Route::dispatch(); diff --git a/web/js/uoj.js b/web/js/uoj.js index 9146f3d..e08d151 100644 --- a/web/js/uoj.js +++ b/web/js/uoj.js @@ -958,19 +958,68 @@ $.fn.remote_submit_type_group = function(oj, pid, url, submit_type) { var input_submit_type_bot = $(''); var input_submit_type_my = $(''); var input_my_account_data = $(''); + + var my_account_validation_status = $('').append('待验证'); + var my_account_validation_btn = $(''); + + var validate_my_account = function(data) { + my_account_validation_btn.html(''); + my_account_validation_btn.addClass('disabled'); + + $.ajax({ + type: 'POST', + url: '/api/remote_judge/custom_account_validator?type=' + oj, + data: data, + success: function(res) { + my_account_validation_btn.html('验证'); + my_account_validation_btn.removeClass('disabled'); + + console.log('Validation status', res); + + if (res.ok) { + my_account_validation_status.html('可用'); + } else { + my_account_validation_status.html('不可用'); + } + }, + error: function() { + my_account_validation_btn.html('验证'); + my_account_validation_btn.removeClass('disabled'); + my_account_validation_status.html('待验证'); + }, + dataType: 'json', + }); + }; var div_submit_type_bot = $('
') .append('
将使用公用账号提交本题。
'); var div_submit_type_my = $('
') - .append('
将使用您的账号提交本题。
'); + .append($('
') + .append('将使用您的账号提交本题。') + .append('账号状态:') + .append(my_account_validation_status) + .append(my_account_validation_btn) + ); + + if ('localStorage' in window) { + var prefer_submit_type = localStorage.getItem('uoj_remote_judge_save_prefer_submit_type__' + oj) || null; + var save_prefer_submit_type = function(type) { + localStorage.setItem('uoj_remote_judge_save_prefer_submit_type__' + oj, type); + } + } else { + var prefer_submit_type = null; + var save_prefer_submit_type = function(type) {}; + } input_submit_type_bot.click(function() { div_submit_type_my.hide('fast'); div_submit_type_bot.show('fast'); + save_prefer_submit_type('bot'); }); input_submit_type_my.click(function() { div_submit_type_bot.hide('fast'); div_submit_type_my.show('fast'); + save_prefer_submit_type('my'); }); if (submit_type[0] == 'bot') { @@ -983,15 +1032,26 @@ $.fn.remote_submit_type_group = function(oj, pid, url, submit_type) { if (submit_type.indexOf('bot') == -1) { input_submit_type_bot.attr('disabled', 'disabled'); + } else if (prefer_submit_type == 'bot') { + div_submit_type_my.hide(); + div_submit_type_bot.show(); + input_submit_type_bot[0].checked = true; + input_submit_type_my[0].checked = false; } + if (submit_type.indexOf('my') == -1) { input_submit_type_my.attr('disabled', 'disabled'); + } else if (prefer_submit_type == 'my') { + div_submit_type_bot.hide(); + div_submit_type_my.show(); + input_submit_type_bot[0].checked = false; + input_submit_type_my[0].checked = true; } if (oj == 'luogu') { var luogu_account_data = {"_uid": "", "__client_id": ""}; - var input_luogu_uid = $(''); - var input_luogu_client_id = $(''); + var input_luogu_uid = $(''); + var input_luogu_client_id = $(''); if ('localStorage' in window) { try { @@ -1012,32 +1072,50 @@ $.fn.remote_submit_type_group = function(oj, pid, url, submit_type) { luogu_account_data._uid = $(this).val(); input_my_account_data.val(JSON.stringify(luogu_account_data)); save_luogu_account_data(); + my_account_validation_status.html('待验证'); }); input_luogu_client_id.change(function() { luogu_account_data.__client_id = $(this).val(); input_my_account_data.val(JSON.stringify(luogu_account_data)); save_luogu_account_data(); + my_account_validation_status.html('待验证'); + }); + + my_account_validation_btn.click(function() { + validate_my_account({ + type: 'luogu', + _uid: input_luogu_uid.val(), + __client_id: input_luogu_client_id.val(), + }); }); input_my_account_data.val(JSON.stringify(luogu_account_data)); input_luogu_uid.val(luogu_account_data._uid); input_luogu_client_id.val(luogu_account_data.__client_id); + if (luogu_account_data._uid && luogu_account_data.__client_id){ + validate_my_account({ + type: 'luogu', + _uid: luogu_account_data._uid, + __client_id: luogu_account_data.__client_id, + }); + } + div_submit_type_my.append( - $('
') + $('
') .append($('
').append('')) .append($('
').append(input_luogu_uid)) - .append($('
').append($('
').append('请填入 Cookie 中的 _uid。'))) + .append($('
').append($('
').append('请填入 Cookie 中的 _uid。'))) ).append( - $('
') + $('
') .append($('
').append('')) .append($('
').append(input_luogu_client_id)) - .append($('
').append($('
').append('请填入 Cookie 中的 __client_id。'))) + .append($('
').append($('
').append('请填入 Cookie 中的 __client_id。'))) ).append(input_my_account_data); } else if (oj == 'codeforces') { var codeforces_account_data = {"JSESSIONID": ""}; - var input_codeforces_jsessionid = $(''); + var input_codeforces_jsessionid = $(''); if ('localStorage' in window) { try { @@ -1056,16 +1134,31 @@ $.fn.remote_submit_type_group = function(oj, pid, url, submit_type) { codeforces_account_data.JSESSIONID = $(this).val(); input_my_account_data.val(JSON.stringify(codeforces_account_data)); save_codeforces_account_data(); + my_account_validation_status.html('待验证'); + }); + + my_account_validation_btn.click(function() { + validate_my_account({ + type: 'codeforces', + JSESSIONID: input_codeforces_jsessionid.val(), + }); }); input_my_account_data.val(JSON.stringify(codeforces_account_data)); input_codeforces_jsessionid.val(codeforces_account_data.JSESSIONID); + if (codeforces_account_data.JSESSIONID) { + validate_my_account({ + type: 'codeforces', + JSESSIONID: codeforces_account_data.JSESSIONID, + }); + } + div_submit_type_my.append( - $('
') + $('
') .append($('
').append('')) .append($('
').append(input_codeforces_jsessionid)) - .append($('
').append($('
').append('请填入 Cookie 中的 JSESSIONID。'))) + .append($('
').append($('
').append('请填入 Cookie 中的 JSESSIONID。'))) ).append(input_my_account_data); } else if (oj == 'uoj') { var uoj_account_data = {"UOJSESSID": ""};