diff --git a/src/misc/safe-for-sql.ts b/src/misc/safe-for-sql.ts new file mode 100644 index 0000000000000000000000000000000000000000..7a57fabdfc3a55e24474cc5fe5079ea81b1db0fb --- /dev/null +++ b/src/misc/safe-for-sql.ts @@ -0,0 +1,3 @@ +export function safeForSql(text: string): boolean { + return /[\0\x08\x09\x1a\n\r"'\\\%]/g.test(text); +} diff --git a/src/server/api/endpoints/hashtags/trend.ts b/src/server/api/endpoints/hashtags/trend.ts index 740b6de4d7f0ce474e22fad6660c750065c97440..cfa97d147529811086e9b2330326225fe09063df 100644 --- a/src/server/api/endpoints/hashtags/trend.ts +++ b/src/server/api/endpoints/hashtags/trend.ts @@ -3,6 +3,7 @@ import define from '../../define'; import { fetchMeta } from '../../../../misc/fetch-meta'; import { Notes } from '../../../../models'; import { Note } from '../../../../models/entities/note'; +import { safeForSql } from '../../../../misc/safe-for-sql'; /* トレンドã«è¼‰ã‚‹ãŸã‚ã«ã¯ã€Œã€Žç›´è¿‘a分間ã®ãƒ¦ãƒ‹ãƒ¼ã‚¯æŠ•ç¨¿æ•°ãŒä»Šã‹ã‚‰a分å‰ï½žä»Šã‹ã‚‰b分å‰ã®é–“ã®ãƒ¦ãƒ‹ãƒ¼ã‚¯æŠ•ç¨¿æ•°ã®nå€ä»¥ä¸Šã€ã®ãƒãƒƒã‚·ãƒ¥ã‚¿ã‚°ã®ä¸Šä½5ä½ä»¥å†…ã«å…¥ã‚‹ã€ã“ã¨ãŒå¿…è¦ @@ -113,7 +114,7 @@ export default define(meta, async () => { for (let i = 0; i < range; i++) { countPromises.push(Promise.all(hots.map(tag => Notes.createQueryBuilder('note') .select('count(distinct note.userId)') - .where(':tag = ANY(note.tags)', { tag: tag }) + .where(`'{"${safeForSql(tag) ? tag : 'aichan_kawaii'}"}' <@ note.tags`) .andWhere('note.createdAt < :lt', { lt: new Date(now.getTime() - (interval * i)) }) .andWhere('note.createdAt > :gt', { gt: new Date(now.getTime() - (interval * (i + 1))) }) .cache(60000) // 1 min @@ -127,7 +128,7 @@ export default define(meta, async () => { const totalCounts = await Promise.all(hots.map(tag => Notes.createQueryBuilder('note') .select('count(distinct note.userId)') - .where(':tag = ANY(note.tags)', { tag: tag }) + .where(`'{"${safeForSql(tag) ? tag : 'aichan_kawaii'}"}' <@ note.tags`) .andWhere('note.createdAt > :gt', { gt: new Date(now.getTime() - rangeA) }) .cache(60000 * 60) // 60 min .getRawOne() diff --git a/src/server/api/endpoints/notes/search-by-tag.ts b/src/server/api/endpoints/notes/search-by-tag.ts index f4b89ff9f5a207e7c8488ff81c130478b0d900ab..aaeec5ecf478c0c4dddc3aa5173e73a87ae3a344 100644 --- a/src/server/api/endpoints/notes/search-by-tag.ts +++ b/src/server/api/endpoints/notes/search-by-tag.ts @@ -99,7 +99,8 @@ export default define(meta, async (ps, me) => { if (me) generateMuteQuery(query, me); if (ps.tag) { - query.andWhere(':tag = ANY(note.tags)', { tag: ps.tag.toLowerCase() }); + if (/[\0\x08\x09\x1a\n\r"'\\\%]/g.test(ps.tag)) return; + query.andWhere(`'{"${ps.tag.toLowerCase()}"}' <@ note.tags`); } else { let i = 0; query.andWhere(new Brackets(qb => { @@ -143,7 +144,7 @@ export default define(meta, async (ps, me) => { } // Search notes - const notes = await query.take(ps.limit!).getMany(); + const notes = await query.take(ps.limit!).printSql().getMany(); return await Notes.packMany(notes, me); });