Browse Source

Fix CSRF for APIs

master
Menci 8 years ago
parent
commit
87dd3a787c
  1. 8
      app.js
  2. 3
      models/judge_state.js
  3. 8
      models/waiting_judge.js
  4. 71
      modules/api.js
  5. 83
      modules/api_v2.js
  6. 3
      modules/problem.js

8
app.js

@ -60,6 +60,14 @@ global.syzoj = {
let multer = require('multer'); let multer = require('multer');
app.multer = multer({ dest: syzoj.utils.resolvePath(syzoj.config.upload_dir, 'tmp') }); app.multer = multer({ dest: syzoj.utils.resolvePath(syzoj.config.upload_dir, 'tmp') });
// Trick to bypass CSRF for APIv2
app.use((() => {
let router = new Express.Router();
app.apiRouter = router;
require('./modules/api_v2');
return router;
})());
let csurf = require('csurf'); let csurf = require('csurf');
app.use(csurf({ cookie: true })); app.use(csurf({ cookie: true }));

3
models/judge_state.js

@ -219,7 +219,8 @@ class JudgeState extends Model {
let WaitingJudge = syzoj.model('waiting_judge'); let WaitingJudge = syzoj.model('waiting_judge');
let waiting_judge = await WaitingJudge.create({ let waiting_judge = await WaitingJudge.create({
judge_id: this.id judge_id: this.id,
priority: 2
}); });
await waiting_judge.save(); await waiting_judge.save();

8
models/waiting_judge.js

@ -26,7 +26,10 @@ let JudgeState = syzoj.model('judge_state');
let model = db.define('waiting_judge', { let model = db.define('waiting_judge', {
id: { type: Sequelize.INTEGER, primaryKey: true, autoIncrement: true }, id: { type: Sequelize.INTEGER, primaryKey: true, autoIncrement: true },
judge_id: { type: Sequelize.INTEGER } judge_id: { type: Sequelize.INTEGER },
// Smaller is higher
priority: { type: Sequelize.INTEGER }
}, { }, {
timestamps: false, timestamps: false,
tableName: 'waiting_judge', tableName: 'waiting_judge',
@ -41,7 +44,8 @@ let Model = require('./common');
class WaitingJudge extends Model { class WaitingJudge extends Model {
static async create(val) { static async create(val) {
return WaitingJudge.fromRecord(WaitingJudge.model.build(Object.assign({ return WaitingJudge.fromRecord(WaitingJudge.model.build(Object.assign({
judge_id: 0 judge_id: 0,
priority: 0
}, val))); }, val)));
} }

71
modules/api.js

@ -21,8 +21,6 @@
let User = syzoj.model('user'); let User = syzoj.model('user');
let Problem = syzoj.model('problem'); let Problem = syzoj.model('problem');
let WaitingJudge = syzoj.model('waiting_judge');
let JudgeState = syzoj.model('judge_state');
let File = syzoj.model('file'); let File = syzoj.model('file');
function setLoginCookie(username, password, res) { function setLoginCookie(username, password, res) {
@ -163,75 +161,6 @@ app.post('/api/markdown', async (req, res) => {
} }
}); });
// APIs for judge client
app.post('/api/waiting_judge', async (req, res) => {
try {
if (req.query.session_id !== syzoj.config.judge_token) return res.status(404).send({ err: 'Permission denied' });
let judge_state;
await syzoj.utils.lock('/api/waiting_judge', async () => {
let waiting_judge = await WaitingJudge.findOne();
if (!waiting_judge) {
return;
}
judge_state = await waiting_judge.getJudgeState();
await judge_state.loadRelationships();
await judge_state.problem.loadRelationships();
await waiting_judge.destroy();
});
if (judge_state) {
await judge_state.loadRelationships();
await judge_state.problem.loadRelationships();
if (judge_state.problem.type === 'submit-answer') {
res.send({
have_task: 1,
judge_id: judge_state.id,
answer_file: judge_state.code,
testdata: judge_state.problem.id,
problem_type: judge_state.problem.type
});
} else {
res.send({
have_task: 1,
judge_id: judge_state.id,
code: judge_state.code,
language: judge_state.language,
testdata: judge_state.problem.id,
time_limit: judge_state.problem.time_limit,
memory_limit: judge_state.problem.memory_limit,
file_io: judge_state.problem.file_io,
file_io_input_name: judge_state.problem.file_io_input_name,
file_io_output_name: judge_state.problem.file_io_output_name,
problem_type: judge_state.problem.type
});
}
} else {
res.send({ have_task: 0 });
}
} catch (e) {
res.status(500).send(e);
}
});
app.post('/api/update_judge/:id', async (req, res) => {
try {
if (req.query.session_id !== syzoj.config.judge_token) return res.status(404).send({ err: 'Permission denied' });
let judge_state = await JudgeState.fromID(req.params.id);
await judge_state.updateResult(JSON.parse(req.body.result));
await judge_state.save();
await judge_state.updateRelatedInfo();
res.send({ return: 0 });
} catch (e) {
syzoj.log(e);
res.status(500).send(e);
}
});
app.get('/static/uploads/answer/:md5', async (req, res) => { app.get('/static/uploads/answer/:md5', async (req, res) => {
try { try {
res.sendFile(File.resolvePath('answer', req.params.md5)); res.sendFile(File.resolvePath('answer', req.params.md5));

83
modules/api_v2.js

@ -19,11 +19,10 @@
'use strict'; 'use strict';
let Problem = syzoj.model('problem');
let ProblemTag = syzoj.model('problem_tag');
app.get('/api/v2/search/problems/:keyword*?', async (req, res) => { app.get('/api/v2/search/problems/:keyword*?', async (req, res) => {
try { try {
let Problem = syzoj.model('problem');
let keyword = req.params.keyword || ''; let keyword = req.params.keyword || '';
let problems = await Problem.query(null, { let problems = await Problem.query(null, {
title: { like: `%${req.params.keyword}%` } title: { like: `%${req.params.keyword}%` }
@ -54,6 +53,9 @@ app.get('/api/v2/search/problems/:keyword*?', async (req, res) => {
app.get('/api/v2/search/tags/:keyword*?', async (req, res) => { app.get('/api/v2/search/tags/:keyword*?', async (req, res) => {
try { try {
let Problem = syzoj.model('problem');
let ProblemTag = syzoj.model('problem_tag');
let keyword = req.params.keyword || ''; let keyword = req.params.keyword || '';
let tags = await ProblemTag.query(null, { let tags = await ProblemTag.query(null, {
name: { like: `%${req.params.keyword}%` } name: { like: `%${req.params.keyword}%` }
@ -69,7 +71,7 @@ app.get('/api/v2/search/tags/:keyword*?', async (req, res) => {
} }
}); });
app.post('/api/v2/markdown', async (req, res) => { app.apiRouter.post('/api/v2/markdown', async (req, res) => {
try { try {
let s = await syzoj.utils.markdown(req.body.s.toString(), null, req.body.noReplaceUI === 'true'); let s = await syzoj.utils.markdown(req.body.s.toString(), null, req.body.noReplaceUI === 'true');
res.send(s); res.send(s);
@ -78,3 +80,76 @@ app.post('/api/v2/markdown', async (req, res) => {
res.send(e); res.send(e);
} }
}); });
// APIs for judge client
app.apiRouter.post('/api/v2/judge/peek', async (req, res) => {
try {
if (req.query.session_id !== syzoj.config.judge_token) return res.status(404).send({ err: 'Permission denied' });
let WaitingJudge = syzoj.model('waiting_judge');
let JudgeState = syzoj.model('judge_state');
let judge_state;
await syzoj.utils.lock('/api/v2/judge/peek', async () => {
let waiting_judge = await WaitingJudge.findOne({ order: [['priority', 'ASC']] });
if (!waiting_judge) {
return;
}
judge_state = await waiting_judge.getJudgeState();
await judge_state.loadRelationships();
await judge_state.problem.loadRelationships();
await waiting_judge.destroy();
});
if (judge_state) {
await judge_state.loadRelationships();
await judge_state.problem.loadRelationships();
if (judge_state.problem.type === 'submit-answer') {
res.send({
have_task: 1,
judge_id: judge_state.id,
answer_file: judge_state.code,
testdata: judge_state.problem.id,
problem_type: judge_state.problem.type
});
} else {
res.send({
have_task: 1,
judge_id: judge_state.id,
code: judge_state.code,
language: judge_state.language,
testdata: judge_state.problem.id,
time_limit: judge_state.problem.time_limit,
memory_limit: judge_state.problem.memory_limit,
file_io: judge_state.problem.file_io,
file_io_input_name: judge_state.problem.file_io_input_name,
file_io_output_name: judge_state.problem.file_io_output_name,
problem_type: judge_state.problem.type
});
}
} else {
res.send({ have_task: 0 });
}
} catch (e) {
res.status(500).send(e);
}
});
app.apiRouter.post('/api/v2/judge/update/:id', async (req, res) => {
try {
if (req.query.session_id !== syzoj.config.judge_token) return res.status(404).send({ err: 'Permission denied' });
let JudgeState = syzoj.model('judge_state');
let judge_state = await JudgeState.fromID(req.params.id);
await judge_state.updateResult(JSON.parse(req.body.result));
await judge_state.save();
await judge_state.updateRelatedInfo();
res.send({ return: 0 });
} catch (e) {
syzoj.log(e);
res.status(500).send(e);
}
});

3
modules/problem.js

@ -633,7 +633,8 @@ app.post('/problem/:id/submit', app.multer.fields([{ name: 'answer', maxCount: 1
await judge_state.updateRelatedInfo(true); await judge_state.updateRelatedInfo(true);
let waiting_judge = await WaitingJudge.create({ let waiting_judge = await WaitingJudge.create({
judge_id: judge_state.id judge_id: judge_state.id,
priority: 1
}); });
await waiting_judge.save(); await waiting_judge.save();

Loading…
Cancel
Save