外部サービス認証情報の配信 (#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:
Acid Chicken (硫酸鶏) 2019-01-24 17:33:39 +09:00 committed by syuilo
parent 4632eecb76
commit e2f7e82cac
4 changed files with 88 additions and 20 deletions

View file

@ -0,0 +1,5 @@
export type IIdentifier = {
type: string;
name: string;
value: string;
};

View file

@ -19,6 +19,7 @@ import getDriveFileUrl from '../../../misc/get-drive-file-url';
import { IEmoji } from '../../../models/emoji'; import { IEmoji } from '../../../models/emoji';
import { ITag } from './tag'; import { ITag } from './tag';
import Following from '../../../models/following'; import Following from '../../../models/following';
import { IIdentifier } from './identifier';
const log = debug('misskey:activitypub'); 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 host = toUnicode(new URL(object.id).hostname.toLowerCase());
const fields = await extractFields(person.attachment).catch(e => { const { fields, services } = analyzeAttachments(person.attachment);
console.log(`cat not extract fields: ${e}`);
});
const isBot = object.type == 'Service'; const isBot = object.type == 'Service';
@ -171,7 +170,8 @@ export async function createPerson(uri: string, resolver?: Resolver): Promise<IU
uri: person.id, uri: person.id,
url: person.url, url: person.url,
fields, fields,
isBot: isBot, ...services,
isBot,
isCat: (person as any).isCat === true isCat: (person as any).isCat === true
}) as IRemoteUser; }) as IRemoteUser;
} catch (e) { } catch (e) {
@ -332,9 +332,7 @@ export async function updatePerson(uri: string, resolver?: Resolver, hint?: obje
const emojiNames = emojis.map(emoji => emoji.name); const emojiNames = emojis.map(emoji => emoji.name);
const fields = await extractFields(person.attachment).catch(e => { const { fields, services } = analyzeAttachments(person.attachment);
console.log(`cat not extract fields: ${e}`);
});
const updates = { const updates = {
lastFetchedAt: new Date(), lastFetchedAt: new Date(),
@ -350,6 +348,7 @@ export async function updatePerson(uri: string, resolver?: Resolver, hint?: obje
url: person.url, url: person.url,
endpoints: person.endpoints, endpoints: person.endpoints,
fields, fields,
...services,
isBot: object.type == 'Service', isBot: object.type == 'Service',
isCat: (person as any).isCat === true, isCat: (person as any).isCat === true,
isLocked: person.manuallyApprovesFollowers, isLocked: person.manuallyApprovesFollowers,
@ -413,16 +412,61 @@ export async function resolvePerson(uri: string, verifier?: string, resolver?: R
return await createPerson(uri, resolver); return await createPerson(uri, resolver);
} }
export async function extractFields(attachments: ITag[]) { const isPropertyValue = (x: {
if (!attachments) return []; 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) const services: {
.map(a => { [x: string]: (id: string, username: string) => any
return { } = {
name: a.name, 'misskey:authentication:twitter': (userId, screenName) => ({ userId, screenName }),
value: htmlToMFM(a.value) '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) { export async function updateFeatured(userId: mongo.ObjectID) {

View file

@ -1,4 +1,5 @@
import { IIcon } from './icon'; import { IIcon } from './icon';
import { IIdentifier } from './identifier';
/*** /***
* tag (ActivityPub) * tag (ActivityPub)
@ -10,4 +11,5 @@ export type ITag = {
value?: string; value?: string;
updated?: Date; updated?: Date;
icon?: IIcon; icon?: IIcon;
identifier?: IIdentifier;
}; };

View file

@ -7,6 +7,7 @@ import parse from '../../../mfm/parse';
import DriveFile from '../../../models/drive-file'; import DriveFile from '../../../models/drive-file';
import { getEmojis } from './note'; import { getEmojis } from './note';
import renderEmoji from './emoji'; import renderEmoji from './emoji';
import { IIdentifier } from '../models/identifier';
export default async (user: ILocalUser) => { export default async (user: ILocalUser) => {
const id = `${config.url}/users/${user._id}`; const id = `${config.url}/users/${user._id}`;
@ -20,14 +21,20 @@ export default async (user: ILocalUser) => {
type: string, type: string,
name: string, name: string,
value: string, value: string,
verified_at?: string verified_at?: string,
identifier?: IIdentifier
}[] = []; }[] = [];
if (user.twitter) { if (user.twitter) {
attachment.push({ attachment.push({
type: 'PropertyValue', type: 'PropertyValue',
name: 'Twitter', 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({ attachment.push({
type: 'PropertyValue', type: 'PropertyValue',
name: 'GitHub', 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({ attachment.push({
type: 'PropertyValue', type: 'PropertyValue',
name: 'Discord', 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}`
}
}); });
} }