Merge branch 'develop' of https://github.com/misskey-dev/misskey into develop
This commit is contained in:
		
						commit
						2acb3917ba
					
				
					 10 changed files with 27 additions and 15 deletions
				
			
		|  | @ -99,6 +99,7 @@ You should also include the user name that made the change. | ||||||
| - Server: アンテナの作成数上限を追加 @syuilo | - Server: アンテナの作成数上限を追加 @syuilo | ||||||
| - Server: pages/likeのエラーIDが重複しているのを修正 @syuilo | - Server: pages/likeのエラーIDが重複しているのを修正 @syuilo | ||||||
| - Server: pages/updateのパラメータによってはsummaryの値が更新されないのを修正 @syuilo | - Server: pages/updateのパラメータによってはsummaryの値が更新されないのを修正 @syuilo | ||||||
|  | - Server: Escape SQL LIKE @mei23 | ||||||
| - Client: case insensitive emoji search @saschanaz | - Client: case insensitive emoji search @saschanaz | ||||||
| - Client: InAppウィンドウが操作できなくなることがあるのを修正 @tamaina | - Client: InAppウィンドウが操作できなくなることがあるのを修正 @tamaina | ||||||
| - Client: use proxied image for instance icon @syuilo | - Client: use proxied image for instance icon @syuilo | ||||||
|  |  | ||||||
							
								
								
									
										3
									
								
								packages/backend/src/misc/sql-like-escape.ts
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										3
									
								
								packages/backend/src/misc/sql-like-escape.ts
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,3 @@ | ||||||
|  | export function sqlLikeEscape(s: string) { | ||||||
|  | 	return s.replace(/([%_])/g, '\\$1'); | ||||||
|  | } | ||||||
|  | @ -5,6 +5,7 @@ import { QueryService } from '@/core/QueryService.js'; | ||||||
| import { UtilityService } from '@/core/UtilityService.js'; | import { UtilityService } from '@/core/UtilityService.js'; | ||||||
| import { EmojiEntityService } from '@/core/entities/EmojiEntityService.js'; | import { EmojiEntityService } from '@/core/entities/EmojiEntityService.js'; | ||||||
| import { DI } from '@/di-symbols.js'; | import { DI } from '@/di-symbols.js'; | ||||||
|  | import { sqlLikeEscape } from '@/misc/sql-like-escape'; | ||||||
| 
 | 
 | ||||||
| export const meta = { | export const meta = { | ||||||
| 	tags: ['admin'], | 	tags: ['admin'], | ||||||
|  | @ -92,7 +93,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { | ||||||
| 			} | 			} | ||||||
| 
 | 
 | ||||||
| 			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 | 			const emojis = await q | ||||||
|  |  | ||||||
|  | @ -5,6 +5,7 @@ import type { Emoji } from '@/models/entities/Emoji.js'; | ||||||
| import { QueryService } from '@/core/QueryService.js'; | import { QueryService } from '@/core/QueryService.js'; | ||||||
| import { DI } from '@/di-symbols.js'; | import { DI } from '@/di-symbols.js'; | ||||||
| import { EmojiEntityService } from '@/core/entities/EmojiEntityService.js'; | import { EmojiEntityService } from '@/core/entities/EmojiEntityService.js'; | ||||||
|  | //import { sqlLikeEscape } from '@/misc/sql-like-escape';
 | ||||||
| 
 | 
 | ||||||
| export const meta = { | export const meta = { | ||||||
| 	tags: ['admin'], | 	tags: ['admin'], | ||||||
|  | @ -82,7 +83,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { | ||||||
| 			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(); | ||||||
|  |  | ||||||
|  | @ -3,6 +3,7 @@ import type { UsersRepository } from '@/models/index.js'; | ||||||
| import { Endpoint } from '@/server/api/endpoint-base.js'; | import { Endpoint } from '@/server/api/endpoint-base.js'; | ||||||
| import { DI } from '@/di-symbols.js'; | import { DI } from '@/di-symbols.js'; | ||||||
| import { UserEntityService } from '@/core/entities/UserEntityService.js'; | import { UserEntityService } from '@/core/entities/UserEntityService.js'; | ||||||
|  | import { sqlLikeEscape } from '@/misc/sql-like-escape'; | ||||||
| 
 | 
 | ||||||
| export const meta = { | export const meta = { | ||||||
| 	tags: ['admin'], | 	tags: ['admin'], | ||||||
|  | @ -68,7 +69,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { | ||||||
| 			} | 			} | ||||||
| 
 | 
 | ||||||
| 			if (ps.username) { | 			if (ps.username) { | ||||||
| 				query.andWhere('user.usernameLower like :username', { username: ps.username.toLowerCase() + '%' }); | 				query.andWhere('user.usernameLower like :username', { username: sqlLikeEscape(ps.username.toLowerCase()) + '%' }); | ||||||
| 			} | 			} | ||||||
| 
 | 
 | ||||||
| 			if (ps.hostname) { | 			if (ps.hostname) { | ||||||
|  |  | ||||||
|  | @ -4,6 +4,7 @@ import type { InstancesRepository } from '@/models/index.js'; | ||||||
| import { InstanceEntityService } from '@/core/entities/InstanceEntityService.js'; | import { InstanceEntityService } from '@/core/entities/InstanceEntityService.js'; | ||||||
| import { MetaService } from '@/core/MetaService.js'; | import { MetaService } from '@/core/MetaService.js'; | ||||||
| import { DI } from '@/di-symbols.js'; | import { DI } from '@/di-symbols.js'; | ||||||
|  | import { sqlLikeEscape } from '@/misc/sql-like-escape'; | ||||||
| 
 | 
 | ||||||
| export const meta = { | export const meta = { | ||||||
| 	tags: ['federation'], | 	tags: ['federation'], | ||||||
|  | @ -120,7 +121,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { | ||||||
| 			} | 			} | ||||||
| 
 | 
 | ||||||
| 			if (ps.host) { | 			if (ps.host) { | ||||||
| 				query.andWhere('instance.host like :host', { host: '%' + ps.host.toLowerCase() + '%' }); | 				query.andWhere('instance.host like :host', { host: '%' + sqlLikeEscape(ps.host.toLowerCase()) + '%' }); | ||||||
| 			} | 			} | ||||||
| 
 | 
 | ||||||
| 			const instances = await query.take(ps.limit).skip(ps.offset).getMany(); | 			const instances = await query.take(ps.limit).skip(ps.offset).getMany(); | ||||||
|  |  | ||||||
|  | @ -2,6 +2,7 @@ import { Inject, Injectable } from '@nestjs/common'; | ||||||
| import { Endpoint } from '@/server/api/endpoint-base.js'; | import { Endpoint } from '@/server/api/endpoint-base.js'; | ||||||
| import type { HashtagsRepository } from '@/models/index.js'; | import type { HashtagsRepository } from '@/models/index.js'; | ||||||
| import { DI } from '@/di-symbols.js'; | import { DI } from '@/di-symbols.js'; | ||||||
|  | import { sqlLikeEscape } from '@/misc/sql-like-escape'; | ||||||
| 
 | 
 | ||||||
| export const meta = { | export const meta = { | ||||||
| 	tags: ['hashtags'], | 	tags: ['hashtags'], | ||||||
|  | @ -37,7 +38,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { | ||||||
| 	) { | 	) { | ||||||
| 		super(meta, paramDef, async (ps, me) => { | 		super(meta, paramDef, async (ps, me) => { | ||||||
| 			const hashtags = await this.hashtagsRepository.createQueryBuilder('tag') | 			const hashtags = await this.hashtagsRepository.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) | ||||||
|  |  | ||||||
|  | @ -6,6 +6,7 @@ import { QueryService } from '@/core/QueryService.js'; | ||||||
| import { NoteEntityService } from '@/core/entities/NoteEntityService.js'; | import { NoteEntityService } from '@/core/entities/NoteEntityService.js'; | ||||||
| import type { Config } from '@/config.js'; | import type { Config } from '@/config.js'; | ||||||
| import { DI } from '@/di-symbols.js'; | import { DI } from '@/di-symbols.js'; | ||||||
|  | import { sqlLikeEscape } from '@/misc/sql-like-escape'; | ||||||
| 
 | 
 | ||||||
| export const meta = { | export const meta = { | ||||||
| 	tags: ['notes'], | 	tags: ['notes'], | ||||||
|  | @ -70,7 +71,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { | ||||||
| 			} | 			} | ||||||
| 
 | 
 | ||||||
| 			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') | ||||||
|  |  | ||||||
|  | @ -6,6 +6,7 @@ import type { User } from '@/models/entities/User.js'; | ||||||
| import { Endpoint } from '@/server/api/endpoint-base.js'; | import { Endpoint } from '@/server/api/endpoint-base.js'; | ||||||
| import { UserEntityService } from '@/core/entities/UserEntityService.js'; | import { UserEntityService } from '@/core/entities/UserEntityService.js'; | ||||||
| import { DI } from '@/di-symbols.js'; | import { DI } from '@/di-symbols.js'; | ||||||
|  | import { sqlLikeEscape } from '@/misc/sql-like-escape'; | ||||||
| 
 | 
 | ||||||
| export const meta = { | export const meta = { | ||||||
| 	tags: ['users'], | 	tags: ['users'], | ||||||
|  | @ -59,10 +60,10 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { | ||||||
| 			if (ps.host) { | 			if (ps.host) { | ||||||
| 				const q = this.usersRepository.createQueryBuilder('user') | 				const q = this.usersRepository.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', { username: ps.username.toLowerCase() + '%' }); | 					q.andWhere('user.usernameLower LIKE :username', { username: sqlLikeEscape(ps.username.toLowerCase()) + '%' }); | ||||||
| 				} | 				} | ||||||
| 
 | 
 | ||||||
| 				q.andWhere('user.updatedAt IS NOT NULL'); | 				q.andWhere('user.updatedAt IS NOT NULL'); | ||||||
|  | @ -83,7 +84,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { | ||||||
| 						.where(`user.id IN (${ followingQuery.getQuery() })`) | 						.where(`user.id IN (${ followingQuery.getQuery() })`) | ||||||
| 						.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', { username: ps.username.toLowerCase() + '%' }) | 						.andWhere('user.usernameLower LIKE :username', { username: sqlLikeEscape(ps.username.toLowerCase()) + '%' }) | ||||||
| 						.andWhere(new Brackets(qb => { qb | 						.andWhere(new Brackets(qb => { qb | ||||||
| 							.where('user.updatedAt IS NULL') | 							.where('user.updatedAt IS NULL') | ||||||
| 							.orWhere('user.updatedAt > :activeThreshold', { activeThreshold: activeThreshold }); | 							.orWhere('user.updatedAt > :activeThreshold', { activeThreshold: activeThreshold }); | ||||||
|  | @ -101,7 +102,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { | ||||||
| 							.where(`user.id NOT IN (${ followingQuery.getQuery() })`) | 							.where(`user.id NOT IN (${ followingQuery.getQuery() })`) | ||||||
| 							.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', { username: ps.username.toLowerCase() + '%' }) | 							.andWhere('user.usernameLower LIKE :username', { username: sqlLikeEscape(ps.username.toLowerCase()) + '%' }) | ||||||
| 							.andWhere('user.updatedAt IS NOT NULL'); | 							.andWhere('user.updatedAt IS NOT NULL'); | ||||||
| 
 | 
 | ||||||
| 						otherQuery.setParameters(followingQuery.getParameters()); | 						otherQuery.setParameters(followingQuery.getParameters()); | ||||||
|  | @ -116,7 +117,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { | ||||||
| 				} else { | 				} else { | ||||||
| 					users = await this.usersRepository.createQueryBuilder('user') | 					users = await this.usersRepository.createQueryBuilder('user') | ||||||
| 						.where('user.isSuspended = FALSE') | 						.where('user.isSuspended = FALSE') | ||||||
| 						.andWhere('user.usernameLower LIKE :username', { username: ps.username.toLowerCase() + '%' }) | 						.andWhere('user.usernameLower LIKE :username', { 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') | ||||||
| 						.take(ps.limit - users.length) | 						.take(ps.limit - users.length) | ||||||
|  |  | ||||||
|  | @ -5,6 +5,7 @@ import type { User } from '@/models/entities/User.js'; | ||||||
| import { Endpoint } from '@/server/api/endpoint-base.js'; | import { Endpoint } from '@/server/api/endpoint-base.js'; | ||||||
| import { UserEntityService } from '@/core/entities/UserEntityService.js'; | import { UserEntityService } from '@/core/entities/UserEntityService.js'; | ||||||
| import { DI } from '@/di-symbols.js'; | import { DI } from '@/di-symbols.js'; | ||||||
|  | import { sqlLikeEscape } from '@/misc/sql-like-escape'; | ||||||
| 
 | 
 | ||||||
| export const meta = { | export const meta = { | ||||||
| 	tags: ['users'], | 	tags: ['users'], | ||||||
|  | @ -57,7 +58,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { | ||||||
| 
 | 
 | ||||||
| 			if (isUsername) { | 			if (isUsername) { | ||||||
| 				const usernameQuery = this.usersRepository.createQueryBuilder('user') | 				const usernameQuery = this.usersRepository.createQueryBuilder('user') | ||||||
| 					.where('user.usernameLower LIKE :username', { username: ps.query.replace('@', '').toLowerCase() + '%' }) | 					.where('user.usernameLower LIKE :username', { username: sqlLikeEscape(ps.query.replace('@', '').toLowerCase()) + '%' }) | ||||||
| 					.andWhere(new Brackets(qb => { qb | 					.andWhere(new Brackets(qb => { qb | ||||||
| 						.where('user.updatedAt IS NULL') | 						.where('user.updatedAt IS NULL') | ||||||
| 						.orWhere('user.updatedAt > :activeThreshold', { activeThreshold: activeThreshold }); | 						.orWhere('user.updatedAt > :activeThreshold', { activeThreshold: activeThreshold }); | ||||||
|  | @ -78,11 +79,11 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { | ||||||
| 			} else { | 			} else { | ||||||
| 				const nameQuery = this.usersRepository.createQueryBuilder('user') | 				const nameQuery = this.usersRepository.createQueryBuilder('user') | ||||||
| 					.where(new Brackets(qb => {  | 					.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
 | 						// Also search username if it qualifies as username
 | ||||||
| 						if (this.userEntityService.validateLocalUsername(ps.query)) { | 						if (this.userEntityService.validateLocalUsername(ps.query)) { | ||||||
| 							qb.orWhere('user.usernameLower LIKE :username', { username: '%' + ps.query.toLowerCase() + '%' }); | 							qb.orWhere('user.usernameLower LIKE :username', { username: '%' + sqlLikeEscape(ps.query.toLowerCase()) + '%' }); | ||||||
| 						} | 						} | ||||||
| 					})) | 					})) | ||||||
| 					.andWhere(new Brackets(qb => { qb | 					.andWhere(new Brackets(qb => { qb | ||||||
|  | @ -106,7 +107,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { | ||||||
| 				if (users.length < ps.limit) { | 				if (users.length < ps.limit) { | ||||||
| 					const profQuery = this.userProfilesRepository.createQueryBuilder('prof') | 					const profQuery = this.userProfilesRepository.createQueryBuilder('prof') | ||||||
| 						.select('prof.userId') | 						.select('prof.userId') | ||||||
| 						.where('prof.description ILIKE :query', { query: '%' + ps.query + '%' }); | 						.where('prof.description ILIKE :query', { query: '%' + sqlLikeEscape(ps.query) + '%' }); | ||||||
| 
 | 
 | ||||||
| 					if (ps.origin === 'local') { | 					if (ps.origin === 'local') { | ||||||
| 						profQuery.andWhere('prof.userHost IS NULL'); | 						profQuery.andWhere('prof.userHost IS NULL'); | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue