43
									
								
								packages/backend/src/server/api/endpoints/federation/dns.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										43
									
								
								packages/backend/src/server/api/endpoints/federation/dns.ts
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,43 @@ | ||||
| import { promises as dns } from 'dns'; | ||||
| import $ from 'cafy'; | ||||
| import define from '../../define'; | ||||
| import { Instances } from '@/models/index'; | ||||
| import { toPuny } from '@/misc/convert-host'; | ||||
|  | ||||
| const resolver = new dns.Resolver(); | ||||
| resolver.setServers(['1.1.1.1']); | ||||
|  | ||||
| export const meta = { | ||||
| 	tags: ['federation'], | ||||
|  | ||||
| 	requireCredential: false as const, | ||||
|  | ||||
| 	params: { | ||||
| 		host: { | ||||
| 			validator: $.str | ||||
| 		} | ||||
| 	}, | ||||
| }; | ||||
|  | ||||
| export default define(meta, async (ps, me) => { | ||||
| 	const instance = await Instances.findOneOrFail({ host: toPuny(ps.host) }); | ||||
|  | ||||
| 	const [ | ||||
| 		resolved4, | ||||
| 		resolved6, | ||||
| 		resolvedCname, | ||||
| 		resolvedTxt, | ||||
| 	] = await Promise.all([ | ||||
| 		resolver.resolve4(instance.host).catch(() => []), | ||||
| 		resolver.resolve6(instance.host).catch(() => []), | ||||
| 		resolver.resolveCname(instance.host).catch(() => []), | ||||
| 		resolver.resolveTxt(instance.host).catch(() => []), | ||||
| 	]); | ||||
|  | ||||
| 	return { | ||||
| 		a: resolved4, | ||||
| 		aaaa: resolved6, | ||||
| 		cname: resolvedCname, | ||||
| 		txt: resolvedTxt, | ||||
| 	}; | ||||
| }); | ||||
| @@ -0,0 +1,51 @@ | ||||
| import $ from 'cafy'; | ||||
| import { ID } from '@/misc/cafy-id'; | ||||
| import define from '../../define'; | ||||
| import { Followings } from '@/models/index'; | ||||
| import { makePaginationQuery } from '../../common/make-pagination-query'; | ||||
|  | ||||
| export const meta = { | ||||
| 	tags: ['federation'], | ||||
|  | ||||
| 	requireCredential: false as const, | ||||
|  | ||||
| 	params: { | ||||
| 		host: { | ||||
| 			validator: $.str | ||||
| 		}, | ||||
|  | ||||
| 		sinceId: { | ||||
| 			validator: $.optional.type(ID), | ||||
| 		}, | ||||
|  | ||||
| 		untilId: { | ||||
| 			validator: $.optional.type(ID), | ||||
| 		}, | ||||
|  | ||||
| 		limit: { | ||||
| 			validator: $.optional.num.range(1, 100), | ||||
| 			default: 10 | ||||
| 		}, | ||||
| 	}, | ||||
|  | ||||
| 	res: { | ||||
| 		type: 'array' as const, | ||||
| 		optional: false as const, nullable: false as const, | ||||
| 		items: { | ||||
| 			type: 'object' as const, | ||||
| 			optional: false as const, nullable: false as const, | ||||
| 			ref: 'Following', | ||||
| 		} | ||||
| 	}, | ||||
| }; | ||||
|  | ||||
| export default define(meta, async (ps, me) => { | ||||
| 	const query = makePaginationQuery(Followings.createQueryBuilder('following'), ps.sinceId, ps.untilId) | ||||
| 		.andWhere(`following.followeeHost = :host`, { host: ps.host }); | ||||
|  | ||||
| 	const followings = await query | ||||
| 		.take(ps.limit!) | ||||
| 		.getMany(); | ||||
|  | ||||
| 	return await Followings.packMany(followings, me, { populateFollowee: true }); | ||||
| }); | ||||
| @@ -0,0 +1,51 @@ | ||||
| import $ from 'cafy'; | ||||
| import { ID } from '@/misc/cafy-id'; | ||||
| import define from '../../define'; | ||||
| import { Followings } from '@/models/index'; | ||||
| import { makePaginationQuery } from '../../common/make-pagination-query'; | ||||
|  | ||||
| export const meta = { | ||||
| 	tags: ['federation'], | ||||
|  | ||||
| 	requireCredential: false as const, | ||||
|  | ||||
| 	params: { | ||||
| 		host: { | ||||
| 			validator: $.str | ||||
| 		}, | ||||
|  | ||||
| 		sinceId: { | ||||
| 			validator: $.optional.type(ID), | ||||
| 		}, | ||||
|  | ||||
| 		untilId: { | ||||
| 			validator: $.optional.type(ID), | ||||
| 		}, | ||||
|  | ||||
| 		limit: { | ||||
| 			validator: $.optional.num.range(1, 100), | ||||
| 			default: 10 | ||||
| 		}, | ||||
| 	}, | ||||
|  | ||||
| 	res: { | ||||
| 		type: 'array' as const, | ||||
| 		optional: false as const, nullable: false as const, | ||||
| 		items: { | ||||
| 			type: 'object' as const, | ||||
| 			optional: false as const, nullable: false as const, | ||||
| 			ref: 'Following', | ||||
| 		} | ||||
| 	}, | ||||
| }; | ||||
|  | ||||
| export default define(meta, async (ps, me) => { | ||||
| 	const query = makePaginationQuery(Followings.createQueryBuilder('following'), ps.sinceId, ps.untilId) | ||||
| 		.andWhere(`following.followerHost = :host`, { host: ps.host }); | ||||
|  | ||||
| 	const followings = await query | ||||
| 		.take(ps.limit!) | ||||
| 		.getMany(); | ||||
|  | ||||
| 	return await Followings.packMany(followings, me, { populateFollowee: true }); | ||||
| }); | ||||
| @@ -0,0 +1,149 @@ | ||||
| import $ from 'cafy'; | ||||
| import config from '@/config/index'; | ||||
| import define from '../../define'; | ||||
| import { Instances } from '@/models/index'; | ||||
| import { fetchMeta } from '@/misc/fetch-meta'; | ||||
|  | ||||
| export const meta = { | ||||
| 	tags: ['federation'], | ||||
|  | ||||
| 	requireCredential: false as const, | ||||
|  | ||||
| 	params: { | ||||
| 		host: { | ||||
| 			validator: $.optional.nullable.str, | ||||
| 		}, | ||||
|  | ||||
| 		blocked: { | ||||
| 			validator: $.optional.nullable.bool, | ||||
| 		}, | ||||
|  | ||||
| 		notResponding: { | ||||
| 			validator: $.optional.nullable.bool, | ||||
| 		}, | ||||
|  | ||||
| 		suspended: { | ||||
| 			validator: $.optional.nullable.bool, | ||||
| 		}, | ||||
|  | ||||
| 		federating: { | ||||
| 			validator: $.optional.nullable.bool, | ||||
| 		}, | ||||
|  | ||||
| 		subscribing: { | ||||
| 			validator: $.optional.nullable.bool, | ||||
| 		}, | ||||
|  | ||||
| 		publishing: { | ||||
| 			validator: $.optional.nullable.bool, | ||||
| 		}, | ||||
|  | ||||
| 		limit: { | ||||
| 			validator: $.optional.num.range(1, 100), | ||||
| 			default: 30 | ||||
| 		}, | ||||
|  | ||||
| 		offset: { | ||||
| 			validator: $.optional.num.min(0), | ||||
| 			default: 0 | ||||
| 		}, | ||||
|  | ||||
| 		sort: { | ||||
| 			validator: $.optional.str, | ||||
| 		} | ||||
| 	}, | ||||
|  | ||||
| 	res: { | ||||
| 		type: 'array' as const, | ||||
| 		optional: false as const, nullable: false as const, | ||||
| 		items: { | ||||
| 			type: 'object' as const, | ||||
| 			optional: false as const, nullable: false as const, | ||||
| 			ref: 'FederationInstance' | ||||
| 		} | ||||
| 	} | ||||
| }; | ||||
|  | ||||
| export default define(meta, async (ps, me) => { | ||||
| 	const query = Instances.createQueryBuilder('instance'); | ||||
|  | ||||
| 	switch (ps.sort) { | ||||
| 		case '+pubSub': query.orderBy('instance.followingCount', 'DESC').orderBy('instance.followersCount', 'DESC'); break; | ||||
| 		case '-pubSub': query.orderBy('instance.followingCount', 'ASC').orderBy('instance.followersCount', 'ASC'); break; | ||||
| 		case '+notes': query.orderBy('instance.notesCount', 'DESC'); break; | ||||
| 		case '-notes': query.orderBy('instance.notesCount', 'ASC'); break; | ||||
| 		case '+users': query.orderBy('instance.usersCount', 'DESC'); break; | ||||
| 		case '-users': query.orderBy('instance.usersCount', 'ASC'); break; | ||||
| 		case '+following': query.orderBy('instance.followingCount', 'DESC'); break; | ||||
| 		case '-following': query.orderBy('instance.followingCount', 'ASC'); break; | ||||
| 		case '+followers': query.orderBy('instance.followersCount', 'DESC'); break; | ||||
| 		case '-followers': query.orderBy('instance.followersCount', 'ASC'); break; | ||||
| 		case '+caughtAt': query.orderBy('instance.caughtAt', 'DESC'); break; | ||||
| 		case '-caughtAt': query.orderBy('instance.caughtAt', 'ASC'); break; | ||||
| 		case '+lastCommunicatedAt': query.orderBy('instance.lastCommunicatedAt', 'DESC'); break; | ||||
| 		case '-lastCommunicatedAt': query.orderBy('instance.lastCommunicatedAt', 'ASC'); break; | ||||
| 		case '+driveUsage': query.orderBy('instance.driveUsage', 'DESC'); break; | ||||
| 		case '-driveUsage': query.orderBy('instance.driveUsage', 'ASC'); break; | ||||
| 		case '+driveFiles': query.orderBy('instance.driveFiles', 'DESC'); break; | ||||
| 		case '-driveFiles': query.orderBy('instance.driveFiles', 'ASC'); break; | ||||
|  | ||||
| 		default: query.orderBy('instance.id', 'DESC'); break; | ||||
| 	} | ||||
|  | ||||
| 	if (typeof ps.blocked === 'boolean') { | ||||
| 		const meta = await fetchMeta(true); | ||||
| 		if (ps.blocked) { | ||||
| 			query.andWhere('instance.host IN (:...blocks)', { blocks: meta.blockedHosts }); | ||||
| 		} else { | ||||
| 			query.andWhere('instance.host NOT IN (:...blocks)', { blocks: meta.blockedHosts }); | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	if (typeof ps.notResponding === 'boolean') { | ||||
| 		if (ps.notResponding) { | ||||
| 			query.andWhere('instance.isNotResponding = TRUE'); | ||||
| 		} else { | ||||
| 			query.andWhere('instance.isNotResponding = FALSE'); | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	if (typeof ps.suspended === 'boolean') { | ||||
| 		if (ps.suspended) { | ||||
| 			query.andWhere('instance.isSuspended = TRUE'); | ||||
| 		} else { | ||||
| 			query.andWhere('instance.isSuspended = FALSE'); | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	if (typeof ps.federating === 'boolean') { | ||||
| 		if (ps.federating) { | ||||
| 			query.andWhere('((instance.followingCount > 0) OR (instance.followersCount > 0))'); | ||||
| 		} else { | ||||
| 			query.andWhere('((instance.followingCount = 0) AND (instance.followersCount = 0))'); | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	if (typeof ps.subscribing === 'boolean') { | ||||
| 		if (ps.subscribing) { | ||||
| 			query.andWhere('instance.followersCount > 0'); | ||||
| 		} else { | ||||
| 			query.andWhere('instance.followersCount = 0'); | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	if (typeof ps.publishing === 'boolean') { | ||||
| 		if (ps.publishing) { | ||||
| 			query.andWhere('instance.followingCount > 0'); | ||||
| 		} else { | ||||
| 			query.andWhere('instance.followingCount = 0'); | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	if (ps.host) { | ||||
| 		query.andWhere('instance.host like :host', { host: '%' + ps.host.toLowerCase() + '%' }); | ||||
| 	} | ||||
|  | ||||
| 	const instances = await query.take(ps.limit!).skip(ps.offset).getMany(); | ||||
|  | ||||
| 	return instances; | ||||
| }); | ||||
| @@ -0,0 +1,29 @@ | ||||
| import $ from 'cafy'; | ||||
| import define from '../../define'; | ||||
| import { Instances } from '@/models/index'; | ||||
| import { toPuny } from '@/misc/convert-host'; | ||||
|  | ||||
| export const meta = { | ||||
| 	tags: ['federation'], | ||||
|  | ||||
| 	requireCredential: false as const, | ||||
|  | ||||
| 	params: { | ||||
| 		host: { | ||||
| 			validator: $.str | ||||
| 		} | ||||
| 	}, | ||||
|  | ||||
| 	res: { | ||||
| 		type: 'object' as const, | ||||
| 		optional: false as const, nullable: false as const, | ||||
| 		ref: 'FederationInstance' | ||||
| 	} | ||||
| }; | ||||
|  | ||||
| export default define(meta, async (ps, me) => { | ||||
| 	const instance = await Instances | ||||
| 		.findOne({ host: toPuny(ps.host) }); | ||||
|  | ||||
| 	return instance; | ||||
| }); | ||||
| @@ -0,0 +1,22 @@ | ||||
| import $ from 'cafy'; | ||||
| import { ID } from '@/misc/cafy-id'; | ||||
| import define from '../../define'; | ||||
| import { getRemoteUser } from '../../common/getters'; | ||||
| import { updatePerson } from '@/remote/activitypub/models/person'; | ||||
|  | ||||
| export const meta = { | ||||
| 	tags: ['federation'], | ||||
|  | ||||
| 	requireCredential: true as const, | ||||
|  | ||||
| 	params: { | ||||
| 		userId: { | ||||
| 			validator: $.type(ID), | ||||
| 		}, | ||||
| 	} | ||||
| }; | ||||
|  | ||||
| export default define(meta, async (ps) => { | ||||
| 	const user = await getRemoteUser(ps.userId); | ||||
| 	await updatePerson(user.uri!); | ||||
| }); | ||||
| @@ -0,0 +1,51 @@ | ||||
| import $ from 'cafy'; | ||||
| import { ID } from '@/misc/cafy-id'; | ||||
| import define from '../../define'; | ||||
| import { Users } from '@/models/index'; | ||||
| import { makePaginationQuery } from '../../common/make-pagination-query'; | ||||
|  | ||||
| export const meta = { | ||||
| 	tags: ['federation'], | ||||
|  | ||||
| 	requireCredential: false as const, | ||||
|  | ||||
| 	params: { | ||||
| 		host: { | ||||
| 			validator: $.str | ||||
| 		}, | ||||
|  | ||||
| 		sinceId: { | ||||
| 			validator: $.optional.type(ID), | ||||
| 		}, | ||||
|  | ||||
| 		untilId: { | ||||
| 			validator: $.optional.type(ID), | ||||
| 		}, | ||||
|  | ||||
| 		limit: { | ||||
| 			validator: $.optional.num.range(1, 100), | ||||
| 			default: 10 | ||||
| 		}, | ||||
| 	}, | ||||
|  | ||||
| 	res: { | ||||
| 		type: 'array' as const, | ||||
| 		optional: false as const, nullable: false as const, | ||||
| 		items: { | ||||
| 			type: 'object' as const, | ||||
| 			optional: false as const, nullable: false as const, | ||||
| 			ref: 'User', | ||||
| 		} | ||||
| 	}, | ||||
| }; | ||||
|  | ||||
| export default define(meta, async (ps, me) => { | ||||
| 	const query = makePaginationQuery(Users.createQueryBuilder('user'), ps.sinceId, ps.untilId) | ||||
| 		.andWhere(`user.host = :host`, { host: ps.host }); | ||||
|  | ||||
| 	const users = await query | ||||
| 		.take(ps.limit!) | ||||
| 		.getMany(); | ||||
|  | ||||
| 	return await Users.packMany(users, me, { detail: true }); | ||||
| }); | ||||
		Reference in New Issue
	
	Block a user
	 syuilo
					syuilo