mirror of
https://github.com/NodeBB/NodeBB.git
synced 2025-10-26 08:36:12 +01:00
feat: ability to view federated profiles via url manipulation
This commit is contained in:
32
src/activitypub/helpers.js
Normal file
32
src/activitypub/helpers.js
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
'use strict';
|
||||||
|
|
||||||
|
const request = require('request-promise-native');
|
||||||
|
|
||||||
|
const Helpers = module.exports;
|
||||||
|
|
||||||
|
Helpers.query = async (id) => {
|
||||||
|
const [username, hostname] = id.split('@');
|
||||||
|
if (!username || !hostname) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Make a webfinger query to retrieve routing information
|
||||||
|
const response = await request(`https://${hostname}/.well-known/webfinger?resource=acct:${id}`, {
|
||||||
|
simple: false,
|
||||||
|
resolveWithFullResponse: true,
|
||||||
|
json: true,
|
||||||
|
});
|
||||||
|
|
||||||
|
if (response.statusCode !== 200 || !response.body.hasOwnProperty('links')) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Parse links to find actor endpoint
|
||||||
|
let actorUri = response.body.links.filter(link => link.type === 'application/activity+json' && link.rel === 'self');
|
||||||
|
if (actorUri.length) {
|
||||||
|
actorUri = actorUri.pop();
|
||||||
|
({ href: actorUri } = actorUri);
|
||||||
|
}
|
||||||
|
|
||||||
|
return { username, hostname, actorUri };
|
||||||
|
};
|
||||||
@@ -3,11 +3,32 @@
|
|||||||
const { generateKeyPairSync } = require('crypto');
|
const { generateKeyPairSync } = require('crypto');
|
||||||
|
|
||||||
const winston = require('winston');
|
const winston = require('winston');
|
||||||
|
const request = require('request-promise-native');
|
||||||
|
|
||||||
const db = require('./database');
|
const db = require('../database');
|
||||||
|
const helpers = require('./helpers');
|
||||||
|
|
||||||
const ActivityPub = module.exports;
|
const ActivityPub = module.exports;
|
||||||
|
|
||||||
|
ActivityPub.getActor = async (id) => {
|
||||||
|
const { hostname, actorUri: uri } = await helpers.query(id);
|
||||||
|
if (!uri) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const actor = await request({
|
||||||
|
uri,
|
||||||
|
headers: {
|
||||||
|
Accept: 'application/ld+json; profile="https://www.w3.org/ns/activitystreams"',
|
||||||
|
},
|
||||||
|
json: true,
|
||||||
|
});
|
||||||
|
|
||||||
|
actor.hostname = hostname;
|
||||||
|
|
||||||
|
return actor;
|
||||||
|
};
|
||||||
|
|
||||||
ActivityPub.getPublicKey = async (uid) => {
|
ActivityPub.getPublicKey = async (uid) => {
|
||||||
let publicKey;
|
let publicKey;
|
||||||
|
|
||||||
@@ -10,12 +10,18 @@ const categories = require('../../categories');
|
|||||||
const plugins = require('../../plugins');
|
const plugins = require('../../plugins');
|
||||||
const privileges = require('../../privileges');
|
const privileges = require('../../privileges');
|
||||||
const accountHelpers = require('./helpers');
|
const accountHelpers = require('./helpers');
|
||||||
|
const { getActor } = require('../../activitypub');
|
||||||
const helpers = require('../helpers');
|
const helpers = require('../helpers');
|
||||||
|
const slugify = require('../../slugify');
|
||||||
const utils = require('../../utils');
|
const utils = require('../../utils');
|
||||||
|
|
||||||
const profileController = module.exports;
|
const profileController = module.exports;
|
||||||
|
|
||||||
profileController.get = async function (req, res, next) {
|
profileController.get = async function (req, res, next) {
|
||||||
|
if (res.locals.uid === -2) {
|
||||||
|
return profileController.getFederated(req, res, next);
|
||||||
|
}
|
||||||
|
|
||||||
const lowercaseSlug = req.params.userslug.toLowerCase();
|
const lowercaseSlug = req.params.userslug.toLowerCase();
|
||||||
|
|
||||||
if (req.params.userslug !== lowercaseSlug) {
|
if (req.params.userslug !== lowercaseSlug) {
|
||||||
@@ -58,6 +64,32 @@ profileController.get = async function (req, res, next) {
|
|||||||
res.render('account/profile', userData);
|
res.render('account/profile', userData);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
profileController.getFederated = async function (req, res, next) {
|
||||||
|
const { userslug: uid } = req.params;
|
||||||
|
const actor = await getActor(uid);
|
||||||
|
if (!actor) {
|
||||||
|
return next();
|
||||||
|
}
|
||||||
|
// console.log(actor);
|
||||||
|
const { preferredUsername, published, icon, image, name, summary, hostname } = actor;
|
||||||
|
|
||||||
|
const payload = {
|
||||||
|
uid,
|
||||||
|
username: `${preferredUsername}@${hostname}`,
|
||||||
|
userslug: slugify(`${preferredUsername}@${hostname}`),
|
||||||
|
fullname: name,
|
||||||
|
joindate: new Date(published).getTime(),
|
||||||
|
picture: typeof icon === 'string' ? icon : icon.url,
|
||||||
|
uploadedpicture: typeof icon === 'string' ? icon : icon.url,
|
||||||
|
'cover:url': typeof image === 'string' ? image : image.url,
|
||||||
|
'cover:position': '50% 50%',
|
||||||
|
aboutme: summary,
|
||||||
|
aboutmeParsed: summary,
|
||||||
|
};
|
||||||
|
|
||||||
|
res.render('account/profile', payload);
|
||||||
|
};
|
||||||
|
|
||||||
async function incrementProfileViews(req, userData) {
|
async function incrementProfileViews(req, userData) {
|
||||||
if (req.uid >= 1) {
|
if (req.uid >= 1) {
|
||||||
req.session.uids_viewed = req.session.uids_viewed || {};
|
req.session.uids_viewed = req.session.uids_viewed || {};
|
||||||
|
|||||||
@@ -172,7 +172,15 @@ async function expose(exposedField, method, field, req, res, next) {
|
|||||||
if (!req.params.hasOwnProperty(field)) {
|
if (!req.params.hasOwnProperty(field)) {
|
||||||
return next();
|
return next();
|
||||||
}
|
}
|
||||||
const value = await method(String(req.params[field]).toLowerCase());
|
const param = String(req.params[field]).toLowerCase();
|
||||||
|
|
||||||
|
// potential hostname — ActivityPub
|
||||||
|
if (param.indexOf('@') !== -1) {
|
||||||
|
res.locals[exposedField] = -2;
|
||||||
|
return next();
|
||||||
|
}
|
||||||
|
|
||||||
|
const value = await method(param);
|
||||||
if (!value) {
|
if (!value) {
|
||||||
next('route');
|
next('route');
|
||||||
return;
|
return;
|
||||||
|
|||||||
Reference in New Issue
Block a user