外部サービス認証情報の配信 (#3975)
* Update person.ts * Update person.ts * Update person.ts * Update person.ts * Create original model * Make type formal * Update person.ts * Follow @mei23's review refs: https://github.com/syuilo/misskey/pull/3975#pullrequestreview-195770172
This commit is contained in:
		
							parent
							
								
									4632eecb76
								
							
						
					
					
						commit
						e2f7e82cac
					
				
					 4 changed files with 88 additions and 20 deletions
				
			
		
							
								
								
									
										5
									
								
								src/remote/activitypub/models/identifier.ts
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								src/remote/activitypub/models/identifier.ts
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,5 @@
 | 
			
		|||
export type IIdentifier = {
 | 
			
		||||
	type: string;
 | 
			
		||||
	name: string;
 | 
			
		||||
	value: string;
 | 
			
		||||
};
 | 
			
		||||
| 
						 | 
				
			
			@ -19,6 +19,7 @@ import getDriveFileUrl from '../../../misc/get-drive-file-url';
 | 
			
		|||
import { IEmoji } from '../../../models/emoji';
 | 
			
		||||
import { ITag } from './tag';
 | 
			
		||||
import Following from '../../../models/following';
 | 
			
		||||
import { IIdentifier } from './identifier';
 | 
			
		||||
 | 
			
		||||
const log = debug('misskey:activitypub');
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -137,9 +138,7 @@ export async function createPerson(uri: string, resolver?: Resolver): Promise<IU
 | 
			
		|||
 | 
			
		||||
	const host = toUnicode(new URL(object.id).hostname.toLowerCase());
 | 
			
		||||
 | 
			
		||||
	const fields = await extractFields(person.attachment).catch(e => {
 | 
			
		||||
		console.log(`cat not extract fields: ${e}`);
 | 
			
		||||
	});
 | 
			
		||||
	const { fields, services } = analyzeAttachments(person.attachment);
 | 
			
		||||
 | 
			
		||||
	const isBot = object.type == 'Service';
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -171,7 +170,8 @@ export async function createPerson(uri: string, resolver?: Resolver): Promise<IU
 | 
			
		|||
			uri: person.id,
 | 
			
		||||
			url: person.url,
 | 
			
		||||
			fields,
 | 
			
		||||
			isBot: isBot,
 | 
			
		||||
			...services,
 | 
			
		||||
			isBot,
 | 
			
		||||
			isCat: (person as any).isCat === true
 | 
			
		||||
		}) as IRemoteUser;
 | 
			
		||||
	} catch (e) {
 | 
			
		||||
| 
						 | 
				
			
			@ -332,9 +332,7 @@ export async function updatePerson(uri: string, resolver?: Resolver, hint?: obje
 | 
			
		|||
 | 
			
		||||
	const emojiNames = emojis.map(emoji => emoji.name);
 | 
			
		||||
 | 
			
		||||
	const fields = await extractFields(person.attachment).catch(e => {
 | 
			
		||||
		console.log(`cat not extract fields: ${e}`);
 | 
			
		||||
	});
 | 
			
		||||
	const { fields, services } = analyzeAttachments(person.attachment);
 | 
			
		||||
 | 
			
		||||
	const updates = {
 | 
			
		||||
		lastFetchedAt: new Date(),
 | 
			
		||||
| 
						 | 
				
			
			@ -350,6 +348,7 @@ export async function updatePerson(uri: string, resolver?: Resolver, hint?: obje
 | 
			
		|||
		url: person.url,
 | 
			
		||||
		endpoints: person.endpoints,
 | 
			
		||||
		fields,
 | 
			
		||||
		...services,
 | 
			
		||||
		isBot: object.type == 'Service',
 | 
			
		||||
		isCat: (person as any).isCat === true,
 | 
			
		||||
		isLocked: person.manuallyApprovesFollowers,
 | 
			
		||||
| 
						 | 
				
			
			@ -413,16 +412,61 @@ export async function resolvePerson(uri: string, verifier?: string, resolver?: R
 | 
			
		|||
	return await createPerson(uri, resolver);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export async function extractFields(attachments: ITag[]) {
 | 
			
		||||
	if (!attachments) return [];
 | 
			
		||||
const isPropertyValue = (x: {
 | 
			
		||||
		type: string,
 | 
			
		||||
		name?: string,
 | 
			
		||||
		value?: string
 | 
			
		||||
	}) =>
 | 
			
		||||
		x &&
 | 
			
		||||
		x.type === 'PropertyValue' &&
 | 
			
		||||
		typeof x.name === 'string' &&
 | 
			
		||||
		typeof x.value === 'string';
 | 
			
		||||
 | 
			
		||||
	return attachments.filter(a => a.type === 'PropertyValue' && a.name && a.value)
 | 
			
		||||
		.map(a => {
 | 
			
		||||
			return {
 | 
			
		||||
				name: a.name,
 | 
			
		||||
				value: htmlToMFM(a.value)
 | 
			
		||||
			};
 | 
			
		||||
		});
 | 
			
		||||
const services: {
 | 
			
		||||
		[x: string]: (id: string, username: string) => any
 | 
			
		||||
	} = {
 | 
			
		||||
	'misskey:authentication:twitter': (userId, screenName) => ({ userId, screenName }),
 | 
			
		||||
	'misskey:authentication:github': (id, login) => ({ id, login }),
 | 
			
		||||
	'misskey:authentication:discord': (id, name) => $discord(id, name)
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
const $discord = (id: string, name: string) => {
 | 
			
		||||
	if (typeof name !== 'string')
 | 
			
		||||
		name = 'unknown#0000';
 | 
			
		||||
	const [username, discriminator] = name.split('#');
 | 
			
		||||
	return { id, username, discriminator };
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
function addService(target: { [x: string]: any }, source: IIdentifier) {
 | 
			
		||||
	const service = services[source.name];
 | 
			
		||||
 | 
			
		||||
	if (typeof source.value !== 'string')
 | 
			
		||||
		source.value = 'unknown';
 | 
			
		||||
 | 
			
		||||
	const [id, username] = source.value.split('@');
 | 
			
		||||
 | 
			
		||||
	if (service)
 | 
			
		||||
		target[source.name.split(':')[2]] = service(id, username);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export function analyzeAttachments(attachments: ITag[]) {
 | 
			
		||||
	const fields: {
 | 
			
		||||
		name: string,
 | 
			
		||||
		value: string
 | 
			
		||||
	}[] = [];
 | 
			
		||||
	const services: { [x: string]: any } = {};
 | 
			
		||||
 | 
			
		||||
	if (Array.isArray(attachments))
 | 
			
		||||
		for (const attachment of attachments.filter(isPropertyValue))
 | 
			
		||||
			if (isPropertyValue(attachment.identifier))
 | 
			
		||||
				addService(services, attachment.identifier);
 | 
			
		||||
			else
 | 
			
		||||
				fields.push({
 | 
			
		||||
					name: attachment.name,
 | 
			
		||||
					value: htmlToMFM(attachment.value)
 | 
			
		||||
				});
 | 
			
		||||
 | 
			
		||||
	return { fields, services };
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export async function updateFeatured(userId: mongo.ObjectID) {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,4 +1,5 @@
 | 
			
		|||
import { IIcon } from './icon';
 | 
			
		||||
import { IIdentifier } from './identifier';
 | 
			
		||||
 | 
			
		||||
/***
 | 
			
		||||
 * tag (ActivityPub)
 | 
			
		||||
| 
						 | 
				
			
			@ -10,4 +11,5 @@ export type ITag = {
 | 
			
		|||
	value?: string;
 | 
			
		||||
	updated?: Date;
 | 
			
		||||
	icon?: IIcon;
 | 
			
		||||
	identifier?: IIdentifier;
 | 
			
		||||
};
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -7,6 +7,7 @@ import parse from '../../../mfm/parse';
 | 
			
		|||
import DriveFile from '../../../models/drive-file';
 | 
			
		||||
import { getEmojis } from './note';
 | 
			
		||||
import renderEmoji from './emoji';
 | 
			
		||||
import { IIdentifier } from '../models/identifier';
 | 
			
		||||
 | 
			
		||||
export default async (user: ILocalUser) => {
 | 
			
		||||
	const id = `${config.url}/users/${user._id}`;
 | 
			
		||||
| 
						 | 
				
			
			@ -20,14 +21,20 @@ export default async (user: ILocalUser) => {
 | 
			
		|||
		type: string,
 | 
			
		||||
		name: string,
 | 
			
		||||
		value: string,
 | 
			
		||||
		verified_at?: string
 | 
			
		||||
		verified_at?: string,
 | 
			
		||||
		identifier?: IIdentifier
 | 
			
		||||
	}[] = [];
 | 
			
		||||
 | 
			
		||||
	if (user.twitter) {
 | 
			
		||||
		attachment.push({
 | 
			
		||||
			type: 'PropertyValue',
 | 
			
		||||
			name: 'Twitter',
 | 
			
		||||
			value: `<a href="https://twitter.com/intent/user?user_id=${user.twitter.userId}" rel="me nofollow noopener" target="_blank"><span>@${user.twitter.screenName}</span></a>`
 | 
			
		||||
			value: `<a href="https://twitter.com/intent/user?user_id=${user.twitter.userId}" rel="me nofollow noopener" target="_blank"><span>@${user.twitter.screenName}</span></a>`,
 | 
			
		||||
			identifier: {
 | 
			
		||||
				type: 'PropertyValue',
 | 
			
		||||
				name: 'misskey:authentication:twitter',
 | 
			
		||||
				value: `${user.twitter.userId}@${user.twitter.screenName}`
 | 
			
		||||
			}
 | 
			
		||||
		});
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -35,7 +42,12 @@ export default async (user: ILocalUser) => {
 | 
			
		|||
		attachment.push({
 | 
			
		||||
			type: 'PropertyValue',
 | 
			
		||||
			name: 'GitHub',
 | 
			
		||||
			value: `<a href="https://github.com/${user.github.login}" rel="me nofollow noopener" target="_blank"><span>@${user.github.login}</span></a>`
 | 
			
		||||
			value: `<a href="https://github.com/${user.github.login}" rel="me nofollow noopener" target="_blank"><span>@${user.github.login}</span></a>`,
 | 
			
		||||
			identifier: {
 | 
			
		||||
				type: 'PropertyValue',
 | 
			
		||||
				name: 'misskey:authentication:github',
 | 
			
		||||
				value: `${user.github.id}@${user.github.login}`
 | 
			
		||||
			}
 | 
			
		||||
		});
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -43,7 +55,12 @@ export default async (user: ILocalUser) => {
 | 
			
		|||
		attachment.push({
 | 
			
		||||
			type: 'PropertyValue',
 | 
			
		||||
			name: 'Discord',
 | 
			
		||||
			value: `<a href="https://discordapp.com/users/${user.discord.id}" rel="me nofollow noopener" target="_blank"><span>${user.discord.username}#${user.discord.discriminator}</span></a>`
 | 
			
		||||
			value: `<a href="https://discordapp.com/users/${user.discord.id}" rel="me nofollow noopener" target="_blank"><span>${user.discord.username}#${user.discord.discriminator}</span></a>`,
 | 
			
		||||
			identifier: {
 | 
			
		||||
				type: 'PropertyValue',
 | 
			
		||||
				name: 'misskey:authentication:discord',
 | 
			
		||||
				value: `${user.discord.id}@${user.discord.username}#${user.discord.discriminator}`
 | 
			
		||||
			}
 | 
			
		||||
		});
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue