core: api: ObjectID validation

This commit is contained in:
undefined committed 2021-10-28 00:06:47 +08:00
1 parent 5d9310fb78
commit 1f9d9a6b94
4 files changed
+38 -32

No files matched your search

+2 -1
View File
@@ -1,6 +1,6 @@
{ {
"name": "hydrooj", "name": "hydrooj",
"version": "3.1.10", "version": "3.1.11",
"bin": "bin/hydrooj.js", "bin": "bin/hydrooj.js",
"main": "src/loader", "main": "src/loader",
"module": "src/loader", "module": "src/loader",
@@ -12,6 +12,7 @@
}, },
"preferUnplugged": true, "preferUnplugged": true,
"dependencies": { "dependencies": {
"@graphql-tools/schema": "^8.3.1",
"@hydrooj/utils": "workspace:*", "@hydrooj/utils": "workspace:*",
"adm-zip": "0.5.5", "adm-zip": "0.5.5",
"ansi_up": "^5.0.1", "ansi_up": "^5.0.1",
+34 -29
View File
@@ -1,4 +1,5 @@
import graphql from 'graphql'; import { makeExecutableSchema } from '@graphql-tools/schema';
import { graphql, GraphQLSchema } from 'graphql';
import { resolvers, typeDefs } from 'graphql-scalars'; import { resolvers, typeDefs } from 'graphql-scalars';
import * as bus from '../service/bus'; import * as bus from '../service/bus';
import { Handler, Route } from '../service/server'; import { Handler, Route } from '../service/server';
@@ -6,7 +7,9 @@ import { Handler, Route } from '../service/server';
const types: Record<string, Record<string, string>> = {}; const types: Record<string, Record<string, string>> = {};
const unions: Record<string, string> = {}; const unions: Record<string, string> = {};
const descriptions: Record<string, Record<string, string>> = {}; const descriptions: Record<string, Record<string, string>> = {};
const handlers: Record<string, Record<string, any>> = {}; const handlers: Record<string, Record<string, any>> = {
Query: {},
};
let root: Record<string, any> = {}; let root: Record<string, any> = {};
export function registerValue(typeName: string, key: string, value: string, description?: string): void; export function registerValue(typeName: string, key: string, value: string, description?: string): void;
@@ -51,30 +54,32 @@ function setDescription(desc: string) {
return JSON.stringify(desc); return JSON.stringify(desc);
} }
function buildSchemaStr() { let schema: GraphQLSchema;
let res = `${Object.keys(unions).map((i) => `union ${i} = ${unions[i]}`)}\n${typeDefs.join('\n')}\n`; let schemaStr = '';
for (const key in types) { root = handlers.Query;
if (descriptions[key]?._description) res += `${setDescription(descriptions[key]._description)}\n`;
res += `type ${key}{\n`;
for (const k in types[key]) {
if (descriptions[key]?.[k]) res += ` ${setDescription(descriptions[key][k])}\n`;
res += ` ${k}: ${types[key][k]}\n`;
}
res += '}\n';
}
return res;
}
let schemaStr = buildSchemaStr();
let schema = graphql.buildSchema(schemaStr);
root = { ...handlers.Query, ...resolvers };
export function rebuild() { export function rebuild() {
try { try {
const str = buildSchemaStr(); const defs = [
schema = graphql.buildSchema(str); ...Object.keys(unions).map((i) => `union ${i} = ${unions[i]}`),
schemaStr = str; ...typeDefs,
root = { ...handlers.Query, ...resolvers }; ...Object.keys(types).map((key) => {
let def = '';
if (descriptions[key]?._description) def += `${setDescription(descriptions[key]._description)}\n`;
def += `type ${key}{\n`;
for (const k in types[key]) {
if (descriptions[key]?.[k]) def += ` ${setDescription(descriptions[key][k])}\n`;
def += ` ${k}: ${types[key][k]}\n`;
}
def += '}\n';
return def;
}),
];
schema = makeExecutableSchema({
typeDefs: defs,
resolvers,
});
schemaStr = defs.join('\n');
} catch (e) { } catch (e) {
console.error(e); console.error(e);
} }
@@ -85,6 +90,11 @@ bus.on('app/started', () => {
}); });
class ApiHandler extends Handler { class ApiHandler extends Handler {
async query(q: string, variables: any) {
// FIXME validation for fields like ObjectID doesn't work.
return graphql(schema, q, root, this, variables);
}
async get() { async get() {
const q = decodeURIComponent(this.ctx.request.querystring); const q = decodeURIComponent(this.ctx.request.querystring);
if (q === 'schema') { if (q === 'schema') {
@@ -92,15 +102,10 @@ class ApiHandler extends Handler {
this.response.body = { schema: schemaStr }; this.response.body = { schema: schemaStr };
} else if (q) { } else if (q) {
this.response.type = 'application/json'; this.response.type = 'application/json';
this.response.body = await graphql.graphql(schema, q, root, this); this.response.body = await this.query(q, {});
} else this.response.template = 'api.html'; } else this.response.template = 'api.html';
} }
async query(q: string, variables: any) {
// FIXME validation for fields like ObjectID doesn't work.
return graphql.graphql(schema, q, root, this, variables);
}
async post() { async post() {
this.response.type = 'application/json'; this.response.type = 'application/json';
this.response.body = await this.query(this.args.query, this.args.variables); this.response.body = await this.query(this.args.query, this.args.variables);
+1 -1
View File
@@ -167,7 +167,7 @@ class JudgeConnectionHandler extends ConnectionHandler {
} }
async message(msg) { async message(msg) {
if (msg.key !== 'ping') logger[['status', 'next'].includes(msg.key) ? 'debug' : 'info']('%o', msg); if (msg.key !== 'ping' && msg.key !== 'prio') logger[['status', 'next'].includes(msg.key) ? 'debug' : 'info']('%o', msg);
if (msg.key === 'next') await next(msg); if (msg.key === 'next') await next(msg);
else if (msg.key === 'end') { else if (msg.key === 'end') {
await end({ judger: this.user._id, ...msg }).catch((e) => logger.error(e)); await end({ judger: this.user._id, ...msg }).catch((e) => logger.error(e));
+1 -1
View File
@@ -76,7 +76,7 @@ registerResolver(
); );
registerResolver( registerResolver(
'Problem', 'manage', 'ProblemManage', 'Problem', 'manage', 'ProblemManage',
async (arg, ctx) => { (arg, ctx) => {
if (!ctx.user.own(ctx.pdoc, PERM.PERM_EDIT_PROBLEM_SELF)) ctx.checkPerm(PERM.PERM_EDIT_PROBLEM); if (!ctx.user.own(ctx.pdoc, PERM.PERM_EDIT_PROBLEM_SELF)) ctx.checkPerm(PERM.PERM_EDIT_PROBLEM);
return {}; return {};
}, },