gancio-upstream/server/federation/users.js

191 lines
7 KiB
JavaScript
Raw Normal View History

2023-01-10 18:16:11 +01:00
const { Event, Place, APUser, Tag } = require('../api/models/models')
const escape = require('lodash/escape')
2021-09-27 10:42:17 +02:00
const config = require('../config')
2021-03-05 14:22:38 +01:00
const log = require('../log')
2022-02-26 21:27:40 +01:00
const settingsController = require('../api/controller/settings')
const { DateTime } = require('luxon')
2024-01-19 00:42:16 +01:00
const Helpers = require('./helpers')
2024-02-28 22:37:57 +01:00
const get = require('lodash/get')
2019-07-30 18:32:26 +02:00
module.exports = {
2019-12-04 01:18:05 +01:00
get (req, res) {
log.debug('[FEDI] Get actor')
// if (req.accepts('html')) { return res.redirect(301, '/') }
2022-02-26 21:27:40 +01:00
const settings = settingsController.settings
2019-07-30 18:32:26 +02:00
const name = req.params.name
2019-10-28 17:33:20 +01:00
if (!name) { return res.status(400).send('Bad request.') }
2020-06-14 20:58:23 +02:00
2022-02-26 21:27:40 +01:00
if (name !== settings.instance_name) { return res.status(404).send(`No record found for ${escape(name)}`) }
2019-07-30 18:32:26 +02:00
const ret = {
'@context': [
'https://www.w3.org/ns/activitystreams',
'https://w3id.org/security/v1',
{
toot: 'http://joinmastodon.org/ns#',
// A property-value pair, e.g. representing a feature of a product or place. We use this to publish this very same instance
// https://docs.joinmastodon.org/spec/activitypub/#PropertyValue
schema: 'http://schema.org#',
ProperyValue: 'schema:PropertyValue',
value: 'schema:value',
// https://docs.joinmastodon.org/spec/activitypub/#discoverable
discoverable: 'toot:discoverable',
indexable: 'toot:indexable'
}
2019-07-30 18:32:26 +02:00
],
id: `${config.baseurl}/federation/u/${name}`,
type: 'Application',
summary: config.description,
name: settings.instance_name,
2024-02-28 15:07:52 +01:00
preferredUsername: name,
2019-07-30 18:32:26 +02:00
inbox: `${config.baseurl}/federation/u/${name}/inbox`,
2020-06-14 20:58:23 +02:00
outbox: `${config.baseurl}/federation/u/${name}/outbox`,
2023-12-22 20:58:38 +01:00
manuallyApprovesFollowers: false,
endpoints: { sharedInbox: `${config.baseurl}/federation/u/${name}/inbox` },
discoverable: true,
indexable: true,
attachment: [
{
type: 'PropertyValue',
name: 'Website',
value: `<a href='${config.baseurl}'>${config.baseurl}</a>`
}
],
2019-09-11 19:12:24 +02:00
icon: {
type: 'Image',
2019-09-19 23:12:56 +02:00
mediaType: 'image/png',
2020-07-07 21:56:49 +02:00
url: config.baseurl + '/logo.png'
2019-09-11 19:12:24 +02:00
},
2023-12-28 00:47:31 +01:00
summary: settings.description,
2019-07-30 18:32:26 +02:00
publicKey: {
id: `${config.baseurl}/federation/u/${name}#main-key`,
owner: `${config.baseurl}/federation/u/${name}`,
2022-02-26 21:27:40 +01:00
publicKeyPem: settings.publicKey
},
url: config.baseurl,
2019-07-30 18:32:26 +02:00
}
2019-08-01 15:18:45 +02:00
res.type('application/activity+json; charset=utf-8')
2019-07-30 18:32:26 +02:00
res.json(ret)
},
2024-02-28 15:07:52 +01:00
// async followers (req, res) {
// const settings = settingsController.settings
// const name = req.params.name
// const page = req.query.page
// log.debug(`Retrieve ${name} followers`)
// if (!name) { return res.status(400).send('Bad request.') }
// if (name !== settings.instance_name) {
// log.warn('No record found')
// return res.status(404).send(`No record found for ${escape(name)}`)
// }
// const followers = await APUser.findAll({ where: { follower: true } })
// res.type('application/activity+json; charset=utf-8')
// if (!page) {
// log.debug('No pagination')
// return res.json({
// '@context': 'https://www.w3.org/ns/activitystreams',
// id: `${settings.baseurl}/federation/u/${name}/followers`,
// type: 'OrderedCollection',
// totalItems: followers.length,
// first: `${settings.baseurl}/federation/u/${name}/followers?page=true`
// // last: `${config.baseurl}/federation/u/${name}/followers?page=true`,
// // orderedItems: followers.map(f => f.ap_id)
// })
// }
// return res.json({
// '@context': 'https://www.w3.org/ns/activitystreams',
// id: `${settings.baseurl}/federation/u/${name}/followers?page=${page}`,
// type: 'OrderedCollectionPage',
// totalItems: followers.length,
// partOf: `${settings.baseurl}/federation/u/${name}/followers`,
// orderedItems: followers.map(f => f.ap_id)
// })
// },
2019-09-11 19:12:24 +02:00
async remove (req, res) {
2024-02-28 22:37:57 +01:00
const ap_id = get(req.body, 'object.id', req.body.object)
const ap_actor = await APUser.findOne({ where: { ap_id }})
if (!ap_actor) {
2024-02-28 22:37:57 +01:00
log.info(`[FEDI] Delete of unknown object ${ap_id}`)
return res.status(404).send('Not found')
}
2019-09-11 19:12:24 +02:00
// check if fedi_user that requested resource removal
// is the same that created the resource at first place
if (res.locals.fedi_user.ap_id === ap_actor.ap_id) {
await ap_actor.destroy()
log.info(`[FEDI] Actor ${ap_actor.ap_id} removed`)
res.sendStatus(201)
} else {
log.info(`[FEDI] ${res.locals.fedi_user.ap_id} is trying to remove ${ap_actor.ap_id}?`)
res.sendStatus(403)
2019-07-30 18:32:26 +02:00
}
},
2019-09-11 19:12:24 +02:00
2019-07-31 01:03:21 +02:00
async outbox (req, res) {
2019-07-30 18:53:59 +02:00
const name = req.params.name
const page = parseInt(req.query?.page)
const events_per_page = 10
2022-02-26 21:27:40 +01:00
const settings = settingsController.settings
2019-10-28 17:33:20 +01:00
2021-03-05 14:22:38 +01:00
if (!name) {
log.info('[AP] Bad /outbox request')
return res.status(400).send('Bad request.')
}
2022-02-26 21:27:40 +01:00
if (name !== settings.instance_name) {
2024-01-19 00:42:16 +01:00
log.info(`[FEDI] No record found for ${name} (applicationActor is ${settings.instance_name})`)
return res.status(404).send(`No record found for ${escape(name)}`)
2021-03-05 14:22:38 +01:00
}
2019-07-31 01:03:21 +02:00
2024-01-19 00:42:16 +01:00
const n_events = await Event.count({ where: { is_visible: true, ap_id: null }})
let events = []
log.debug(`[FEDI] GET /outbox, should return all events from this instance: ${n_events}`)
2019-07-31 01:03:21 +02:00
// https://www.w3.org/TR/activitypub/#outbox
2019-09-11 19:12:24 +02:00
res.type('application/activity+json; charset=utf-8')
const last_page = Math.ceil(n_events/10)
if (page) {
2024-01-19 00:42:16 +01:00
events = await Event.findAll({
where: { is_visible: true, ap_id: null },
include: [{ model: Tag, required: false }, Place],
limit: events_per_page,
offset: (page-1)*events_per_page,
order: [['start_datetime', 'DESC']],
})
return res.json({
2024-01-19 00:42:16 +01:00
'@context': Helpers['@context'],
id: `${config.baseurl}/federation/u/${name}/outbox?page=${page}`,
type: 'OrderedCollectionPage',
2024-01-19 00:42:16 +01:00
totalItems: n_events,
partOf: `${config.baseurl}/federation/u/${name}/outbox`,
...( page > 1 && { prev: `${config.baseurl}/federation/u/${name}/outbox?page=${page-1}`}),
...( page !== last_page && { next: `${config.baseurl}/federation/u/${name}/outbox?page=${page+1}`}),
orderedItems: events.map(e => ({
id: `${config.baseurl}/federation/m/${e.id}#create`,
type: 'Create',
to: 'https://www.w3.org/ns/activitystreams#Public',
published: new DateTime(e.createdAt).toISO(),
actor: `${config.baseurl}/federation/u/${name}`,
2023-12-28 00:47:31 +01:00
object: e.toAP(settings)
}))
})
} else {
2021-03-05 14:22:38 +01:00
return res.json({
'@context': 'https://www.w3.org/ns/activitystreams',
2022-03-07 17:47:31 +01:00
id: `${settings.baseurl}/federation/u/${name}/outbox`,
2021-03-05 14:22:38 +01:00
type: 'OrderedCollection',
totalItems: n_events,
first: `${settings.baseurl}/federation/u/${name}/outbox?page=1`,
last: `${settings.baseurl}/federation/u/${name}/outbox?page=${last_page}`
2021-03-05 14:22:38 +01:00
})
}
2019-07-30 18:32:26 +02:00
}
2019-07-30 18:47:17 +02:00
}