diff --git a/packages/server/src/api/routes/tests/search.spec.ts b/packages/server/src/api/routes/tests/search.spec.ts index 2f3dbe91f6..d69f3f2c38 100644 --- a/packages/server/src/api/routes/tests/search.spec.ts +++ b/packages/server/src/api/routes/tests/search.spec.ts @@ -7,6 +7,7 @@ import { import { context, db as dbCore, + docIds, features, MAX_VALID_DATE, MIN_VALID_DATE, @@ -130,14 +131,14 @@ describe.each([ } }) - async function createTable(schema: TableSchema) { + async function createTable(schema?: TableSchema) { const table = await config.api.table.save( tableForDatasource(datasource, { schema }) ) return table._id! } - async function createView(tableId: string, schema: ViewV2Schema) { + async function createView(tableId: string, schema?: ViewV2Schema) { const view = await config.api.viewV2.create({ tableId: tableId, name: generator.guid(), @@ -154,22 +155,34 @@ describe.each([ rows = await config.api.row.fetch(tableOrViewId) } + async function getTable(tableOrViewId: string): Promise { + if (docIds.isViewId(tableOrViewId)) { + const view = await config.api.viewV2.get(tableOrViewId) + return await config.api.table.get(view.tableId) + } else { + return await config.api.table.get(tableOrViewId) + } + } + describe.each([ ["table", createTable], [ "view", - async (schema: TableSchema) => { + async (schema?: TableSchema) => { const tableId = await createTable(schema) const viewId = await createView( tableId, - Object.keys(schema).reduce((viewSchema, fieldName) => { - const field = schema[fieldName] - viewSchema[fieldName] = { - visible: field.visible ?? true, - readonly: false, - } - return viewSchema - }, {}) + Object.keys(schema || {}).reduce( + (viewSchema, fieldName) => { + const field = schema![fieldName] + viewSchema[fieldName] = { + visible: field.visible ?? true, + readonly: false, + } + return viewSchema + }, + {} + ) ) return viewId }, @@ -3476,36 +3489,45 @@ describe.each([ isSql && describe("SQL injection", () => { const badStrings = [ - "1; DROP TABLE test;", - "1; DELETE FROM test;", - "1; UPDATE test SET name = 'foo';", - "1; INSERT INTO test (name) VALUES ('foo');", + "1; DROP TABLE %table_name%;", + "1; DELETE FROM %table_name%;", + "1; UPDATE %table_name% SET name = 'foo';", + "1; INSERT INTO %table_name% (name) VALUES ('foo');", "' OR '1'='1' --", - "'; DROP TABLE users; --", + "'; DROP TABLE %table_name%; --", "' OR 1=1 --", "' UNION SELECT null, null, null; --", - "' AND (SELECT COUNT(*) FROM users) > 0 --", + "' AND (SELECT COUNT(*) FROM %table_name%) > 0 --", "\"; EXEC xp_cmdshell('dir'); --", "\"' OR 'a'='a", "OR 1=1;", "'; SHUTDOWN --", ] - describe.each(badStrings)("bad string: %s", badString => { + describe.each(badStrings)("bad string: %s", badStringTemplate => { // The SQL that knex generates when you try to use a double quote in a // field name is always invalid and never works, so we skip it for these // tests. - const skipFieldNameCheck = isOracle && badString.includes('"') + const skipFieldNameCheck = isOracle && badStringTemplate.includes('"') !skipFieldNameCheck && it("should not allow SQL injection as a field name", async () => { - const tableOrViewId = await createTableOrView({ - [badString]: { - name: badString, - type: FieldType.STRING, + const tableOrViewId = await createTableOrView() + const table = await getTable(tableOrViewId) + const badString = badStringTemplate.replace( + /%table_name%/g, + table.name + ) + + await config.api.table.save({ + ...table, + schema: { + [badString]: { name: badString, type: FieldType.STRING }, }, }) + expect(await client!.schema.hasTable(table.name)).toBeTrue() + await config.api.row.save(tableOrViewId, { [badString]: "foo" }) const { rows } = await config.api.row.search( @@ -3515,6 +3537,7 @@ describe.each([ ) expect(rows).toHaveLength(1) + expect(await client!.schema.hasTable(table.name)).toBeTrue() }) it("should not allow SQL injection as a field value", async () => { @@ -3524,6 +3547,13 @@ describe.each([ type: FieldType.STRING, }, }) + const table = await getTable(tableOrViewId) + const badString = badStringTemplate.replace( + /%table_name%/g, + table.name + ) + + expect(await client!.schema.hasTable(table.name)).toBeTrue() await config.api.row.save(tableOrViewId, { foo: "foo" }) @@ -3534,6 +3564,7 @@ describe.each([ ) expect(rows).toBeEmpty() + expect(await client!.schema.hasTable(table.name)).toBeTrue() }) }) })