UNPKG

@nuxt/content

Version:

Write your content inside your Nuxt app

92 lines (91 loc) 2.85 kB
const SQL_COMMANDS = /SELECT|INSERT|UPDATE|DELETE|DROP|ALTER|\$/i; const SQL_COUNT_REGEX = /COUNT\((DISTINCT )?([a-z_]\w+|\*)\)/i; const SQL_SELECT_REGEX = /^SELECT (.*) FROM (\w+)( WHERE .*)? ORDER BY (["\w,\s]+) (ASC|DESC)( LIMIT \d+)?( OFFSET \d+)?$/; export function assertSafeQuery(sql, collection) { if (!sql) { throw new Error("Invalid query"); } const cleanedupQuery = cleanupQuery(sql); if (cleanedupQuery !== sql) { throw new Error("Invalid query"); } const match = sql.match(SQL_SELECT_REGEX); if (!match) { throw new Error("Invalid query"); } const [_, select, from, where, orderBy, order, limit, offset] = match; const columns = select.trim().split(", "); if (columns.length === 1) { if (columns[0] !== "*" && !columns[0].match(SQL_COUNT_REGEX) && !columns[0].match(/^"[a-z_]\w+"$/i)) { throw new Error("Invalid query"); } } else if (!columns.every((column) => column.match(/^"[a-z_]\w+"$/i))) { throw new Error("Invalid query"); } if (from !== `_content_${collection}`) { throw new Error("Invalid query"); } if (where) { if (!where.startsWith(" WHERE (") || !where.endsWith(")")) { throw new Error("Invalid query"); } const noString = cleanupQuery(where, { removeString: true }); if (noString.match(SQL_COMMANDS)) { throw new Error("Invalid query"); } } const _order = (orderBy + " " + order).split(", "); if (!_order.every((column) => column.match(/^("[a-zA-Z_]+"|[a-zA-Z_]+) (ASC|DESC)$/))) { throw new Error("Invalid query"); } if (limit !== void 0 && !limit.match(/^ LIMIT \d+$/)) { throw new Error("Invalid query"); } if (offset !== void 0 && !offset.match(/^ OFFSET \d+$/)) { throw new Error("Invalid query"); } return true; } function cleanupQuery(query, options = { removeString: false }) { let inString = false; let stringFence = ""; let result = ""; for (let i = 0; i < query.length; i++) { const char = query[i]; const prevChar = query[i - 1]; const nextChar = query[i + 1]; if (char === "'" || char === '"') { if (!options?.removeString) { result += char; continue; } if (inString) { if (char !== stringFence || nextChar === stringFence || prevChar === stringFence) { continue; } inString = false; stringFence = ""; continue; } else { inString = true; stringFence = char; continue; } } if (!inString) { if (char === "-" && nextChar === "-") { return result; } if (char === "/" && nextChar === "*") { i += 2; while (i < query.length && !(query[i] === "*" && query[i + 1] === "/")) { i += 1; } i += 2; continue; } result += char; } } return result; }