From 910b06c35a44efc5ca352d232ff5f05837b02188 Mon Sep 17 00:00:00 2001 From: MeiMei <30769358+mei23@users.noreply.github.com> Date: Sun, 8 Jan 2023 20:32:17 +0900 Subject: [PATCH] fix: Escape SQL LIKE * SQL LIKE escape --- .../server/api/endpoints/admin/emoji/list-remote.ts | 3 ++- .../src/server/api/endpoints/admin/emoji/list.ts | 3 ++- .../src/server/api/endpoints/admin/show-users.ts | 3 ++- .../src/server/api/endpoints/federation/instances.ts | 3 ++- .../src/server/api/endpoints/hashtags/search.ts | 3 ++- .../backend/src/server/api/endpoints/notes/search.ts | 3 ++- .../endpoints/users/search-by-username-and-host.ts | 11 ++++++----- .../backend/src/server/api/endpoints/users/search.ts | 9 +++++---- 8 files changed, 23 insertions(+), 15 deletions(-) diff --git a/packages/backend/src/server/api/endpoints/admin/emoji/list-remote.ts b/packages/backend/src/server/api/endpoints/admin/emoji/list-remote.ts index 07d70365d6..dac752d3ab 100644 --- a/packages/backend/src/server/api/endpoints/admin/emoji/list-remote.ts +++ b/packages/backend/src/server/api/endpoints/admin/emoji/list-remote.ts @@ -2,6 +2,7 @@ import define from "../../../define.js"; import { Emojis } from "@/models/index.js"; import { toPuny } from "@/misc/convert-host.js"; import { makePaginationQuery } from "../../../common/make-pagination-query.js"; +import { sqlLikeEscape } from "@/misc/sql-like-escape"; export const meta = { tags: ["admin"], @@ -106,7 +107,7 @@ export default define(meta, paramDef, async (ps) => { } if (ps.query) { - q.andWhere("emoji.name like :query", { query: `%${ps.query}%` }); + q.andWhere('emoji.name like :query', { query: `%${sqlLikeEscape(ps.query)}%` }); } const emojis = await q.orderBy("emoji.id", "DESC").take(ps.limit).getMany(); diff --git a/packages/backend/src/server/api/endpoints/admin/emoji/list.ts b/packages/backend/src/server/api/endpoints/admin/emoji/list.ts index 9390dfb202..5ac110d6fd 100644 --- a/packages/backend/src/server/api/endpoints/admin/emoji/list.ts +++ b/packages/backend/src/server/api/endpoints/admin/emoji/list.ts @@ -2,6 +2,7 @@ import define from "../../../define.js"; import { Emojis } from "@/models/index.js"; import { makePaginationQuery } from "../../../common/make-pagination-query.js"; import type { Emoji } from "@/models/entities/emoji.js"; +//import { sqlLikeEscape } from "@/misc/sql-like-escape"; export const meta = { tags: ["admin"], @@ -96,7 +97,7 @@ export default define(meta, paramDef, async (ps) => { let emojis: Emoji[]; if (ps.query) { - //q.andWhere('emoji.name ILIKE :q', { q: `%${ps.query}%` }); + //q.andWhere('emoji.name ILIKE :q', { q: `%${sqlLikeEscape(ps.query)}%` }); //const emojis = await q.take(ps.limit).getMany(); emojis = await q.getMany(); diff --git a/packages/backend/src/server/api/endpoints/admin/show-users.ts b/packages/backend/src/server/api/endpoints/admin/show-users.ts index 868df9dc9b..1e76e08462 100644 --- a/packages/backend/src/server/api/endpoints/admin/show-users.ts +++ b/packages/backend/src/server/api/endpoints/admin/show-users.ts @@ -1,5 +1,6 @@ import { Users } from "@/models/index.js"; import define from "../../define.js"; +import { sqlLikeEscape } from "@/misc/sql-like-escape"; export const meta = { tags: ["admin"], @@ -106,7 +107,7 @@ export default define(meta, paramDef, async (ps, me) => { if (ps.username) { query.andWhere("user.usernameLower like :username", { - username: `${ps.username.toLowerCase()}%`, + username: `${sqlLikeEscape(ps.username.toLowerCase())}%`, }); } diff --git a/packages/backend/src/server/api/endpoints/federation/instances.ts b/packages/backend/src/server/api/endpoints/federation/instances.ts index 646f38282b..34af50f36d 100644 --- a/packages/backend/src/server/api/endpoints/federation/instances.ts +++ b/packages/backend/src/server/api/endpoints/federation/instances.ts @@ -2,6 +2,7 @@ import config from "@/config/index.js"; import define from "../../define.js"; import { Instances } from "@/models/index.js"; import { fetchMeta } from "@/misc/fetch-meta.js"; +import { sqlLikeEscape } from "@/misc/sql-like-escape"; export const meta = { tags: ["federation"], @@ -178,7 +179,7 @@ export default define(meta, paramDef, async (ps, me) => { if (ps.host) { query.andWhere("instance.host like :host", { - host: `%${ps.host.toLowerCase()}%`, + host: `%${sqlLikeEscape(ps.host.toLowerCase())}%`, }); } diff --git a/packages/backend/src/server/api/endpoints/hashtags/search.ts b/packages/backend/src/server/api/endpoints/hashtags/search.ts index 95bc608ece..49cc2aca11 100644 --- a/packages/backend/src/server/api/endpoints/hashtags/search.ts +++ b/packages/backend/src/server/api/endpoints/hashtags/search.ts @@ -1,5 +1,6 @@ import define from "../../define.js"; import { Hashtags } from "@/models/index.js"; +import { sqlLikeEscape } from "@/misc/sql-like-escape"; export const meta = { tags: ["hashtags"], @@ -31,7 +32,7 @@ export const paramDef = { export default define(meta, paramDef, async (ps) => { const hashtags = await Hashtags.createQueryBuilder("tag") - .where("tag.name like :q", { q: `${ps.query.toLowerCase()}%` }) + .where("tag.name like :q", { q: `${sqlLikeEscape(ps.query.toLowerCase())}%` }) .orderBy("tag.count", "DESC") .groupBy("tag.id") .take(ps.limit) diff --git a/packages/backend/src/server/api/endpoints/notes/search.ts b/packages/backend/src/server/api/endpoints/notes/search.ts index 8f563c384f..6b151efef2 100644 --- a/packages/backend/src/server/api/endpoints/notes/search.ts +++ b/packages/backend/src/server/api/endpoints/notes/search.ts @@ -9,6 +9,7 @@ import { makePaginationQuery } from "../../common/make-pagination-query.js"; import { generateVisibilityQuery } from "../../common/generate-visibility-query.js"; import { generateMutedUserQuery } from "../../common/generate-muted-user-query.js"; import { generateBlockedUserQuery } from "../../common/generate-block-query.js"; +import { sqlLikeEscape } from "@/misc/sql-like-escape"; export const meta = { tags: ["notes"], @@ -77,7 +78,7 @@ export default define(meta, paramDef, async (ps, me) => { } query - .andWhere("note.text ILIKE :q", { q: `%${ps.query}%` }) + .andWhere("note.text ILIKE :q", { q: `%${sqlLikeEscape(ps.query)}%` }) .innerJoinAndSelect("note.user", "user") .leftJoinAndSelect("user.avatar", "avatar") .leftJoinAndSelect("user.banner", "banner") diff --git a/packages/backend/src/server/api/endpoints/users/search-by-username-and-host.ts b/packages/backend/src/server/api/endpoints/users/search-by-username-and-host.ts index 99aa2f1af3..3449481019 100644 --- a/packages/backend/src/server/api/endpoints/users/search-by-username-and-host.ts +++ b/packages/backend/src/server/api/endpoints/users/search-by-username-and-host.ts @@ -3,6 +3,7 @@ import { Followings, Users } from "@/models/index.js"; import { USER_ACTIVE_THRESHOLD } from "@/const.js"; import type { User } from "@/models/entities/user.js"; import define from "../../define.js"; +import { sqlLikeEscape } from "@/misc/sql-like-escape"; export const meta = { tags: ["users"], @@ -44,11 +45,11 @@ export default define(meta, paramDef, async (ps, me) => { if (ps.host) { const q = Users.createQueryBuilder("user") .where("user.isSuspended = FALSE") - .andWhere("user.host LIKE :host", { host: `${ps.host.toLowerCase()}%` }); + .andWhere("user.host LIKE :host", { host: `${sqlLikeEscape(ps.host.toLowerCase())}%` }); if (ps.username) { q.andWhere("user.usernameLower LIKE :username", { - username: `${ps.username.toLowerCase()}%`, + username: `${sqlLikeEscape(ps.username.toLowerCase())}%`, }); } @@ -71,7 +72,7 @@ export default define(meta, paramDef, async (ps, me) => { .andWhere("user.id != :meId", { meId: me.id }) .andWhere("user.isSuspended = FALSE") .andWhere("user.usernameLower LIKE :username", { - username: `${ps.username.toLowerCase()}%`, + username: `${sqlLikeEscape(ps.username.toLowerCase())}%`, }) .andWhere( new Brackets((qb) => { @@ -95,7 +96,7 @@ export default define(meta, paramDef, async (ps, me) => { .andWhere("user.id != :meId", { meId: me.id }) .andWhere("user.isSuspended = FALSE") .andWhere("user.usernameLower LIKE :username", { - username: `${ps.username.toLowerCase()}%`, + username: `${sqlLikeEscape(ps.username.toLowerCase())}%`, }) .andWhere("user.updatedAt IS NOT NULL"); @@ -112,7 +113,7 @@ export default define(meta, paramDef, async (ps, me) => { users = await Users.createQueryBuilder("user") .where("user.isSuspended = FALSE") .andWhere("user.usernameLower LIKE :username", { - username: `${ps.username.toLowerCase()}%`, + username: `${sqlLikeEscape(ps.username.toLowerCase())}%`, }) .andWhere("user.updatedAt IS NOT NULL") .orderBy("user.updatedAt", "DESC") diff --git a/packages/backend/src/server/api/endpoints/users/search.ts b/packages/backend/src/server/api/endpoints/users/search.ts index db687a1075..02bdf6d4b7 100644 --- a/packages/backend/src/server/api/endpoints/users/search.ts +++ b/packages/backend/src/server/api/endpoints/users/search.ts @@ -2,6 +2,7 @@ import { Brackets } from "typeorm"; import { UserProfiles, Users } from "@/models/index.js"; import type { User } from "@/models/entities/user.js"; import define from "../../define.js"; +import { sqlLikeEscape } from "@/misc/sql-like-escape"; export const meta = { tags: ["users"], @@ -50,7 +51,7 @@ export default define(meta, paramDef, async (ps, me) => { if (isUsername) { const usernameQuery = Users.createQueryBuilder("user") .where("user.usernameLower LIKE :username", { - username: `${ps.query.replace("@", "").toLowerCase()}%`, + username: `${sqlLikeEscape(ps.query.replace("@", "").toLowerCase())}%`, }) .andWhere( new Brackets((qb) => { @@ -77,12 +78,12 @@ export default define(meta, paramDef, async (ps, me) => { const nameQuery = Users.createQueryBuilder("user") .where( new Brackets((qb) => { - qb.where("user.name ILIKE :query", { query: `%${ps.query}%` }); + qb.where("user.name ILIKE :query", { query: `%${sqlLikeEscape(ps.query)}%` }); // Also search username if it qualifies as username if (Users.validateLocalUsername(ps.query)) { qb.orWhere("user.usernameLower LIKE :username", { - username: `%${ps.query.toLowerCase()}%`, + username: `%${sqlLikeEscape(ps.query.toLowerCase())}%`, }); } }), @@ -113,7 +114,7 @@ export default define(meta, paramDef, async (ps, me) => { const profQuery = UserProfiles.createQueryBuilder("prof") .select("prof.userId") .where("prof.description ILIKE :query", { - query: `%${ps.query}%`, + query: `%${sqlLikeEscape(ps.query)}%`, }); if (ps.origin === "local") {