Cherry pick prisma query protection.

pull/1739/head
Brian Cao 2023-01-12 11:29:37 -08:00
parent 4c202741c2
commit 9a7385e4d5
9 changed files with 68 additions and 47 deletions

View File

@ -54,7 +54,19 @@ function getClient(options) {
return prisma; return prisma;
} }
function getDateQuery(field, unit, timezone?): string { function toUuid(): string {
const db = getDatabaseType(process.env.DATABASE_URL);
if (db === POSTGRESQL) {
return '::uuid';
}
if (db === MYSQL) {
return '';
}
}
function getDateQuery(field: string, unit: string, timezone?: string): string {
const db = getDatabaseType(process.env.DATABASE_URL); const db = getDatabaseType(process.env.DATABASE_URL);
if (db === POSTGRESQL) { if (db === POSTGRESQL) {
@ -201,7 +213,7 @@ function parseFilters(
event: { event_name }, event: { event_name },
joinSession: joinSession:
os || browser || device || country os || browser || device || country
? `inner join session on ${sessionKey} = session.${sessionKey}` ? `inner join session on website_event.${sessionKey} = session.${sessionKey}`
: '', : '',
filterQuery: getFilterQuery(filters, params), filterQuery: getFilterQuery(filters, params),
}; };
@ -235,6 +247,7 @@ export default {
getFilterQuery, getFilterQuery,
getEventDataColumnsQuery, getEventDataColumnsQuery,
getEventDataFilterQuery, getEventDataFilterQuery,
toUuid,
parseFilters, parseFilters,
rawQuery, rawQuery,
transaction, transaction,

View File

@ -82,7 +82,7 @@ export default async (
endDate, endDate,
timezone: tz, timezone: tz,
unit, unit,
count: 'distinct pageview.', count: 'distinct website_event.',
filters: { filters: {
url, url,
os, os,

View File

@ -38,17 +38,17 @@ async function relationalQuery(
}, },
) { ) {
const { startDate, endDate, eventName, columns, filters } = data; const { startDate, endDate, eventName, columns, filters } = data;
const { rawQuery, getEventDataColumnsQuery, getEventDataFilterQuery } = prisma; const { toUuid, rawQuery, getEventDataColumnsQuery, getEventDataFilterQuery } = prisma;
const params = [startDate, endDate]; const params: any = [websiteId, startDate, endDate, eventName];
return rawQuery( return rawQuery(
`select `select
${getEventDataColumnsQuery('event_data', columns)} ${getEventDataColumnsQuery('event_data', columns)}
from website_event from website_event
where website_id ='${websiteId}' where website_id = $1${toUuid()}
and created_at between $1 and $2 and created_at between $2 and $3
and event_type = ${EVENT_TYPE.customEvent} and event_type = ${EVENT_TYPE.customEvent}
${eventName ? `and eventName = ${eventName}` : ''} ${eventName ? `and eventName = $4` : ''}
${ ${
Object.keys(filters).length > 0 Object.keys(filters).length > 0
? `and ${getEventDataFilterQuery('event_data', filters)}` ? `and ${getEventDataFilterQuery('event_data', filters)}`

View File

@ -45,8 +45,8 @@ async function relationalQuery(
}; };
}, },
) { ) {
const { rawQuery, getDateQuery, getFilterQuery } = prisma; const { toUuid, rawQuery, getDateQuery, getFilterQuery } = prisma;
const params = [startDate, endDate]; const params: any = [websiteId, startDate, endDate];
return rawQuery( return rawQuery(
`select `select
@ -54,8 +54,8 @@ async function relationalQuery(
${getDateQuery('created_at', unit, timezone)} t, ${getDateQuery('created_at', unit, timezone)} t,
count(*) y count(*) y
from website_event from website_event
where website_id='${websiteId}' where website_id = $1${toUuid()}
and created_at between $1 and $2 and created_at between $2 and $3
and event_type = ${EVENT_TYPE.customEvent} and event_type = ${EVENT_TYPE.customEvent}
${getFilterQuery(filters, params)} ${getFilterQuery(filters, params)}
group by 1, 2 group by 1, 2

View File

@ -32,18 +32,23 @@ async function relationalQuery(
filters: object; filters: object;
}, },
) { ) {
const { startDate, endDate, column, filters = {} } = data; const { startDate, endDate, column, filters = {}, type } = data;
const { rawQuery, parseFilters } = prisma; const { rawQuery, parseFilters, toUuid } = prisma;
const params = [startDate, endDate]; const params: any = [
websiteId,
startDate,
endDate,
type === 'event' ? EVENT_TYPE.customEvent : EVENT_TYPE.pageView,
];
const { filterQuery, joinSession } = parseFilters(filters, params); const { filterQuery, joinSession } = parseFilters(filters, params);
return rawQuery( return rawQuery(
`select ${column} x, count(*) y `select ${column} x, count(*) y
from website_event from website_event
${joinSession} ${joinSession}
where website_id='${websiteId}' where website_event.website_id = $1${toUuid()}
and website_event.created_at between $1 and $2 and website_event.created_at between $2 and $3
and event_type = ${EVENT_TYPE.pageView} and event_type = $4
${filterQuery} ${filterQuery}
group by 1 group by 1
order by 2 desc`, order by 2 desc`,

View File

@ -45,8 +45,8 @@ async function relationalQuery(
filters = {}, filters = {},
sessionKey = 'session_id', sessionKey = 'session_id',
} = data; } = data;
const { getDateQuery, parseFilters, rawQuery } = prisma; const { toUuid, getDateQuery, parseFilters, rawQuery } = prisma;
const params = [startDate, endDate]; const params: any = [websiteId, startDate, endDate];
const { filterQuery, joinSession } = parseFilters(filters, params); const { filterQuery, joinSession } = parseFilters(filters, params);
return rawQuery( return rawQuery(
@ -54,8 +54,8 @@ async function relationalQuery(
count(${count !== '*' ? `${count}${sessionKey}` : count}) y count(${count !== '*' ? `${count}${sessionKey}` : count}) y
from website_event from website_event
${joinSession} ${joinSession}
where website.website_id='${websiteId}' where website_event.website_id = $1${toUuid()}
and pageview.created_at between $1 and $2 and website_event.created_at between $2 and $3
and event_type = ${EVENT_TYPE.pageView} and event_type = ${EVENT_TYPE.pageView}
${filterQuery} ${filterQuery}
group by 1`, group by 1`,
@ -90,7 +90,7 @@ async function clickhouseQuery(
${getDateQuery('created_at', unit, timezone)} t, ${getDateQuery('created_at', unit, timezone)} t,
count(${count !== '*' ? 'distinct session_id' : count}) y count(${count !== '*' ? 'distinct session_id' : count}) y
from event from event
where website_id = $1 where website_id = $1
and rev_id = $2 and rev_id = $2
and event_type = ${EVENT_TYPE.pageView} and event_type = ${EVENT_TYPE.pageView}
and ${getBetweenDates('created_at', startDate, endDate)} and ${getBetweenDates('created_at', startDate, endDate)}

View File

@ -20,21 +20,21 @@ async function relationalQuery(
data: { startDate: Date; endDate: Date; field: string; filters: object }, data: { startDate: Date; endDate: Date; field: string; filters: object },
) { ) {
const { startDate, endDate, field, filters = {} } = data; const { startDate, endDate, field, filters = {} } = data;
const { parseFilters, rawQuery } = prisma; const { toUuid, parseFilters, rawQuery } = prisma;
const params = [startDate, endDate]; const params: any = [websiteId, startDate, endDate];
const { filterQuery, joinSession } = parseFilters(filters, params); const { filterQuery, joinSession } = parseFilters(filters, params);
return rawQuery( return rawQuery(
`select ${field} x, count(*) y `select ${field} x, count(*) y
from session as x from session as x
where x.session_id in ( where x.session_id in (
select pageview.session_id select website_event.session_id
from pageview from website_event
join website join website
on pageview.website_id = website.website_id on website_event.website_id = website.website_id
${joinSession} ${joinSession}
where website.website_id='${websiteId}' where website.website_id = $1${toUuid()}
and pageview.created_at between $1 and $2 and website_event.created_at between $2 and $3
${filterQuery} ${filterQuery}
) )
group by 1 group by 1

View File

@ -11,16 +11,18 @@ export async function getActiveVisitors(...args: [websiteId: string]) {
} }
async function relationalQuery(websiteId: string) { async function relationalQuery(websiteId: string) {
const date = subMinutes(new Date(), 5); const { toUuid, rawQuery } = prisma;
const params = [date];
return prisma.rawQuery( const date = subMinutes(new Date(), 5);
const params: any = [websiteId, date];
return rawQuery(
`select count(distinct session_id) x `select count(distinct session_id) x
from pageview from website_event
join website join website
on pageview.website_id = website.website_id on website_event.website_id = website.website_id
where website.website_id = '${websiteId}' where website.website_id = $1${toUuid()}
and pageview.created_at >= $1`, and website_event.created_at >= $2`,
params, params,
); );
} }

View File

@ -2,6 +2,7 @@ import prisma from 'lib/prisma';
import clickhouse from 'lib/clickhouse'; import clickhouse from 'lib/clickhouse';
import { runQuery, CLICKHOUSE, PRISMA } from 'lib/db'; import { runQuery, CLICKHOUSE, PRISMA } from 'lib/db';
import cache from 'lib/cache'; import cache from 'lib/cache';
import { EVENT_TYPE } from 'lib/constants';
export async function getWebsiteStats( export async function getWebsiteStats(
...args: [websiteId: string, data: { startDate: Date; endDate: Date; filters: object }] ...args: [websiteId: string, data: { startDate: Date; endDate: Date; filters: object }]
@ -17,8 +18,8 @@ async function relationalQuery(
data: { startDate: Date; endDate: Date; filters: object }, data: { startDate: Date; endDate: Date; filters: object },
) { ) {
const { startDate, endDate, filters = {} } = data; const { startDate, endDate, filters = {} } = data;
const { getDateQuery, getTimestampInterval, parseFilters, rawQuery } = prisma; const { toUuid, getDateQuery, getTimestampInterval, parseFilters, rawQuery } = prisma;
const params = [startDate, endDate]; const params: any = [websiteId, startDate, endDate];
const { filterQuery, joinSession } = parseFilters(filters, params); const { filterQuery, joinSession } = parseFilters(filters, params);
return rawQuery( return rawQuery(
@ -27,16 +28,16 @@ async function relationalQuery(
sum(case when t.c = 1 then 1 else 0 end) as "bounces", sum(case when t.c = 1 then 1 else 0 end) as "bounces",
sum(t.time) as "totaltime" sum(t.time) as "totaltime"
from ( from (
select pageview.session_id, select website_event.session_id,
${getDateQuery('pageview.created_at', 'hour')}, ${getDateQuery('website_event.created_at', 'hour')},
count(*) c, count(*) c,
${getTimestampInterval('pageview.created_at')} as "time" ${getTimestampInterval('website_event.created_at')} as "time"
from pageview from website_event
join website join website
on pageview.website_id = website.website_id on website_event.website_id = website.website_id
${joinSession} ${joinSession}
where website.website_id='${websiteId}' where website.website_id = $1${toUuid()}
and pageview.created_at between $1 and $2 and website_event.created_at between $2 and $3
${filterQuery} ${filterQuery}
group by 1, 2 group by 1, 2
) t`, ) t`,
@ -67,7 +68,7 @@ async function clickhouseQuery(
min(created_at) min_time, min(created_at) min_time,
max(created_at) max_time max(created_at) max_time
from event from event
where event_name = '' where event_type = ${EVENT_TYPE.pageView}
and website_id = $1 and website_id = $1
and rev_id = $2 and rev_id = $2
and ${getBetweenDates('created_at', startDate, endDate)} and ${getBetweenDates('created_at', startDate, endDate)}