Skip to content

Commit

Permalink
feat(client): throw when executeRaw is used with Alter and parameters (
Browse files Browse the repository at this point in the history
  • Loading branch information
williamluke4 committed Dec 30, 2020
1 parent 337b901 commit 650cfcc
Show file tree
Hide file tree
Showing 3 changed files with 111 additions and 2 deletions.
@@ -0,0 +1,13 @@
datasource db {
provider = "postgresql"
url = env("TEST_POSTGRES_URI")
}

generator client {
provider = "prisma-client-js"
previewFeatures = ["nativeTypes"]
}

model A {
id String @id @default(uuid())
}
@@ -0,0 +1,69 @@
import { getTestClient } from '../../../../utils/getTestClient'
import sql from 'sql-template-tag'

let prisma

beforeAll(async () => {
const PrismaClient = await getTestClient()
prisma = new PrismaClient()
})

afterAll(() => {
prisma.$disconnect()
})

test('executeRaw-alter-postgres', async () => {
const password = 'prisma'
// Should Throw
try {
await prisma.$executeRaw`ALTER USER prisma WITH PASSWORD '${password}'`
} catch (err) {
//isReadonlyArray
expect(err).toMatchInlineSnapshot(`
Running ALTER using prisma.$executeRaw\`<SQL>\` is not supported
Using the example below you can still execute your query with Prisma, but please note that it is vulnerable to SQL injection attacks and requires you to take care of input sanitization.
Example:
await prisma.$executeRaw(\`ALTER USER prisma WITH PASSWORD '\${password}'\`)
More Information: https://pris.ly/d/execute-raw
`)
}
try {
await prisma.$executeRaw(`ALTER USER prisma WITH PASSWORD $1`, password)
} catch (err) {
// String
expect(err).toMatchInlineSnapshot(`
Running ALTER using prisma.$executeRaw(<SQL>, [...values]) is not supported
Using the example below you can still execute your query with Prisma, but please note that it is vulnerable to SQL injection attacks and requires you to take care of input sanitization.
Example:
await prisma.$executeRaw(\`ALTER USER prisma WITH PASSWORD '\${password}'\`)
More Information: https://pris.ly/d/execute-raw
`)
}
try {
await prisma.$executeRaw(sql`ALTER USER prisma WITH PASSWORD '${password}'`)
} catch (err) {
// Else
expect(err).toMatchInlineSnapshot(`
Running ALTER using prisma.$executeRaw(sql\`<SQL>\`) is not supported
Using the example below you can still execute your query with Prisma, but please note that it is vulnerable to SQL injection attacks and requires you to take care of input sanitization.
Example:
await prisma.$executeRaw(\`ALTER USER prisma WITH PASSWORD '\${password}'\`)
More Information: https://pris.ly/d/execute-raw
`)
}

// Should Work
const result = await prisma.$executeRaw(
`ALTER USER prisma WITH PASSWORD '${password}'`,
)
expect(result).toMatchInlineSnapshot(`0`)
})
31 changes: 29 additions & 2 deletions src/packages/client/src/runtime/getPrismaClient.ts
Expand Up @@ -43,11 +43,32 @@ import { printStack } from './utils/printStack'
import { serializeRawParameters } from './utils/serializeRawParameters'
import { validatePrismaClientOptions } from './utils/validatePrismaClientOptions'
const debug = Debug('prisma-client')
const ALTER_RE = /^(\s*alter\s)/i

function isReadonlyArray(arg: any): arg is ReadonlyArray<any> {
return Array.isArray(arg)
}

function checkAlter(
query: string,
values: sqlTemplateTag.Value[],
invalidCall:
| 'prisma.$executeRaw`<SQL>`'
| 'prisma.$executeRaw(<SQL>, [...values])'
| 'prisma.$executeRaw(sql`<SQL>`)',
) {
if (values.length > 0 && ALTER_RE.exec(query)) {
// See https://github.com/prisma/prisma-client-js/issues/940 for more info
throw new Error(`Running ALTER using ${invalidCall} is not supported
Using the example below you can still execute your query with Prisma, but please note that it is vulnerable to SQL injection attacks and requires you to take care of input sanitization.
Example:
await prisma.$executeRaw(\`ALTER USER prisma WITH PASSWORD '\${password}'\`)
More Information: https://pris.ly/d/execute-raw
`)
}
}
export type ErrorFormat = 'pretty' | 'colorless' | 'minimal'

export type Datasource = {
Expand Down Expand Up @@ -527,14 +548,14 @@ export function getPrismaClient(config: GetPrismaClientOptions): any {
// TODO Clean up types
let query = ''
let parameters: any = undefined

if (typeof stringOrTemplateStringsArray === 'string') {
// If this was called as prisma.$executeRaw(<SQL>, [...values]), assume it is a pre-prepared SQL statement, and forward it without any changes
query = stringOrTemplateStringsArray
parameters = {
values: serializeRawParameters(values || []),
__prismaRawParamaters__: true,
}
checkAlter(query, values, 'prisma.$executeRaw(<SQL>, [...values])')
} else if (isReadonlyArray(stringOrTemplateStringsArray)) {
// If this was called as prisma.$executeRaw`<SQL>`, try to generate a SQL prepared statement
switch (this._activeProvider) {
Expand All @@ -560,6 +581,7 @@ export function getPrismaClient(config: GetPrismaClientOptions): any {
)

query = queryInstance.text
checkAlter(query, queryInstance.values, 'prisma.$executeRaw`<SQL>`')
parameters = {
values: serializeRawParameters(queryInstance.values),
__prismaRawParamaters__: true,
Expand All @@ -577,14 +599,19 @@ export function getPrismaClient(config: GetPrismaClientOptions): any {
}
}
} else {
// If this was called as prisma.raw(sql`<SQL>`), use prepared statements from sql-template-tag
// If this was called as prisma.$executeRaw(sql`<SQL>`), use prepared statements from sql-template-tag
switch (this._activeProvider) {
case 'sqlite':
case 'mysql':
query = stringOrTemplateStringsArray.sql
break
case 'postgresql':
query = stringOrTemplateStringsArray.text
checkAlter(
query,
stringOrTemplateStringsArray.values,
'prisma.$executeRaw(sql`<SQL>`)',
)
break
case 'sqlserver':
query = mssqlPreparedStatement(stringOrTemplateStringsArray.strings)
Expand Down

0 comments on commit 650cfcc

Please sign in to comment.