@goodandready/dsh-moa 0.2.40 → 0.2.42
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +7 -0
- package/README.ru.md +7 -0
- package/README.zh.md +11 -0
- package/lib/client.js +407 -98
- package/lib/history.js +169 -35
- package/lib/index.js +21 -3
- package/lib/live-canvas.js +39 -6
- package/lib/moa-multi-judge.js +151 -59
- package/lib/moa-report.js +41 -20
- package/lib/moa-runner.js +11 -6
- package/lib/moa-stream.js +57 -1
- package/lib/pricing.js +10 -6
- package/lib/routes.js +3 -2
- package/lib/updater.js +23 -0
- package/package.json +1 -1
package/lib/routes.js
CHANGED
|
@@ -356,7 +356,9 @@ ctx.effect(() => {
|
|
|
356
356
|
}
|
|
357
357
|
try {
|
|
358
358
|
const u = new URL(req.url, 'http://localhost')
|
|
359
|
-
const
|
|
359
|
+
const runId = u.searchParams.get('runId') || undefined
|
|
360
|
+
const run = runId ? getMoaRunById(runId) : null
|
|
361
|
+
const cwd = run?.cwd || u.searchParams.get('cwd') || process.cwd()
|
|
360
362
|
const sanitizeTarget = (val, def) => {
|
|
361
363
|
const clean = String(val || '').trim().replace(/[^a-zA-Z0-9_-]/g, '')
|
|
362
364
|
return clean || def
|
|
@@ -366,7 +368,6 @@ ctx.effect(() => {
|
|
|
366
368
|
const rawFile = u.searchParams.get('file') || ''
|
|
367
369
|
const file = (rawFile && isSafeRelativePath(rawFile)) ? rawFile : ''
|
|
368
370
|
|
|
369
|
-
const runId = u.searchParams.get('runId') || undefined
|
|
370
371
|
const fromFiles = await readCandidateFiles(cwd, from, { runId })
|
|
371
372
|
const toFiles = await readCandidateFiles(cwd, to, { runId })
|
|
372
373
|
|
package/lib/updater.js
CHANGED
|
@@ -43,18 +43,39 @@ export function isTrustedUpdateRequest(request) {
|
|
|
43
43
|
|
|
44
44
|
/** General safe write check for plugin write endpoints (CSRF / Cross-Site protection) */
|
|
45
45
|
export function isSafeWriteRequest(request) {
|
|
46
|
+
const remote = request?.socket?.remoteAddress || request?.connection?.remoteAddress;
|
|
47
|
+
const isLoop = !remote || isLoopback(remote);
|
|
48
|
+
|
|
46
49
|
const site = header(request, 'sec-fetch-site');
|
|
47
50
|
if (site === 'cross-site') return false;
|
|
51
|
+
|
|
48
52
|
const origin = header(request, 'origin');
|
|
49
53
|
const host = header(request, 'host');
|
|
54
|
+
|
|
55
|
+
// If non-loopback caller, require valid same-origin browser proof
|
|
56
|
+
if (!isLoop) {
|
|
57
|
+
if (!origin || !host) return false;
|
|
58
|
+
if (site && site !== 'same-origin' && site !== 'none') return false;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
// Same-site without matching origin is rejected regardless of remote
|
|
62
|
+
if (site === 'same-site') {
|
|
63
|
+
if (!origin || !host) return false;
|
|
64
|
+
}
|
|
65
|
+
|
|
50
66
|
if (origin) {
|
|
67
|
+
if (origin === 'null') return false;
|
|
51
68
|
try {
|
|
52
69
|
const url = new URL(origin);
|
|
53
70
|
if (host && url.host !== host) return false;
|
|
71
|
+
if (!isLoop) {
|
|
72
|
+
if (url.protocol !== 'http:' && url.protocol !== 'https:') return false;
|
|
73
|
+
}
|
|
54
74
|
} catch {
|
|
55
75
|
return false;
|
|
56
76
|
}
|
|
57
77
|
}
|
|
78
|
+
|
|
58
79
|
return true;
|
|
59
80
|
}
|
|
60
81
|
|
|
@@ -353,6 +374,8 @@ export function registerPluginUpdater(ctx, options) {
|
|
|
353
374
|
}
|
|
354
375
|
await installExact(target, `${options.packageName}@${before.latestVersion}`, options);
|
|
355
376
|
json(response, 200, {
|
|
377
|
+
ok: true,
|
|
378
|
+
updated: true,
|
|
356
379
|
...before,
|
|
357
380
|
updatedVersion: before.latestVersion,
|
|
358
381
|
restartRequired: true,
|