diff --git a/remote_judger/src/providers/codeforces.ts b/remote_judger/src/providers/codeforces.ts index 76eb301..bf652ad 100644 --- a/remote_judger/src/providers/codeforces.ts +++ b/remote_judger/src/providers/codeforces.ts @@ -11,7 +11,7 @@ import Logger from '../utils/logger'; proxy(superagent); const logger = new Logger('remote/codeforces'); -const langs_map = { +const LANGS_MAP = { C: { name: 'GNU GCC C11 5.1.0', id: 43, @@ -88,7 +88,10 @@ export default class CodeforcesProvider implements IBasicProvider { } static constructFromAccountData(data) { - throw new Error('Method not implemented.'); + return new this({ + type: 'codeforces', + cookie: Object.entries(data).map(([key, value]) => `${key}=${value}`), + }); } cookie: string[] = []; @@ -166,23 +169,41 @@ export default class CodeforcesProvider implements IBasicProvider { get loggedIn() { return this.get('/enter').then(res => { const html = res.text; + if (html.includes('Login into Codeforces')) return false; + if (html.length < 1000 && html.includes('Redirecting...')) { logger.debug('Got a redirect', html); return false; } + + if (res.header['set-cookie']) { + const _39ce7 = this.getCookie.call( + { cookie: res.header['set-cookie'] }, + '39ce7' + ); + + if (_39ce7) this.setCookie('39ce7', _39ce7); + } + return true; }); } async ensureLogin() { if (await this.loggedIn) return true; + logger.info('retry normal login'); + + if (!this.account.handle) return false; + const [csrf, ftaa, bfaa] = await this.getCsrfToken('/enter'); const { header } = await this.get('/enter'); + if (header['set-cookie']) { this.cookie = header['set-cookie']; } + const res = await this.post('/enter').send({ csrf_token: csrf, action: 'enter', @@ -193,10 +214,13 @@ export default class CodeforcesProvider implements IBasicProvider { remember: 'on', _tta: this.tta(this.getCookie('39ce7')), }); + const cookie = res.header['set-cookie']; + if (cookie) { this.cookie = cookie; } + if (await this.loggedIn) { logger.success('Logged in'); return true; @@ -212,18 +236,32 @@ export default class CodeforcesProvider implements IBasicProvider { next, end ) { - const programType = langs_map[lang] || langs_map['C++']; + if (!(await this.ensureLogin())) { + end({ + error: true, + status: 'Judgment Failed', + message: 'Login failed', + }); + + return null; + } + + const programType = LANGS_MAP[lang] || LANGS_MAP['C++']; const comment = programType.comment; + if (comment) { const msg = `S2OJ Submission #${submissionId} @ ${new Date().getTime()}`; if (typeof comment === 'string') code = `${comment} ${msg}\n${code}`; else if (comment instanceof Array) code = `${comment[0]} ${msg} ${comment[1]}\n${code}`; } + const [type, contestId, problemId] = parseProblemId(id); + const [csrf, ftaa, bfaa] = await this.getCsrfToken( type !== 'GYM' ? '/problemset/submit' : `/gym/${contestId}/submit` ); + logger.debug( 'Submitting', id, @@ -231,6 +269,7 @@ export default class CodeforcesProvider implements IBasicProvider { lang, `(S2OJ Submission #${submissionId})` ); + // TODO: check submit time to ensure submission const { text: submit, error } = await this.post( `/${ diff --git a/web/app/models/UOJRemoteProblem.php b/web/app/models/UOJRemoteProblem.php index 636984a..15abe74 100644 --- a/web/app/models/UOJRemoteProblem.php +++ b/web/app/models/UOJRemoteProblem.php @@ -14,7 +14,7 @@ class UOJRemoteProblem { 'ограничение по времени на тест', ], 'languages' => ['C', 'C++', 'C++17', 'C++20', 'Java17', 'Pascal', 'Python2', 'Python3'], - 'submit_type' => ['bot'], + 'submit_type' => ['bot', 'my'], ], 'atcoder' => [ 'name' => 'AtCoder', diff --git a/web/js/uoj.js b/web/js/uoj.js index 3e1f1c2..47ddeae 100644 --- a/web/js/uoj.js +++ b/web/js/uoj.js @@ -1026,15 +1026,47 @@ $.fn.remote_submit_type_group = function(oj, pid, url, submit_type) { div_submit_type_my.append( $('
') - .append($('
').append('')) + .append($('
').append('')) .append($('
').append(input_luogu_uid)) .append($('
').append($('
').append('请填入 Cookie 中的 _uid。'))) ).append( $('
') - .append($('
').append('')) + .append($('
').append('')) .append($('
').append(input_luogu_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 = $(''); + + if ('localStorage' in window) { + try { + var codeforces_account_data_str = localStorage.getItem('uoj_remote_judge_codeforces_account_data'); + if (codeforces_account_data_str) { + codeforces_account_data = JSON.parse(codeforces_account_data_str); + } + } catch (e) {} + + var save_codeforces_account_data = function() { + localStorage.setItem('uoj_remote_judge_codeforces_account_data', JSON.stringify(codeforces_account_data)); + } + } + + input_codeforces_jsessionid.change(function() { + codeforces_account_data.JSESSIONID = $(this).val(); + input_my_account_data.val(JSON.stringify(codeforces_account_data)); + save_codeforces_account_data(); + }); + + input_my_account_data.val(JSON.stringify(codeforces_account_data)); + input_codeforces_jsessionid.val(codeforces_account_data.JSESSIONID); + + div_submit_type_my.append( + $('
') + .append($('
').append('')) + .append($('
').append(input_codeforces_jsessionid)) + .append($('
').append($('
').append('请填入 Cookie 中的 JSESSIONID。'))) + ).append(input_my_account_data); } $(this).append(