added fix for sql injection in custom query constructor for history

This commit is contained in:
CyferShepard
2025-01-27 19:21:40 +02:00
parent 0d1d0a597b
commit f9f061057a
2 changed files with 62 additions and 21 deletions

View File

@@ -1,4 +1,5 @@
const { pool } = require("../db.js");
const pgp = require("pg-promise")();
function wrapField(field) {
if (field === "*") {
@@ -43,9 +44,9 @@ function buildWhereClause(conditions) {
const { column, field, operator, value, type } = condition;
const conjunction = index === 0 ? "" : type ? type.toUpperCase() : "AND";
if (operator == "LIKE") {
return `${conjunction} ${column ? wrapField(column) : field} ${operator} '%${value}%'`;
return `${conjunction} ${column ? wrapField(column) : field} ${operator} ${value}`;
}
return `${conjunction} ${column ? wrapField(column) : field} ${operator} '${value}'`;
return `${conjunction} ${column ? wrapField(column) : field} ${operator} ${value}`;
}
return "";
})
@@ -67,7 +68,7 @@ function buildCTE(cte) {
.map((condition, index) => {
const conjunction = index === 0 ? "" : condition.type ? condition.type.toUpperCase() : "AND";
return `${conjunction} ${wrapField(condition.first)} ${condition.operator} ${
condition.second ? wrapField(condition.second) : `'${condition.value}'`
condition.second ? wrapField(condition.second) : `${condition.value}`
}`;
})
.join(" ");
@@ -102,6 +103,7 @@ async function query({
alias,
joins = [],
where = [],
values = [],
order_by = "Id",
sort_order = "desc",
pageNumber = 1,
@@ -119,7 +121,7 @@ async function query({
.map((condition, index) => {
const conjunction = index === 0 ? "" : condition.type ? condition.type.toUpperCase() : "AND";
return `${conjunction} ${wrapField(condition.first)} ${condition.operator} ${
condition.second ? wrapField(condition.second) : `'${condition.value}'`
condition.second ? wrapField(condition.second) : `${condition.value}`
}`;
})
.join(" ");
@@ -140,10 +142,10 @@ async function query({
query += ` LIMIT ${pageSize} OFFSET ${(pageNumber - 1) * pageSize}`;
// Execute the query
const result = await client.query(query);
const result = await client.query(query, values);
// Count total rows
const countResult = await client.query(countQuery);
const countResult = await client.query(countQuery, values);
const totalRows = parseInt(countResult.rows[0].count, 10);
// Return the structured response

View File

@@ -152,9 +152,11 @@ function buildFilterList(query, filtersArray) {
query.where.push({
column: column,
operator: ">=",
value: filter.min,
value: `$${query.values.length + 1}`,
});
query.values.push(filter.min);
if (applyToCTE) {
if (query.cte) {
if (!query.cte.where) {
@@ -163,8 +165,10 @@ function buildFilterList(query, filtersArray) {
query.cte.where.push({
column: column,
operator: ">=",
value: filter.min,
value: `$${query.values.length + 1}`,
});
query.values.push(filter.min);
}
}
}
@@ -173,9 +177,11 @@ function buildFilterList(query, filtersArray) {
query.where.push({
column: column,
operator: "<=",
value: filter.max,
value: `$${query.values.length + 1}`,
});
query.values.push(filter.max);
if (applyToCTE) {
if (query.cte) {
if (!query.cte.where) {
@@ -184,8 +190,10 @@ function buildFilterList(query, filtersArray) {
query.cte.where.push({
column: column,
operator: "<=",
value: filter.max,
value: `$${query.values.length + 1}`,
});
query.values.push(filter.max);
}
}
}
@@ -193,8 +201,11 @@ function buildFilterList(query, filtersArray) {
if (filter.value) {
const whereClause = {
operator: "LIKE",
value: filter.value.toLowerCase(),
value: `$${query.values.length + 1}`,
};
query.values.push(`%${filter.value.toLowerCase()}%`);
if (isColumn) {
whereClause.column = column;
} else {
@@ -207,7 +218,10 @@ function buildFilterList(query, filtersArray) {
if (!query.cte.where) {
query.cte.where = [];
}
whereClause.value = `$${query.values.length + 1}`;
query.cte.where.push(whereClause);
query.values.push(`%${filter.value.toLowerCase()}%`);
}
}
}
@@ -1227,6 +1241,8 @@ router.get("/getHistory", async (req, res) => {
const sortField = groupedSortMap.find((item) => item.field === sort)?.column || "a.ActivityDateInserted";
const values = [];
try {
const cte = {
cteAlias: "activity_results",
@@ -1291,11 +1307,15 @@ router.get("/getHistory", async (req, res) => {
END
)`,
operator: "LIKE",
value: `${search.toLowerCase()}`,
value: `$${values.length + 1}`,
},
];
values.push(`%${search.toLowerCase()}%`);
}
query.values = values;
buildFilterList(query, filtersArray);
const result = await dbHelper.query(query);
@@ -1378,6 +1398,7 @@ router.post("/getLibraryHistory", async (req, res) => {
}
const sortField = groupedSortMap.find((item) => item.field === sort)?.column || "a.ActivityDateInserted";
const values = [];
const cte = {
cteAlias: "activity_results",
@@ -1420,7 +1441,7 @@ router.post("/getLibraryHistory", async (req, res) => {
alias: "i",
conditions: [
{ first: "i.Id", operator: "=", second: "a.NowPlayingItemId" },
{ first: "i.ParentId", operator: "=", value: libraryid },
{ first: "i.ParentId", operator: "=", value: `$${values.length + 1}` },
],
},
{
@@ -1441,6 +1462,8 @@ router.post("/getLibraryHistory", async (req, res) => {
pageSize: size,
};
values.push(libraryid);
if (search && search.length > 0) {
query.where = [
{
@@ -1451,11 +1474,15 @@ router.post("/getLibraryHistory", async (req, res) => {
END
)`,
operator: "LIKE",
value: `${search.toLowerCase()}`,
value: `$${values.length + 1}`,
},
];
values.push(`%${search.toLowerCase()}%`);
}
query.values = values;
buildFilterList(query, filtersArray);
const result = await dbHelper.query(query);
@@ -1541,7 +1568,7 @@ router.post("/getItemHistory", async (req, res) => {
}
const sortField = unGroupedSortMap.find((item) => item.field === sort)?.column || "a.ActivityDateInserted";
const values = [];
const query = {
select: [
"a.*",
@@ -1559,9 +1586,9 @@ router.post("/getItemHistory", async (req, res) => {
alias: "a",
where: [
[
{ column: "a.EpisodeId", operator: "=", value: itemid },
{ column: "a.SeasonId", operator: "=", value: itemid, type: "or" },
{ column: "a.NowPlayingItemId", operator: "=", value: itemid, type: "or" },
{ column: "a.EpisodeId", operator: "=", value: `$${values.length + 1}` },
{ column: "a.SeasonId", operator: "=", value: `$${values.length + 2}`, type: "or" },
{ column: "a.NowPlayingItemId", operator: "=", value: `$${values.length + 3}`, type: "or" },
],
],
order_by: sortField,
@@ -1570,6 +1597,10 @@ router.post("/getItemHistory", async (req, res) => {
pageSize: size,
};
values.push(itemid);
values.push(itemid);
values.push(itemid);
if (search && search.length > 0) {
query.where = [
{
@@ -1580,11 +1611,13 @@ router.post("/getItemHistory", async (req, res) => {
END
)`,
operator: "LIKE",
value: `${search.toLowerCase()}`,
value: `$${values.length + 1}`,
},
];
values.push(`%${search.toLowerCase()}%`);
}
query.values = values;
buildFilterList(query, filtersArray);
const result = await dbHelper.query(query);
@@ -1667,6 +1700,7 @@ router.post("/getUserHistory", async (req, res) => {
const sortField = unGroupedSortMap.find((item) => item.field === sort)?.column || "a.ActivityDateInserted";
const values = [];
const query = {
select: [
"a.*",
@@ -1682,13 +1716,15 @@ router.post("/getUserHistory", async (req, res) => {
],
table: "jf_playback_activity_with_metadata",
alias: "a",
where: [[{ column: "a.UserId", operator: "=", value: userid }]],
where: [[{ column: "a.UserId", operator: "=", value: `$${values.length + 1}` }]],
order_by: sortField,
sort_order: desc ? "desc" : "asc",
pageNumber: page,
pageSize: size,
};
values.push(userid);
if (search && search.length > 0) {
query.where = [
{
@@ -1699,11 +1735,14 @@ router.post("/getUserHistory", async (req, res) => {
END
)`,
operator: "LIKE",
value: `${search.toLowerCase()}`,
value: `$${values.length + 1}`,
},
];
values.push(`%${search.toLowerCase()}%`);
}
query.values = values;
buildFilterList(query, filtersArray);
const result = await dbHelper.query(query);