automatic actor creation on finger, user lookup. followers collection endpoint populated from inbox activity side effects
This commit is contained in:
parent
0a3c758ad7
commit
e4c150b840
5 changed files with 71 additions and 49 deletions
|
@ -2,14 +2,20 @@ const utils = require('../utils')
|
|||
const crypto = require('crypto')
|
||||
|
||||
module.exports = async function dbSetup (db, domain) {
|
||||
// inbox
|
||||
await db.collection('streams').createIndex({
|
||||
_target: 1,
|
||||
_id: -1,
|
||||
})
|
||||
// outbox
|
||||
await db.collection('streams').createIndex({
|
||||
actor: 1,
|
||||
_id: -1,
|
||||
})
|
||||
// object lookup
|
||||
await db.collection('objects').createIndex({
|
||||
id: 1
|
||||
})
|
||||
const dummyUser = await utils.createLocalActor('dummy', 'Person')
|
||||
await db.collection('objects').findOneAndReplace(
|
||||
{preferredUsername: 'dummy'},
|
||||
|
|
|
@ -10,15 +10,8 @@ router.get('/:name', async function (req, res) {
|
|||
return res.status(400).send('Bad request.');
|
||||
}
|
||||
else {
|
||||
let objs = req.app.get('objs');
|
||||
let db = req.app.get('db')
|
||||
const id = utils.userNameToIRI(name)
|
||||
console.log(`looking up '${id}'`)
|
||||
const user = await db.collection('objects')
|
||||
.find({type: 'Person', id: id})
|
||||
.limit(1)
|
||||
.project({_id: 0, _meta: 0})
|
||||
.next()
|
||||
const user = await utils.getOrCreateActor(name, db)
|
||||
if (user) {
|
||||
return res.json(toJSONLD(user))
|
||||
}
|
||||
|
@ -26,33 +19,28 @@ router.get('/:name', async function (req, res) {
|
|||
}
|
||||
});
|
||||
|
||||
// router.get('/:name/followers', function (req, res) {
|
||||
// let name = req.params.name;
|
||||
// if (!name) {
|
||||
// return res.status(400).send('Bad request.');
|
||||
// }
|
||||
// else {
|
||||
// let db = req.app.get('db');
|
||||
// let domain = req.app.get('domain');
|
||||
// let result = db.prepare('select followers from accounts where name = ?').get(`${name}@${domain}`);
|
||||
// console.log(result);
|
||||
// result.followers = result.followers || '[]';
|
||||
// let followers = JSON.parse(result.followers);
|
||||
// let followersCollection = {
|
||||
// "type":"OrderedCollection",
|
||||
// "totalItems":followers.length,
|
||||
// "id":`https://${domain}/u/${name}/followers`,
|
||||
// "first": {
|
||||
// "type":"OrderedCollectionPage",
|
||||
// "totalItems":followers.length,
|
||||
// "partOf":`https://${domain}/u/${name}/followers`,
|
||||
// "orderedItems": followers,
|
||||
// "id":`https://${domain}/u/${name}/followers?page=1`
|
||||
// },
|
||||
// "@context":["https://www.w3.org/ns/activitystreams"]
|
||||
// };
|
||||
// res.json(toJSONLD(followersCollection));
|
||||
// }
|
||||
// });
|
||||
router.get('/:name/followers', function (req, res) {
|
||||
let name = req.params.name;
|
||||
if (!name) {
|
||||
return res.status(400).send('Bad request.');
|
||||
}
|
||||
const db = req.app.get('db')
|
||||
db.collection('streams')
|
||||
.find({
|
||||
type: 'Follow',
|
||||
_target: name,
|
||||
'object.id': utils.usernameToIRI(name)
|
||||
})
|
||||
.project({_id: 0, actor: 1})
|
||||
.toArray()
|
||||
.then(follows => {
|
||||
const followers = follows.map(utils.actorFromActivity)
|
||||
return res.json(utils.arrayToCollection(followers))
|
||||
})
|
||||
.catch(err => {
|
||||
console.log(err)
|
||||
return res.status(500).send()
|
||||
})
|
||||
});
|
||||
|
||||
module.exports = router;
|
||||
|
|
|
@ -13,12 +13,7 @@ router.get('/', function (req, res) {
|
|||
return res.status(400).send('Requested user is not from this domain')
|
||||
}
|
||||
let db = req.app.get('db');
|
||||
const userId = utils.userNameToIRI(acct[1]);
|
||||
db.collection('objects')
|
||||
.find({id: userId})
|
||||
.limit(1)
|
||||
.project({_id: 0})
|
||||
.next()
|
||||
utils.getOrCreateActor(acct[1], db)
|
||||
.then(result => {
|
||||
if (!result) {
|
||||
return res.status(404).send(`${acct[1]}@${acct[2]} not found`)
|
||||
|
@ -29,7 +24,7 @@ router.get('/', function (req, res) {
|
|||
{
|
||||
'rel': 'self',
|
||||
'type': 'application/activity+json',
|
||||
'href': userId
|
||||
'href': result.id
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
|
@ -1,9 +1,10 @@
|
|||
const crypto = require('crypto')
|
||||
const {promisify} = require('util')
|
||||
const {ASContext} = require('./consts')
|
||||
module.exports.validators = require('./validators');
|
||||
const config = require('../config.json')
|
||||
|
||||
module.exports.validators = require('./validators');
|
||||
|
||||
function isObject(value) {
|
||||
return value && typeof value === 'object' && value.constructor === Object
|
||||
}
|
||||
|
@ -34,13 +35,13 @@ module.exports.arrayToCollection = function (arr, ordered) {
|
|||
}
|
||||
}
|
||||
|
||||
function userNameToIRI (user) {
|
||||
function usernameToIRI (user) {
|
||||
return `https://${config.DOMAIN}/u/${user}`
|
||||
}
|
||||
module.exports.userNameToIRI = userNameToIRI
|
||||
module.exports.usernameToIRI = usernameToIRI
|
||||
|
||||
const generateKeyPairPromise = promisify(crypto.generateKeyPair)
|
||||
module.exports.createLocalActor = function (name, type) {
|
||||
function createLocalActor (name, type) {
|
||||
return generateKeyPairPromise('rsa', {
|
||||
modulusLength: 4096,
|
||||
publicKeyEncoding: {
|
||||
|
@ -54,7 +55,7 @@ module.exports.createLocalActor = function (name, type) {
|
|||
passphrase: config.KEYPASS
|
||||
}
|
||||
}).then(pair => {
|
||||
const actorBase = userNameToIRI(name);
|
||||
const actorBase = usernameToIRI(name);
|
||||
return {
|
||||
_meta: {
|
||||
privateKey: pair.privateKey,
|
||||
|
@ -81,3 +82,35 @@ module.exports.createLocalActor = function (name, type) {
|
|||
}
|
||||
})
|
||||
}
|
||||
module.exports.createLocalActor = createLocalActor
|
||||
|
||||
async function getOrCreateActor(preferredUsername, db) {
|
||||
const id = usernameToIRI(preferredUsername)
|
||||
let user = await db.collection('objects')
|
||||
.find({id: id})
|
||||
.limit(1)
|
||||
.project({_id: 0, _meta: 0})
|
||||
.next()
|
||||
if (user) {
|
||||
return user
|
||||
}
|
||||
// auto create groups whenever an unknown actor is referenced
|
||||
user = await createLocalActor(preferredUsername, 'Group')
|
||||
await db.collection('objects').insertOne(user)
|
||||
// only executed on success
|
||||
delete user._meta
|
||||
delete user._id
|
||||
return user
|
||||
}
|
||||
module.exports.getOrCreateActor = getOrCreateActor
|
||||
|
||||
function actorFromActivity (activity) {
|
||||
if (Object.prototype.toString.call(activity.actor) === '[object String]') {
|
||||
return activity.actor
|
||||
}
|
||||
if (activity.actor.type === 'Link') {
|
||||
return activity.actor.href
|
||||
}
|
||||
return activity.actor.id
|
||||
}
|
||||
module.exports.actorFromActivity = actorFromActivity
|
|
@ -28,7 +28,7 @@ module.exports.outboxActivity = function outboxActivity (req, res, next) {
|
|||
if (!validateObject(req.body)) {
|
||||
return res.status(400).send('Invalid activity')
|
||||
}
|
||||
const newID = ObjectId()
|
||||
const newID = new ObjectId()
|
||||
req.body = {
|
||||
_id: newID,
|
||||
'@context': ASContext,
|
||||
|
|
Loading…
Reference in a new issue