Bryan Ashby 9b01124b2e
Re-work of ActivityPub DBs and various account lookups
* Always look up Actors by explicit Actor IDs
* Re-work DB: style, properties we track, etc.
* Create AP properties via a event!
* Lots of cleanup
* WF may be partially broken if loooking up by 'profile' alias URL: WIP
2023-01-28 11:55:31 -07:00

113 lines
3.2 KiB
JavaScript

const { localActorId } = require('./util');
const { WellKnownActivityTypes } = require('./const');
const ActivityPubObject = require('./object');
const { Errors } = require('../enig_error');
const UserProps = require('../user_property');
const { postJson } = require('../http_util');
const { getISOTimestampString } = require('../database');
// deps
const _ = require('lodash');
module.exports = class Activity extends ActivityPubObject {
constructor(obj) {
super(obj);
}
static get ActivityTypes() {
return WellKnownActivityTypes;
}
static fromJsonString(s) {
const obj = ActivityPubObject.fromJsonString(s);
return new Activity(obj);
}
static makeFollow(webServer, localActor, remoteActor) {
return new Activity({
id: Activity.activityObjectId(webServer),
type: 'Follow',
actor: localActor,
object: remoteActor.id,
});
}
// https://www.w3.org/TR/activitypub/#accept-activity-inbox
static makeAccept(webServer, localActor, followRequest) {
return new Activity({
id: Activity.activityObjectId(webServer),
type: 'Accept',
actor: localActor,
object: followRequest, // previous request Activity
});
}
static makeCreate(webServer, actor, obj) {
return new Activity({
id: Activity.activityObjectId(webServer),
type: 'Create',
actor,
object: obj,
});
}
static makeTombstone(obj) {
const deleted = getISOTimestampString();
return new Activity({
id: obj.id,
type: 'Tombstone',
deleted,
published: deleted,
updated: deleted,
});
}
sendTo(actorUrl, fromUser, webServer, cb) {
const privateKey = fromUser.getProperty(UserProps.PrivateActivityPubSigningKey);
if (_.isEmpty(privateKey)) {
return cb(
Errors.MissingProperty(
`User "${fromUser.username}" is missing the '${UserProps.PrivateActivityPubSigningKey}' property`
)
);
}
const reqOpts = {
headers: {
'Content-Type': 'application/activity+json',
},
sign: {
// :TODO: Make a helper for this
key: privateKey,
keyId: localActorId(webServer, fromUser) + '#main-key',
authorizationHeaderName: 'Signature',
headers: ['(request-target)', 'host', 'date', 'digest', 'content-type'],
},
};
const activityJson = JSON.stringify(this);
return postJson(actorUrl, activityJson, reqOpts, cb);
}
recipientIds() {
const ids = [];
// :TODO: bto, bcc?
['to', 'cc', 'audience'].forEach(field => {
let v = this[field];
if (v) {
if (!Array.isArray(v)) {
v = [v];
}
ids.push(...v);
}
});
return ids;
}
static activityObjectId(webServer) {
return ActivityPubObject.makeObjectId(webServer, 'activity');
}
};