openvibers/openvibe.codes Commits
Cancelling a task refuses a cross-site post, as starting one does (#268)
Changes
@@@ -123,6 +123,8 @@ function createMeApi({ config, store, sso, run, harnesses, actorLimits, tasks =r.post('/me/tasks/:id/cancel', actorLimits.budget('codes.task.start'), async (req, res) => {if (!signedIn(req)) return problem(req, res, 401, 'auth.required', 'sign in to cancel your tasks');++ // As starting a task: a cross-site post from a signed-in browser cannot cancel one (REVIEW-0, 11-03).++ if (!sameOrigin(req)) return problem(req, res, 403, 'cross_site', 'cross-site posts are refused');let row = await own(req, req.params.id);if (!row) return problem(req, res, 404, 'codes.task_not_found', 'no such task of yours');if (row.job_id && !TERMINAL.has(row.state)) {@@@ -71,6 +71,10 @@ const { boot, check, done } = require('./helpers/boot');await check('cancel reaches Run and returns the final state', async () => {const list = await call('GET', '/tasks', { as: ada });const id = list.json().tasks[0].id;++ // REVIEW-0 (11-03): a cross-site post cannot cancel it, as it cannot start one.++ const cross = await call('POST', `/tasks/${id}/cancel`, { as: ada, origin: 'https://evil.example' });++ assert.strictEqual(cross.status, 403);++ assert.ok(!calls.some((x) => x[0] === 'cancel'), 'nothing reached Run');const c = await call('POST', `/tasks/${id}/cancel`, { as: ada });assert.strictEqual(c.status, 200);assert.strictEqual(c.json().state, 'cancelled');
@@ -123,6 +123,8 @@ function createMeApi({ config, store, sso, run, harnesses, actorLimits, tasks =
@@ -123,6 +123,8 @@ function createMeApi({ config, store, sso, run, harnesses, actorLimits, tasks =
r.post('/me/tasks/:id/cancel', actorLimits.budget('codes.task.start'), async (req, res) => {
r.post('/me/tasks/:id/cancel', actorLimits.budget('codes.task.start'), async (req, res) => {
if (!signedIn(req)) return problem(req, res, 401, 'auth.required', 'sign in to cancel your tasks');
if (!signedIn(req)) return problem(req, res, 401, 'auth.required', 'sign in to cancel your tasks');
+ // As starting a task: a cross-site post from a signed-in browser cannot cancel one (REVIEW-0, 11-03).
+ if (!sameOrigin(req)) return problem(req, res, 403, 'cross_site', 'cross-site posts are refused');
let row = await own(req, req.params.id);
let row = await own(req, req.params.id);
if (!row) return problem(req, res, 404, 'codes.task_not_found', 'no such task of yours');
if (!row) return problem(req, res, 404, 'codes.task_not_found', 'no such task of yours');
if (row.job_id && !TERMINAL.has(row.state)) {
if (row.job_id && !TERMINAL.has(row.state)) {
@@ -71,6 +71,10 @@ const { boot, check, done } = require('./helpers/boot');
@@ -71,6 +71,10 @@ const { boot, check, done } = require('./helpers/boot');
await check('cancel reaches Run and returns the final state', async () => {
await check('cancel reaches Run and returns the final state', async () => {
const list = await call('GET', '/tasks', { as: ada });
const list = await call('GET', '/tasks', { as: ada });
const id = list.json().tasks[0].id;
const id = list.json().tasks[0].id;
+ // REVIEW-0 (11-03): a cross-site post cannot cancel it, as it cannot start one.
+ const cross = await call('POST', `/tasks/${id}/cancel`, { as: ada, origin: 'https://evil.example' });
+ assert.strictEqual(cross.status, 403);
+ assert.ok(!calls.some((x) => x[0] === 'cancel'), 'nothing reached Run');
const c = await call('POST', `/tasks/${id}/cancel`, { as: ada });
const c = await call('POST', `/tasks/${id}/cancel`, { as: ada });
assert.strictEqual(c.status, 200);
assert.strictEqual(c.status, 200);
assert.strictEqual(c.json().state, 'cancelled');
assert.strictEqual(c.json().state, 'cancelled');