Skip to content

Commit

Permalink
protect against unsafe sql.fragment usage (#602)
Browse files Browse the repository at this point in the history
* in typescript: protects using types
* in javascript: protects by checking for strings.raw

Ref: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Template_literals#raw_strings

Closes #589

Co-authored-by: alxndrsn <alxndrsn>
  • Loading branch information
alxndrsn authored May 13, 2024
1 parent 53c3258 commit a2a0ac2
Show file tree
Hide file tree
Showing 2 changed files with 19 additions and 3 deletions.
10 changes: 10 additions & 0 deletions packages/sql-tag/src/factories/createSqlTag.test/sql.test.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { FragmentToken } from '../../tokens';
import { createSqlTag } from '../createSqlTag';
import { InvalidInputError } from '@slonik/errors';
import anyTest, { type TestFn } from 'ava';
import { ROARR } from 'roarr';

Expand All @@ -17,6 +18,15 @@ test.beforeEach((t) => {
};
});

test('throws error if called as a function', (t) => {
const error = t.throws(() => {
// @ts-expect-error - intentional
sql.fragment([`SELECT 1`]);
});

t.true(error instanceof InvalidInputError);
});

test('creates an object describing a query', (t) => {
const query = sql.fragment`SELECT 1`;

Expand Down
12 changes: 9 additions & 3 deletions packages/sql-tag/src/factories/createSqlTag.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,9 +32,15 @@ const log = Logger.child({
});

const createFragment = (
parts: readonly string[],
parts: TemplateStringsArray,
values: readonly ValueExpression[],
) => {
if (!Array.isArray(parts.raw) || !Object.isFrozen(parts.raw)) {
throw new InvalidInputError(
'Function must be called as a template literal.',
);
}

let rawSql = '';

const parameterValues: PrimitiveValueExpression[] = [];
Expand Down Expand Up @@ -181,7 +187,7 @@ export const createSqlTag = <
},
type: (parser) => {
return (
parts: readonly string[],
parts: TemplateStringsArray,
...args: readonly ValueExpression[]
) => {
return Object.freeze({
Expand All @@ -199,7 +205,7 @@ export const createSqlTag = <
}

return (
parts: readonly string[],
parts: TemplateStringsArray,
...args: readonly ValueExpression[]
) => {
return Object.freeze({
Expand Down

0 comments on commit a2a0ac2

Please sign in to comment.