Switching from .toString to .toSQL().toNative() for sql injection protection.

This commit is contained in:
mike12345567 2021-06-03 17:45:19 +01:00
parent 20d7d36a16
commit 738b5af4c0
2 changed files with 60 additions and 27 deletions

View File

@ -47,7 +47,7 @@ function addFilters(query, filters) {
function buildCreate(knex, json) { function buildCreate(knex, json) {
const { endpoint, body } = json const { endpoint, body } = json
let query = knex(endpoint.entityId) let query = knex(endpoint.entityId)
return query.insert(body).toString() return query.insert(body)
} }
function buildRead(knex, json, limit) { function buildRead(knex, json, limit) {
@ -78,21 +78,21 @@ function buildRead(knex, json, limit) {
} else { } else {
query.limit(limit) query.limit(limit)
} }
return query.toString() return query
} }
function buildUpdate(knex, json) { function buildUpdate(knex, json) {
const { endpoint, body, filters } = json const { endpoint, body, filters } = json
let query = knex(endpoint.entityId) let query = knex(endpoint.entityId)
query = addFilters(query, filters) query = addFilters(query, filters)
return query.update(body).toString() return query.update(body)
} }
function buildDelete(knex, json) { function buildDelete(knex, json) {
const { endpoint, filters } = json const { endpoint, filters } = json
let query = knex(endpoint.entityId) let query = knex(endpoint.entityId)
query = addFilters(query, filters) query = addFilters(query, filters)
return query.delete().toString() return query.delete()
} }
class SqlQueryBuilder { class SqlQueryBuilder {
@ -102,22 +102,28 @@ class SqlQueryBuilder {
this._limit = limit this._limit = limit
} }
query(json) { _query(json) {
const { endpoint } = json const { endpoint } = json
const knex = require("knex")({ client: this._client }) const knex = require("knex")({ client: this._client })
const operation = endpoint.operation const operation = endpoint.operation
let query
switch (operation) { switch (operation) {
case Operation.CREATE: case Operation.CREATE:
return buildCreate(knex, json) query = buildCreate(knex, json)
break
case Operation.READ: case Operation.READ:
return buildRead(knex, json, this._limit) query = buildRead(knex, json, this._limit)
break
case Operation.UPDATE: case Operation.UPDATE:
return buildUpdate(knex, json) query = buildUpdate(knex, json)
break
case Operation.DELETE: case Operation.DELETE:
return buildDelete(knex, json) query = buildDelete(knex, json)
break
default: default:
throw `Operation ${operation} type is not supported by SQL query builder` throw `Operation ${operation} type is not supported by SQL query builder`
} }
return query.toSQL().toNative()
} }
} }

View File

@ -54,30 +54,39 @@ describe("SQL query builder", () => {
}) })
it("should test a basic read", () => { it("should test a basic read", () => {
const query = sql.query(generateReadJson()) const query = sql._query(generateReadJson())
expect(query).toEqual(`select * from "${TABLE_NAME}" limit ${limit}`) expect(query).toEqual({
bindings: [limit],
sql: `select * from "${TABLE_NAME}" limit $1`
})
}) })
it("should test a read with specific columns", () => { it("should test a read with specific columns", () => {
const query = sql.query(generateReadJson({ const query = sql._query(generateReadJson({
fields: ["name", "age"] fields: ["name", "age"]
})) }))
expect(query).toEqual(`select "name", "age" from "${TABLE_NAME}" limit ${limit}`) expect(query).toEqual({
bindings: [limit],
sql: `select "name", "age" from "${TABLE_NAME}" limit $1`
})
}) })
it("should test a where string starts with read", () => { it("should test a where string starts with read", () => {
const query = sql.query(generateReadJson({ const query = sql._query(generateReadJson({
filters: { filters: {
string: { string: {
name: "John", name: "John",
} }
} }
})) }))
expect(query).toEqual(`select * from "${TABLE_NAME}" where "name" like 'John%' limit ${limit}`) expect(query).toEqual({
bindings: ["John%", limit],
sql: `select * from "${TABLE_NAME}" where "name" like $1 limit $2`
})
}) })
it("should test a where range read", () => { it("should test a where range read", () => {
const query = sql.query(generateReadJson({ const query = sql._query(generateReadJson({
filters: { filters: {
range: { range: {
age: { age: {
@ -87,44 +96,62 @@ describe("SQL query builder", () => {
} }
} }
})) }))
expect(query).toEqual(`select * from "${TABLE_NAME}" where "age" between 2 and 10 limit ${limit}`) expect(query).toEqual({
bindings: [2, 10, limit],
sql: `select * from "${TABLE_NAME}" where "age" between $1 and $2 limit $3`
})
}) })
it("should test an create statement", () => { it("should test an create statement", () => {
const query = sql.query(generateCreateJson(TABLE_NAME, { const query = sql._query(generateCreateJson(TABLE_NAME, {
name: "Michael", name: "Michael",
age: 45, age: 45,
})) }))
expect(query).toEqual(`insert into "${TABLE_NAME}" ("age", "name") values (45, 'Michael')`) expect(query).toEqual({
bindings: [45, "Michael"],
sql: `insert into "${TABLE_NAME}" ("age", "name") values ($1, $2)`
})
}) })
it("should test an update statement", () => { it("should test an update statement", () => {
const query = sql.query(generateUpdateJson(TABLE_NAME, { const query = sql._query(generateUpdateJson(TABLE_NAME, {
name: "John" name: "John"
}, { }, {
equal: { equal: {
id: 1001, id: 1001,
} }
})) }))
expect(query).toEqual(`update "${TABLE_NAME}" set "name" = 'John' where "id" = 1001`) expect(query).toEqual({
bindings: ["John", 1001],
sql: `update "${TABLE_NAME}" set "name" = $1 where "id" = $2`
})
}) })
it("should test a delete statement", () => { it("should test a delete statement", () => {
const query = sql.query(generateDeleteJson(TABLE_NAME, { const query = sql._query(generateDeleteJson(TABLE_NAME, {
equal: { equal: {
id: 1001, id: 1001,
} }
})) }))
expect(query).toEqual(`delete from "${TABLE_NAME}" where "id" = 1001`) expect(query).toEqual({
bindings: [1001],
sql: `delete from "${TABLE_NAME}" where "id" = $1`
})
}) })
it("should work with MS-SQL", () => { it("should work with MS-SQL", () => {
const query = new Sql("mssql", 10).query(generateReadJson()) const query = new Sql("mssql", 10)._query(generateReadJson())
expect(query).toEqual(`select top (10) * from [${TABLE_NAME}]`) expect(query).toEqual({
bindings: [10],
sql: `select top (@p0) * from [${TABLE_NAME}]`
})
}) })
it("should work with mySQL", () => { it("should work with mySQL", () => {
const query = new Sql("mysql", 10).query(generateReadJson()) const query = new Sql("mysql", 10)._query(generateReadJson())
expect(query).toEqual(`select * from \`${TABLE_NAME}\` limit 10`) expect(query).toEqual({
bindings: [10],
sql: `select * from \`${TABLE_NAME}\` limit ?`
})
}) })
}) })