fix: Escape SQL LIKE

* SQL LIKE escape
This commit is contained in:
MeiMei 2023-01-08 20:32:17 +09:00 committed by naskya
parent d8aaa8f199
commit 910b06c35a
No known key found for this signature in database
GPG Key ID: 164DFF24E2D40139
8 changed files with 23 additions and 15 deletions

View File

@ -2,6 +2,7 @@ import define from "../../../define.js";
import { Emojis } from "@/models/index.js"; import { Emojis } from "@/models/index.js";
import { toPuny } from "@/misc/convert-host.js"; import { toPuny } from "@/misc/convert-host.js";
import { makePaginationQuery } from "../../../common/make-pagination-query.js"; import { makePaginationQuery } from "../../../common/make-pagination-query.js";
import { sqlLikeEscape } from "@/misc/sql-like-escape";
export const meta = { export const meta = {
tags: ["admin"], tags: ["admin"],
@ -106,7 +107,7 @@ export default define(meta, paramDef, async (ps) => {
} }
if (ps.query) { 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(); const emojis = await q.orderBy("emoji.id", "DESC").take(ps.limit).getMany();

View File

@ -2,6 +2,7 @@ import define from "../../../define.js";
import { Emojis } from "@/models/index.js"; import { Emojis } from "@/models/index.js";
import { makePaginationQuery } from "../../../common/make-pagination-query.js"; import { makePaginationQuery } from "../../../common/make-pagination-query.js";
import type { Emoji } from "@/models/entities/emoji.js"; import type { Emoji } from "@/models/entities/emoji.js";
//import { sqlLikeEscape } from "@/misc/sql-like-escape";
export const meta = { export const meta = {
tags: ["admin"], tags: ["admin"],
@ -96,7 +97,7 @@ export default define(meta, paramDef, async (ps) => {
let emojis: Emoji[]; let emojis: Emoji[];
if (ps.query) { 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(); //const emojis = await q.take(ps.limit).getMany();
emojis = await q.getMany(); emojis = await q.getMany();

View File

@ -1,5 +1,6 @@
import { Users } from "@/models/index.js"; import { Users } from "@/models/index.js";
import define from "../../define.js"; import define from "../../define.js";
import { sqlLikeEscape } from "@/misc/sql-like-escape";
export const meta = { export const meta = {
tags: ["admin"], tags: ["admin"],
@ -106,7 +107,7 @@ export default define(meta, paramDef, async (ps, me) => {
if (ps.username) { if (ps.username) {
query.andWhere("user.usernameLower like :username", { query.andWhere("user.usernameLower like :username", {
username: `${ps.username.toLowerCase()}%`, username: `${sqlLikeEscape(ps.username.toLowerCase())}%`,
}); });
} }

View File

@ -2,6 +2,7 @@ import config from "@/config/index.js";
import define from "../../define.js"; import define from "../../define.js";
import { Instances } from "@/models/index.js"; import { Instances } from "@/models/index.js";
import { fetchMeta } from "@/misc/fetch-meta.js"; import { fetchMeta } from "@/misc/fetch-meta.js";
import { sqlLikeEscape } from "@/misc/sql-like-escape";
export const meta = { export const meta = {
tags: ["federation"], tags: ["federation"],
@ -178,7 +179,7 @@ export default define(meta, paramDef, async (ps, me) => {
if (ps.host) { if (ps.host) {
query.andWhere("instance.host like :host", { query.andWhere("instance.host like :host", {
host: `%${ps.host.toLowerCase()}%`, host: `%${sqlLikeEscape(ps.host.toLowerCase())}%`,
}); });
} }

View File

@ -1,5 +1,6 @@
import define from "../../define.js"; import define from "../../define.js";
import { Hashtags } from "@/models/index.js"; import { Hashtags } from "@/models/index.js";
import { sqlLikeEscape } from "@/misc/sql-like-escape";
export const meta = { export const meta = {
tags: ["hashtags"], tags: ["hashtags"],
@ -31,7 +32,7 @@ export const paramDef = {
export default define(meta, paramDef, async (ps) => { export default define(meta, paramDef, async (ps) => {
const hashtags = await Hashtags.createQueryBuilder("tag") 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") .orderBy("tag.count", "DESC")
.groupBy("tag.id") .groupBy("tag.id")
.take(ps.limit) .take(ps.limit)

View File

@ -9,6 +9,7 @@ import { makePaginationQuery } from "../../common/make-pagination-query.js";
import { generateVisibilityQuery } from "../../common/generate-visibility-query.js"; import { generateVisibilityQuery } from "../../common/generate-visibility-query.js";
import { generateMutedUserQuery } from "../../common/generate-muted-user-query.js"; import { generateMutedUserQuery } from "../../common/generate-muted-user-query.js";
import { generateBlockedUserQuery } from "../../common/generate-block-query.js"; import { generateBlockedUserQuery } from "../../common/generate-block-query.js";
import { sqlLikeEscape } from "@/misc/sql-like-escape";
export const meta = { export const meta = {
tags: ["notes"], tags: ["notes"],
@ -77,7 +78,7 @@ export default define(meta, paramDef, async (ps, me) => {
} }
query query
.andWhere("note.text ILIKE :q", { q: `%${ps.query}%` }) .andWhere("note.text ILIKE :q", { q: `%${sqlLikeEscape(ps.query)}%` })
.innerJoinAndSelect("note.user", "user") .innerJoinAndSelect("note.user", "user")
.leftJoinAndSelect("user.avatar", "avatar") .leftJoinAndSelect("user.avatar", "avatar")
.leftJoinAndSelect("user.banner", "banner") .leftJoinAndSelect("user.banner", "banner")

View File

@ -3,6 +3,7 @@ import { Followings, Users } from "@/models/index.js";
import { USER_ACTIVE_THRESHOLD } from "@/const.js"; import { USER_ACTIVE_THRESHOLD } from "@/const.js";
import type { User } from "@/models/entities/user.js"; import type { User } from "@/models/entities/user.js";
import define from "../../define.js"; import define from "../../define.js";
import { sqlLikeEscape } from "@/misc/sql-like-escape";
export const meta = { export const meta = {
tags: ["users"], tags: ["users"],
@ -44,11 +45,11 @@ export default define(meta, paramDef, async (ps, me) => {
if (ps.host) { if (ps.host) {
const q = Users.createQueryBuilder("user") const q = Users.createQueryBuilder("user")
.where("user.isSuspended = FALSE") .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) { if (ps.username) {
q.andWhere("user.usernameLower LIKE :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.id != :meId", { meId: me.id })
.andWhere("user.isSuspended = FALSE") .andWhere("user.isSuspended = FALSE")
.andWhere("user.usernameLower LIKE :username", { .andWhere("user.usernameLower LIKE :username", {
username: `${ps.username.toLowerCase()}%`, username: `${sqlLikeEscape(ps.username.toLowerCase())}%`,
}) })
.andWhere( .andWhere(
new Brackets((qb) => { new Brackets((qb) => {
@ -95,7 +96,7 @@ export default define(meta, paramDef, async (ps, me) => {
.andWhere("user.id != :meId", { meId: me.id }) .andWhere("user.id != :meId", { meId: me.id })
.andWhere("user.isSuspended = FALSE") .andWhere("user.isSuspended = FALSE")
.andWhere("user.usernameLower LIKE :username", { .andWhere("user.usernameLower LIKE :username", {
username: `${ps.username.toLowerCase()}%`, username: `${sqlLikeEscape(ps.username.toLowerCase())}%`,
}) })
.andWhere("user.updatedAt IS NOT NULL"); .andWhere("user.updatedAt IS NOT NULL");
@ -112,7 +113,7 @@ export default define(meta, paramDef, async (ps, me) => {
users = await Users.createQueryBuilder("user") users = await Users.createQueryBuilder("user")
.where("user.isSuspended = FALSE") .where("user.isSuspended = FALSE")
.andWhere("user.usernameLower LIKE :username", { .andWhere("user.usernameLower LIKE :username", {
username: `${ps.username.toLowerCase()}%`, username: `${sqlLikeEscape(ps.username.toLowerCase())}%`,
}) })
.andWhere("user.updatedAt IS NOT NULL") .andWhere("user.updatedAt IS NOT NULL")
.orderBy("user.updatedAt", "DESC") .orderBy("user.updatedAt", "DESC")

View File

@ -2,6 +2,7 @@ import { Brackets } from "typeorm";
import { UserProfiles, Users } from "@/models/index.js"; import { UserProfiles, Users } from "@/models/index.js";
import type { User } from "@/models/entities/user.js"; import type { User } from "@/models/entities/user.js";
import define from "../../define.js"; import define from "../../define.js";
import { sqlLikeEscape } from "@/misc/sql-like-escape";
export const meta = { export const meta = {
tags: ["users"], tags: ["users"],
@ -50,7 +51,7 @@ export default define(meta, paramDef, async (ps, me) => {
if (isUsername) { if (isUsername) {
const usernameQuery = Users.createQueryBuilder("user") const usernameQuery = Users.createQueryBuilder("user")
.where("user.usernameLower LIKE :username", { .where("user.usernameLower LIKE :username", {
username: `${ps.query.replace("@", "").toLowerCase()}%`, username: `${sqlLikeEscape(ps.query.replace("@", "").toLowerCase())}%`,
}) })
.andWhere( .andWhere(
new Brackets((qb) => { new Brackets((qb) => {
@ -77,12 +78,12 @@ export default define(meta, paramDef, async (ps, me) => {
const nameQuery = Users.createQueryBuilder("user") const nameQuery = Users.createQueryBuilder("user")
.where( .where(
new Brackets((qb) => { 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 // Also search username if it qualifies as username
if (Users.validateLocalUsername(ps.query)) { if (Users.validateLocalUsername(ps.query)) {
qb.orWhere("user.usernameLower LIKE :username", { 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") const profQuery = UserProfiles.createQueryBuilder("prof")
.select("prof.userId") .select("prof.userId")
.where("prof.description ILIKE :query", { .where("prof.description ILIKE :query", {
query: `%${ps.query}%`, query: `%${sqlLikeEscape(ps.query)}%`,
}); });
if (ps.origin === "local") { if (ps.origin === "local") {