mirror of
https://github.com/NodeBB/NodeBB.git
synced 2025-10-26 16:46:12 +01:00
feat: handle incoming non-public activities as chat message, #12834
This commit is contained in:
@@ -154,6 +154,9 @@ Helpers.resolveLocalId = async (input) => {
|
||||
const uid = await user.getUidByUserslug(value);
|
||||
return { type: 'user', id: uid, ...activityData };
|
||||
}
|
||||
|
||||
case 'message':
|
||||
return { type: 'message', id: value, ...activityData };
|
||||
}
|
||||
|
||||
return { type: null, id: null, ...activityData };
|
||||
|
||||
@@ -62,9 +62,9 @@ async function announce(id, activity) {
|
||||
inbox.create = async (req) => {
|
||||
const { object } = req.body;
|
||||
|
||||
// Temporary, reject non-public notes.
|
||||
// Alternative logic for non-public objects
|
||||
if (![...object.to, ...object.cc].includes(activitypub._constants.publicAddress)) {
|
||||
throw new Error('[[error:activitypub.not-implemented]]');
|
||||
return await activitypub.notes.assertPrivate(object);
|
||||
}
|
||||
|
||||
const asserted = await activitypub.notes.assert(0, object);
|
||||
|
||||
@@ -8,6 +8,7 @@ const batch = require('../batch');
|
||||
const meta = require('../meta');
|
||||
const privileges = require('../privileges');
|
||||
const categories = require('../categories');
|
||||
const messaging = require('../messaging');
|
||||
const user = require('../user');
|
||||
const topics = require('../topics');
|
||||
const posts = require('../posts');
|
||||
@@ -190,6 +191,79 @@ Notes.assert = async (uid, input, options = { skipChecks: false }) => {
|
||||
return { tid, count };
|
||||
};
|
||||
|
||||
Notes.assertPrivate = async (object) => {
|
||||
// Given an object, adds it to an existing chat or creates a new chat otherwise
|
||||
// todo: context stuff
|
||||
|
||||
const recipients = new Set([...object.to, ...object.cc]);
|
||||
|
||||
// Remove follower urls
|
||||
const isFollowerUrl = await db.isObjectFields('followersUrl:uid', Array.from(recipients));
|
||||
Array.from(recipients).forEach((id, idx) => {
|
||||
if (isFollowerUrl[idx]) {
|
||||
recipients.delete(id);
|
||||
}
|
||||
});
|
||||
|
||||
const localUids = [];
|
||||
const recipientsResolved = new Set([...recipients]);
|
||||
await Promise.all(Array.from(recipients).map(async (value) => {
|
||||
const { type, id } = await activitypub.helpers.resolveLocalId(value);
|
||||
if (type === 'user') {
|
||||
localUids.push(id);
|
||||
recipientsResolved.delete(value);
|
||||
recipientsResolved.add(parseInt(id, 10));
|
||||
}
|
||||
}));
|
||||
|
||||
// Locate the roomId based on `inReplyTo`
|
||||
let roomId;
|
||||
const resolved = await activitypub.helpers.resolveLocalId(object.inReplyTo);
|
||||
let toMid = resolved.type === 'message' && resolved.id;
|
||||
if (object.inReplyTo && await messaging.messageExists(toMid || object.inReplyTo)) {
|
||||
roomId = await messaging.getMessageField(toMid || object.inReplyTo, 'roomId');
|
||||
}
|
||||
|
||||
// Compare room members with object recipients; if someone in-room is omitted, start new chat
|
||||
if (roomId) {
|
||||
const participants = await messaging.getUsersInRoom(roomId, 0, -1);
|
||||
const omitted = participants.filter((user) => {
|
||||
let { uid } = user;
|
||||
uid = utils.isNumber(uid) ? `${nconf.get('url')}/uid/${uid}` : uid;
|
||||
return !recipients.has(uid) && uid !== object.attributedTo;
|
||||
});
|
||||
if (omitted.length) {
|
||||
toMid = undefined; // message creation logic fails if toMid is not in room
|
||||
roomId = null;
|
||||
}
|
||||
}
|
||||
|
||||
let timestamp;
|
||||
try {
|
||||
timestamp = new Date(object.published).getTime() || Date.now();
|
||||
} catch (e) {
|
||||
timestamp = Date.now();
|
||||
}
|
||||
|
||||
if (!roomId) {
|
||||
roomId = await messaging.newRoom(object.attributedTo, { uids: [...recipientsResolved] });
|
||||
timestamp = Date.now(); // otherwise message can't be seen in room as it pre-dates participants joining
|
||||
}
|
||||
|
||||
// Add message to room
|
||||
await messaging.sendMessage({
|
||||
mid: object.id,
|
||||
uid: object.attributedTo,
|
||||
roomId: roomId,
|
||||
content: object.content,
|
||||
toMid: toMid,
|
||||
timestamp,
|
||||
// ip: caller.ip,
|
||||
});
|
||||
|
||||
return { roomId };
|
||||
};
|
||||
|
||||
async function assertRelation(post) {
|
||||
/**
|
||||
* Given a mocked post object, ensures that it is related to some other object in database
|
||||
|
||||
@@ -50,7 +50,7 @@ module.exports = function (Messaging) {
|
||||
throw new Error('[[error:no-privileges]]');
|
||||
}
|
||||
}
|
||||
const mid = await db.incrObjectField('global', 'nextMid');
|
||||
const mid = data.mid || await db.incrObjectField('global', 'nextMid');
|
||||
const timestamp = data.timestamp || Date.now();
|
||||
let message = {
|
||||
mid: mid,
|
||||
|
||||
@@ -5,6 +5,7 @@ const validator = require('validator');
|
||||
|
||||
const db = require('../database');
|
||||
const user = require('../user');
|
||||
const posts = require('../posts');
|
||||
const utils = require('../utils');
|
||||
const plugins = require('../plugins');
|
||||
|
||||
@@ -185,6 +186,8 @@ module.exports = function (Messaging) {
|
||||
async function parseMessage(message, uid, roomId, isNew) {
|
||||
if (message.system) {
|
||||
return validator.escape(String(message.content));
|
||||
} else if (!utils.isNumber(message.mid)) {
|
||||
return posts.sanitize(message.content);
|
||||
}
|
||||
|
||||
return await Messaging.parse(message.content, message.fromuid, uid, roomId, isNew);
|
||||
|
||||
Reference in New Issue
Block a user