mirror of
https://gitcode.com/gh_mirrors/hy/Hydro.git
synced 2026-10-17 09:36:08 +08:00
vjudge: codeforces: add getCsrfTokenOnDocument (#855)
Co-authored-by: undefined <i@undefined.moe>
This commit is contained in:
1 parent
ef4862d785
commit
5eea7489c9
1 file changed
+49
-40
@@ -82,6 +82,16 @@ export default class CodeforcesProvider extends BasicFetcher implements IBasicPr
|
||||
return _tta;
|
||||
}
|
||||
|
||||
getCsrfTokenOnDocument(document: Document) {
|
||||
const meta = document.querySelector("meta[name='X-Csrf-Token']")?.getAttribute('content');
|
||||
if (meta?.length === 32) return meta;
|
||||
const span = document.querySelector('span.csrf-token')?.getAttribute('data-csrf');
|
||||
if (span?.length === 32) return span;
|
||||
const input = document.querySelector('input[name="csrf_token"]')?.getAttribute('value');
|
||||
if (input?.length === 32) return input;
|
||||
return '';
|
||||
}
|
||||
|
||||
async getCsrfToken(url: string) {
|
||||
const { document, html, headers } = await this.html(url);
|
||||
if (document.body.children.length < 2 && html.length < 512) {
|
||||
@@ -89,13 +99,7 @@ export default class CodeforcesProvider extends BasicFetcher implements IBasicPr
|
||||
}
|
||||
const ftaa = this.getCookie('70a7c28f3de') || 'n/a';
|
||||
const bfaa = this.getCookie('raa') || this.getCookie('bfaa') || 'n/a';
|
||||
return [
|
||||
(
|
||||
document.querySelector('meta[name="X-Csrf-Token"]')
|
||||
|| document.querySelector('input[name="csrf_token"]')
|
||||
)?.getAttribute('content'),
|
||||
ftaa, bfaa, headers,
|
||||
];
|
||||
return [this.getCsrfTokenOnDocument(document), ftaa, bfaa, headers];
|
||||
}
|
||||
|
||||
get loggedIn() {
|
||||
@@ -270,11 +274,15 @@ export default class CodeforcesProvider extends BasicFetcher implements IBasicPr
|
||||
});
|
||||
}
|
||||
|
||||
async readLatestSubmission(contestId = '') {
|
||||
const { document } = await this.html(contestId ? `/gym/${contestId}/my` : '/problemset/status?my=on');
|
||||
this.csrf = document.querySelector('meta[name="X-Csrf-Token"]').getAttribute('content');
|
||||
const submission = document.querySelector('[data-submission-id]').getAttribute('data-submission-id');
|
||||
return submission;
|
||||
async readLatestSubmission(contestId = '', allowEmpty = false) {
|
||||
for (let i = 1; i <= 3; i++) {
|
||||
await sleep(1000);
|
||||
const { document } = await this.html(contestId ? `/gym/${contestId}/my` : '/problemset/status?my=on');
|
||||
this.csrf = this.getCsrfTokenOnDocument(document);
|
||||
const id = document.querySelector('[data-submission-id]')?.getAttribute('data-submission-id');
|
||||
if (id || allowEmpty) return id;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
async submitProblem(id: string, lang: string, code: string, info, next, end) {
|
||||
@@ -283,37 +291,38 @@ export default class CodeforcesProvider extends BasicFetcher implements IBasicPr
|
||||
const endpoint = type === 'GYM'
|
||||
? `/gym/${contestId}/submit`
|
||||
: `/problemset/submit/${contestId}/${problemId}`;
|
||||
const latestSubmission = await this.readLatestSubmission(type === 'GYM' ? contestId : '');
|
||||
const [csrf, ftaa, bfaa] = await this.getCsrfToken(endpoint);
|
||||
// TODO check submit time to ensure submission
|
||||
const { text: submit, redirects } = await this.post(`${endpoint}?csrf_token=${csrf}`).send({
|
||||
csrf_token: csrf,
|
||||
action: 'submitSolutionFormSubmitted',
|
||||
programTypeId,
|
||||
source: code,
|
||||
tabSize: 4,
|
||||
sourceFile: '',
|
||||
ftaa,
|
||||
bfaa,
|
||||
_tta: this.tta(this.getCookie('39ce7')),
|
||||
contestId,
|
||||
submittedProblemIndex: problemId,
|
||||
});
|
||||
const { window: { document: statusDocument } } = new JSDOM(submit);
|
||||
const message = Array.from(statusDocument.querySelectorAll('.error'))
|
||||
.map((i) => i.textContent).join('').replace(/ /g, ' ').trim();
|
||||
if (message) {
|
||||
end({ status: STATUS.STATUS_SYSTEM_ERROR, message });
|
||||
return null;
|
||||
}
|
||||
const submission = await this.readLatestSubmission(type === 'GYM' ? contestId : '');
|
||||
if (submission === latestSubmission || redirects.length === 0 || !redirects.toString().includes('my')) {
|
||||
// Submit failed so the request is not redirected
|
||||
try {
|
||||
const latestSubmission = await this.readLatestSubmission(type === 'GYM' ? contestId : '', true);
|
||||
const [csrf, ftaa, bfaa] = await this.getCsrfToken(endpoint);
|
||||
// TODO check submit time to ensure submission
|
||||
const { text: submit, redirects } = await this.post(`${endpoint}?csrf_token=${csrf}`).send({
|
||||
csrf_token: csrf,
|
||||
action: 'submitSolutionFormSubmitted',
|
||||
programTypeId,
|
||||
source: code,
|
||||
tabSize: 4,
|
||||
sourceFile: '',
|
||||
ftaa,
|
||||
bfaa,
|
||||
_tta: this.tta(this.getCookie('39ce7')),
|
||||
contestId,
|
||||
submittedProblemIndex: problemId,
|
||||
});
|
||||
const { window: { document: statusDocument } } = new JSDOM(submit);
|
||||
const message = Array.from(statusDocument.querySelectorAll('.error'))
|
||||
.map((i) => i.textContent).join('').replace(/ /g, ' ').trim();
|
||||
if (message) throw new Error(message);
|
||||
const submission = await this.readLatestSubmission(type === 'GYM' ? contestId : '');
|
||||
if (!submission) throw new Error('Failed to get submission id.');
|
||||
if (submission === latestSubmission) throw new Error('Submission page is not updated.');
|
||||
if (redirects.length === 0 || !redirects.toString().includes('my')) throw new Error('No redirect to submission page.');
|
||||
return type !== 'GYM' ? submission : `${contestId}#${submission}`;
|
||||
} catch (e) {
|
||||
next({ message: e.message });
|
||||
// eslint-disable-next-line max-len
|
||||
end({ status: STATUS.STATUS_SYSTEM_ERROR, message: 'Submit failed. Check service status or use better network to avoid rejection by server protection.' });
|
||||
end({ status: STATUS.STATUS_SYSTEM_ERROR, message: 'Submit to remote failed. Check service status or use better network to avoid rejection by server protection.' });
|
||||
return null;
|
||||
}
|
||||
return type !== 'GYM' ? submission : `${contestId}#${submission}`;
|
||||
}
|
||||
|
||||
async waitForSubmission(id: string, next, end) {
|
||||
|
||||
Reference in new issue
Block a user