[IMP] web: add some validation in orm service

Before this commit, orm service calls had no validation whatsoever,
which means that the requests would fail serverside, then display a
python traceback. This makes it harder for developers to find the cause
of the issue.  Also, it is easy to perfom some really basic validation
anyway.
This commit is contained in:
Géry Debongnie
2021-07-05 13:57:54 +00:00
parent 3e4c37ec6b
commit 3e8ee3aedc
2 changed files with 56 additions and 3 deletions
+36
View File
@@ -66,6 +66,27 @@ export const Commands = {
},
};
function validateModel(value) {
if (typeof value !== "string" || value.length === 0) {
throw new Error(`Invalid model name: ${value}`);
}
}
function validatePrimitiveList(name, type, value) {
if (!Array.isArray(value) || value.some((val) => typeof val !== type)) {
throw new Error(`Invalid ${name} list: ${value}`);
}
}
function validateObject(name, obj) {
if (typeof obj !== "object" || obj === null || Array.isArray(obj)) {
throw new Error(`${name} should be an object`);
}
}
function validateArray(name, array) {
if (!Array.isArray(array)) {
throw new Error(`${name} should be an array`);
}
}
class ORM {
constructor(rpc, user) {
this.rpc = rpc;
@@ -78,6 +99,7 @@ class ORM {
}
call(model, method, args = [], kwargs = {}) {
validateModel(model);
let url = `/web/dataset/call_kw/${model}/${method}`;
const fullContext = Object.assign({}, this.user.context, kwargs.context || {});
const fullKwargs = Object.assign({}, kwargs, { context: fullContext });
@@ -91,14 +113,20 @@ class ORM {
}
create(model, state, ctx) {
validateObject("state", state);
return this.call(model, "create", [state], { context: ctx });
}
read(model, ids, fields, ctx) {
validatePrimitiveList("ids", "number", ids);
validatePrimitiveList("fields", "string", fields);
return this.call(model, "read", [ids, fields], { context: ctx });
}
readGroup(model, domain, fields, groupby, options = {}, ctx = {}) {
validatePrimitiveList("fields", "string", fields);
validatePrimitiveList("groupby", "string", groupby);
validateArray("domain", domain);
const kwargs = {
domain,
groupby,
@@ -110,6 +138,7 @@ class ORM {
}
search(model, domain, options = {}, ctx = {}) {
validateArray("domain", domain);
const kwargs = {
context: ctx,
};
@@ -118,22 +147,29 @@ class ORM {
}
searchRead(model, domain, fields, options = {}, ctx = {}) {
validateArray("domain", domain);
validatePrimitiveList("fields", "string", fields);
const kwargs = { context: ctx, domain, fields };
assignOptions(kwargs, options, ["offset", "limit", "order"]);
return this.call(model, "search_read", [], kwargs);
}
unlink(model, ids, ctx) {
validatePrimitiveList("ids", "number", ids);
return this.call(model, "unlink", [ids], { context: ctx });
}
webSearchRead(model, domain, fields, options = {}, ctx = {}) {
validateArray("domain", domain);
validatePrimitiveList("fields", "string", fields);
const kwargs = { context: ctx, domain, fields };
assignOptions(kwargs, options, ["offset", "limit", "order"]);
return this.call(model, "web_search_read", [], kwargs);
}
write(model, ids, data, ctx) {
validatePrimitiveList("ids", "number", ids);
validateObject("data", data);
return this.call(model, "write", [ids, data], { context: ctx });
}
}
@@ -261,9 +261,9 @@ QUnit.test("silent mode", async (assert) => {
orm.call("my_model", "my_method");
orm.silent.call("my_model", "my_method");
orm.call("my_model", "my_method");
orm.read("my_model");
orm.silent.read("my_model");
orm.read("my_model");
orm.read("my_model", [], []);
orm.silent.read("my_model", [], []);
orm.read("my_model", [], []);
assert.verifySteps([
"/web/dataset/call_kw/my_model/my_method",
@@ -274,3 +274,20 @@ QUnit.test("silent mode", async (assert) => {
"/web/dataset/call_kw/my_model/read",
]);
});
QUnit.test("validate some obviously wrong calls", async (assert) => {
assert.expect(2);
const [query, rpc] = makeFakeRPC();
serviceRegistry.add("rpc", rpc);
const env = await makeTestEnv();
try {
await env.services.orm.read(false, [3], ["id", "descr"]);
} catch (error) {
assert.strictEqual(error.message, "Invalid model name: false");
}
try {
await env.services.orm.read("res.partner", false, ["id", "descr"]);
} catch (error) {
assert.strictEqual(error.message, "Invalid ids list: false");
}
});