Merge pull request 'security: escape SQL-like queries' (#10182) from naskya/calckey:security/escape-sql into develop

Reviewed-on: https://codeberg.org/calckey/calckey/pulls/10182
This commit is contained in:
Kainoa Kanter 2023-05-23 05:29:55 +00:00
commit 88b2c1d60c
8 changed files with 31 additions and 15 deletions

View file

@ -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.js";
export const meta = {
tags: ["admin"],
@ -106,7 +107,9 @@ 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();

View file

@ -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.js";
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();

View file

@ -1,5 +1,6 @@
import { Users } from "@/models/index.js";
import define from "../../define.js";
import { sqlLikeEscape } from "@/misc/sql-like-escape.js";
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())}%`,
});
}

View file

@ -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.js";
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())}%`,
});
}

View file

@ -1,5 +1,6 @@
import define from "../../define.js";
import { Hashtags } from "@/models/index.js";
import { sqlLikeEscape } from "@/misc/sql-like-escape.js";
export const meta = {
tags: ["hashtags"],
@ -31,7 +32,9 @@ 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)

View file

@ -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.js";
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")

View file

@ -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.js";
export const meta = {
tags: ["users"],
@ -44,11 +45,13 @@ 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 +74,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 +98,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 +115,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")

View file

@ -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.js";
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,14 @@ 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 +116,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") {