Merge pull request #130 from thevahidal/67_protection_against_sql_injection
Protection against SQL injection
This commit is contained in:
@@ -1,4 +1,5 @@
|
||||
const db = require('../db/index');
|
||||
const { rowService } = require('../services');
|
||||
|
||||
const quotePrimaryKeys = (pks) => {
|
||||
const primaryKeys = pks.split(',');
|
||||
@@ -107,14 +108,22 @@ const listTableRows = async (req, res) => {
|
||||
}
|
||||
|
||||
let whereString = '';
|
||||
const whereStringValues = [];
|
||||
|
||||
if (_filters !== '') {
|
||||
whereString += ' WHERE ';
|
||||
whereString += filters
|
||||
.map((filter) =>
|
||||
filter.value !== null
|
||||
? `${tableName}.${filter.field} ${filter.operator} '${filter.value}'`
|
||||
: `${tableName}.${filter.field} ${filter.operator}`
|
||||
)
|
||||
.map((filter) => {
|
||||
let query;
|
||||
if (filter.value != null) {
|
||||
query = `${tableName}.${filter.field} ${filter.operator} ?`;
|
||||
whereStringValues.push(filter.value);
|
||||
} else {
|
||||
query = `${tableName}.${filter.field} ${filter.operator}`;
|
||||
}
|
||||
|
||||
return query;
|
||||
})
|
||||
.join(' AND ');
|
||||
params = `_filters=${_filters}&`;
|
||||
}
|
||||
@@ -261,13 +270,17 @@ const listTableRows = async (req, res) => {
|
||||
}
|
||||
}
|
||||
|
||||
// get paginated rows
|
||||
const query = `SELECT ${schemaString} FROM ${tableName} ${extendString} ${whereString} ${orderString} LIMIT ${limit} OFFSET ${
|
||||
limit * (page - 1)
|
||||
}`;
|
||||
|
||||
try {
|
||||
let data = db.prepare(query).all();
|
||||
let data = rowService.get({
|
||||
schemaString,
|
||||
tableName,
|
||||
extendString,
|
||||
whereString,
|
||||
orderString,
|
||||
limit,
|
||||
page: limit * (page - 1),
|
||||
whereStringValues,
|
||||
});
|
||||
|
||||
// parse json extended files
|
||||
if (_extend) {
|
||||
@@ -283,9 +296,11 @@ const listTableRows = async (req, res) => {
|
||||
}
|
||||
|
||||
// get total number of rows
|
||||
const total = db
|
||||
.prepare(`SELECT COUNT(*) as total FROM ${tableName} ${whereString}`)
|
||||
.get().total;
|
||||
const total = rowService.getCount({
|
||||
tableName,
|
||||
whereString,
|
||||
whereStringValues,
|
||||
});
|
||||
|
||||
const next =
|
||||
data.length === limit
|
||||
@@ -343,27 +358,8 @@ const insertRowInTable = async (req, res, next) => {
|
||||
Object.entries(queryFields).filter(([_, value]) => value !== null)
|
||||
);
|
||||
|
||||
const fieldsString = Object.keys(fields).join(", ");
|
||||
|
||||
// wrap text values in quotes
|
||||
const valuesString = Object.values(fields)
|
||||
.map((value) => {
|
||||
if (typeof value === "string") {
|
||||
return `'${value}'`;
|
||||
}
|
||||
return value;
|
||||
})
|
||||
.join(", ");
|
||||
|
||||
let values = `(${fieldsString}) VALUES (${valuesString})`;
|
||||
|
||||
if (valuesString === "") {
|
||||
values = "DEFAULT VALUES";
|
||||
}
|
||||
|
||||
const query = `INSERT INTO ${tableName} ${values}`;
|
||||
try {
|
||||
const data = db.prepare(query).run();
|
||||
const data = rowService.save({ tableName, fields });
|
||||
|
||||
/*
|
||||
#swagger.responses[201] = {
|
||||
@@ -374,15 +370,15 @@ const insertRowInTable = async (req, res, next) => {
|
||||
}
|
||||
*/
|
||||
res.status(201).json({
|
||||
message: "Row inserted",
|
||||
data
|
||||
message: 'Row inserted',
|
||||
data,
|
||||
});
|
||||
req.broadcast = {
|
||||
type: "INSERT",
|
||||
type: 'INSERT',
|
||||
data: {
|
||||
pk: data.lastInsertRowid,
|
||||
...fields
|
||||
}
|
||||
...fields,
|
||||
},
|
||||
};
|
||||
next();
|
||||
} catch (error) {
|
||||
@@ -396,7 +392,7 @@ const insertRowInTable = async (req, res, next) => {
|
||||
*/
|
||||
res.status(400).json({
|
||||
message: error.message,
|
||||
error: error
|
||||
error: error,
|
||||
});
|
||||
}
|
||||
};
|
||||
@@ -555,12 +551,14 @@ const getRowInTableByPK = async (req, res) => {
|
||||
});
|
||||
}
|
||||
|
||||
const query = `SELECT ${schemaString} FROM ${tableName} ${extendString} WHERE ${tableName}.${lookupField} in (${quotePrimaryKeys(
|
||||
pks
|
||||
)})`;
|
||||
|
||||
try {
|
||||
let data = db.prepare(query).all();
|
||||
let data = rowService.getById({
|
||||
schemaString,
|
||||
tableName,
|
||||
extendString,
|
||||
lookupField,
|
||||
pks,
|
||||
});
|
||||
|
||||
// parse json extended files
|
||||
if (_extend) {
|
||||
@@ -665,12 +663,13 @@ const updateRowInTableByPK = async (req, res, next) => {
|
||||
});
|
||||
}
|
||||
|
||||
const query = `UPDATE ${tableName} SET ${fieldsString} WHERE ${lookupField} in (${quotePrimaryKeys(
|
||||
pks
|
||||
)})`;
|
||||
|
||||
try {
|
||||
const data = db.prepare(query).run();
|
||||
const data = rowService.update({
|
||||
tableName,
|
||||
fieldsString,
|
||||
lookupField,
|
||||
pks,
|
||||
});
|
||||
|
||||
res.json({
|
||||
message: 'Row updated',
|
||||
@@ -738,12 +737,8 @@ const deleteRowInTableByPK = async (req, res, next) => {
|
||||
}
|
||||
}
|
||||
|
||||
const query = `DELETE FROM ${tableName} WHERE ${lookupField} in (${quotePrimaryKeys(
|
||||
pks
|
||||
)})`;
|
||||
|
||||
try {
|
||||
const data = db.prepare(query).run();
|
||||
const data = rowService.delete({ tableName, lookupField, pks });
|
||||
|
||||
if (data.changes === 0) {
|
||||
res.status(404).json({
|
||||
|
||||
6
core/src/services/index.js
Normal file
6
core/src/services/index.js
Normal file
@@ -0,0 +1,6 @@
|
||||
const db = require('../db');
|
||||
|
||||
const rowService = require('./rowService')(db);
|
||||
const tableService = require('./tableService')(db);
|
||||
|
||||
module.exports = { rowService, tableService };
|
||||
69
core/src/services/rowService.js
Normal file
69
core/src/services/rowService.js
Normal file
@@ -0,0 +1,69 @@
|
||||
module.exports = (db) => {
|
||||
return {
|
||||
get(data) {
|
||||
const query = `SELECT ${data.schemaString} FROM ${data.tableName} ${data.extendString} ${data.whereString} ${data.orderString} LIMIT ? OFFSET ?`;
|
||||
const statement = db.prepare(query);
|
||||
const result = statement.all(
|
||||
...data.whereStringValues,
|
||||
data.limit,
|
||||
data.page
|
||||
);
|
||||
return result;
|
||||
},
|
||||
|
||||
getById(data) {
|
||||
const pks = data.pks.split(',');
|
||||
const placeholders = pks.map((pk) => '?').join(',');
|
||||
const query = `SELECT ${data.schemaString} FROM ${data.tableName} ${data.extendString} WHERE ${data.tableName}.${data.lookupField} in (${placeholders})`;
|
||||
const statement = db.prepare(query);
|
||||
const result = statement.all(...pks);
|
||||
return result;
|
||||
},
|
||||
|
||||
getCount(data) {
|
||||
const query = `SELECT COUNT(*) as total FROM ${data.tableName} ${data.whereString}`;
|
||||
const statement = db.prepare(query);
|
||||
const result = statement.get(...data.whereStringValues).total;
|
||||
return result;
|
||||
},
|
||||
|
||||
save(data) {
|
||||
// wrap text values in quotes
|
||||
const fieldsString = Object.keys(data.fields).join(', ');
|
||||
|
||||
// wrap text values in quotes
|
||||
const valuesString = Object.values(data.fields).map((value) => value);
|
||||
const placeholders = Object.values(data.fields)
|
||||
.map(() => '?')
|
||||
.join(',');
|
||||
|
||||
let values = `(${fieldsString}) VALUES (${placeholders})`;
|
||||
if (valuesString === '') {
|
||||
values = 'DEFAULT VALUES';
|
||||
}
|
||||
|
||||
const query = `INSERT INTO ${data.tableName} ${values}`;
|
||||
const statement = db.prepare(query);
|
||||
const result = statement.run(...valuesString);
|
||||
return result;
|
||||
},
|
||||
|
||||
update(data) {
|
||||
const pks = data.pks.split(',');
|
||||
const placeholders = pks.map((pk) => '?').join(',');
|
||||
const query = `UPDATE ${data.tableName} SET ${data.fieldsString} WHERE ${data.lookupField} in (${placeholders})`;
|
||||
const statement = db.prepare(query);
|
||||
const result = statement.run(...pks);
|
||||
return result;
|
||||
},
|
||||
|
||||
delete(data) {
|
||||
const pks = data.pks.split(',');
|
||||
const placeholders = pks.map((pk) => '?').join(',');
|
||||
const query = `DELETE FROM ${data.tableName} WHERE ${data.lookupField} in (${placeholders})`;
|
||||
const statement = db.prepare(query);
|
||||
const result = statement.run(...pks);
|
||||
return result;
|
||||
},
|
||||
};
|
||||
};
|
||||
5
core/src/services/tableService.js
Normal file
5
core/src/services/tableService.js
Normal file
@@ -0,0 +1,5 @@
|
||||
module.exports = (db) => {
|
||||
return {
|
||||
get() {},
|
||||
};
|
||||
};
|
||||
Reference in New Issue
Block a user