Merge pull request #1346 from akihikodaki/user
Implement Activity Streams representation of user
This commit is contained in:
commit
55f716fc62
4 changed files with 63 additions and 55 deletions
1
src/crypto_key.d.ts
vendored
1
src/crypto_key.d.ts
vendored
|
@ -1 +1,2 @@
|
||||||
|
export function extractPublic(keypair: String): String;
|
||||||
export function generate(): String;
|
export function generate(): String;
|
||||||
|
|
|
@ -278,61 +278,6 @@ export const pack = (
|
||||||
resolve(_user);
|
resolve(_user);
|
||||||
});
|
});
|
||||||
|
|
||||||
/**
|
|
||||||
* Pack a user for ActivityPub
|
|
||||||
*
|
|
||||||
* @param user target
|
|
||||||
* @return Packed user
|
|
||||||
*/
|
|
||||||
export const packForAp = (
|
|
||||||
user: string | mongo.ObjectID | IUser
|
|
||||||
) => new Promise<any>(async (resolve, reject) => {
|
|
||||||
|
|
||||||
let _user: any;
|
|
||||||
|
|
||||||
const fields = {
|
|
||||||
// something
|
|
||||||
};
|
|
||||||
|
|
||||||
// Populate the user if 'user' is ID
|
|
||||||
if (mongo.ObjectID.prototype.isPrototypeOf(user)) {
|
|
||||||
_user = await User.findOne({
|
|
||||||
_id: user
|
|
||||||
}, { fields });
|
|
||||||
} else if (typeof user === 'string') {
|
|
||||||
_user = await User.findOne({
|
|
||||||
_id: new mongo.ObjectID(user)
|
|
||||||
}, { fields });
|
|
||||||
} else {
|
|
||||||
_user = deepcopy(user);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!_user) return reject('invalid user arg.');
|
|
||||||
|
|
||||||
const userUrl = `${config.url}/@@${_user._id}`;
|
|
||||||
|
|
||||||
resolve({
|
|
||||||
"@context": ["https://www.w3.org/ns/activitystreams", {
|
|
||||||
"@language": "ja"
|
|
||||||
}],
|
|
||||||
"type": "Person",
|
|
||||||
"id": userUrl,
|
|
||||||
"following": `${userUrl}/following.json`,
|
|
||||||
"followers": `${userUrl}/followers.json`,
|
|
||||||
"liked": `${userUrl}/liked.json`,
|
|
||||||
"inbox": `${userUrl}/inbox.json`,
|
|
||||||
"outbox": `${userUrl}/outbox.json`,
|
|
||||||
"sharedInbox": `${config.url}/inbox`,
|
|
||||||
"url": `${config.url}/@${_user.username}`,
|
|
||||||
"preferredUsername": _user.username,
|
|
||||||
"name": _user.name,
|
|
||||||
"summary": _user.description,
|
|
||||||
"icon": [
|
|
||||||
`${config.drive_url}/${_user.avatarId}`
|
|
||||||
]
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
function img(url) {
|
function img(url) {
|
||||||
return {
|
return {
|
||||||
|
|
60
src/server/activitypub.ts
Normal file
60
src/server/activitypub.ts
Normal file
|
@ -0,0 +1,60 @@
|
||||||
|
import config from '../conf';
|
||||||
|
import { extractPublic } from '../crypto_key';
|
||||||
|
import parseAcct from '../common/user/parse-acct';
|
||||||
|
import User, { ILocalAccount } from '../models/user';
|
||||||
|
const express = require('express');
|
||||||
|
|
||||||
|
const app = express();
|
||||||
|
|
||||||
|
app.get('/@:user', async (req, res, next) => {
|
||||||
|
const accepted = req.accepts(['html', 'application/activity+json', 'application/ld+json']);
|
||||||
|
if (!['application/activity+json', 'application/ld+json'].includes(accepted)) {
|
||||||
|
return next();
|
||||||
|
}
|
||||||
|
|
||||||
|
const { username, host } = parseAcct(req.params.user);
|
||||||
|
if (host !== null) {
|
||||||
|
return res.send(422);
|
||||||
|
}
|
||||||
|
|
||||||
|
const user = await User.findOne({
|
||||||
|
usernameLower: username.toLowerCase(),
|
||||||
|
host: null
|
||||||
|
});
|
||||||
|
if (user === null) {
|
||||||
|
return res.send(404);
|
||||||
|
}
|
||||||
|
|
||||||
|
const id = `${config.url}/@${user.username}`;
|
||||||
|
|
||||||
|
if (username !== user.username) {
|
||||||
|
return res.redirect(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
res.json({
|
||||||
|
'@context': [
|
||||||
|
'https://www.w3.org/ns/activitystreams',
|
||||||
|
'https://w3id.org/security/v1'
|
||||||
|
],
|
||||||
|
type: 'Person',
|
||||||
|
id,
|
||||||
|
preferredUsername: user.username,
|
||||||
|
name: user.name,
|
||||||
|
summary: user.description,
|
||||||
|
icon: user.avatarId && {
|
||||||
|
type: 'Image',
|
||||||
|
url: `${config.drive_url}/${user.avatarId}`
|
||||||
|
},
|
||||||
|
image: user.bannerId && {
|
||||||
|
type: 'Image',
|
||||||
|
url: `${config.drive_url}/${user.bannerId}`
|
||||||
|
},
|
||||||
|
publicKey: {
|
||||||
|
type: 'Key',
|
||||||
|
owner: id,
|
||||||
|
publicKeyPem: extractPublic((user.account as ILocalAccount).keypair)
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
export default app;
|
|
@ -9,6 +9,7 @@ import * as express from 'express';
|
||||||
import * as morgan from 'morgan';
|
import * as morgan from 'morgan';
|
||||||
import Accesses from 'accesses';
|
import Accesses from 'accesses';
|
||||||
|
|
||||||
|
import activityPub from './activitypub';
|
||||||
import log from './log-request';
|
import log from './log-request';
|
||||||
import config from '../conf';
|
import config from '../conf';
|
||||||
|
|
||||||
|
@ -53,6 +54,7 @@ app.use((req, res, next) => {
|
||||||
*/
|
*/
|
||||||
app.use('/api', require('./api'));
|
app.use('/api', require('./api'));
|
||||||
app.use('/files', require('./file'));
|
app.use('/files', require('./file'));
|
||||||
|
app.use(activityPub);
|
||||||
app.use(require('./web'));
|
app.use(require('./web'));
|
||||||
|
|
||||||
function createServer() {
|
function createServer() {
|
||||||
|
|
Loading…
Reference in a new issue