mirror of
https://github.com/TryGhost/Ghost.git
synced 2024-11-27 10:42:45 +03:00
Added ability for Actor to sign requests
ref https://linear.app/tryghost/issue/MOM-74 This will allow us to generated signed requests for Activites.
This commit is contained in:
parent
deb6e05889
commit
e6552ddb63
57
ghost/ghost/src/core/activitypub/actor.entity.test.ts
Normal file
57
ghost/ghost/src/core/activitypub/actor.entity.test.ts
Normal file
@ -0,0 +1,57 @@
|
||||
import crypto from 'node:crypto';
|
||||
import {Actor} from './actor.entity';
|
||||
import {HTTPSignature} from './http-signature.service';
|
||||
import assert from 'node:assert';
|
||||
|
||||
describe('Actor', function () {
|
||||
describe('#sign', function () {
|
||||
it('returns a request with a valid Signature header', async function () {
|
||||
const keypair = crypto.generateKeyPairSync('rsa', {
|
||||
modulusLength: 512
|
||||
});
|
||||
const baseUrl = new URL('https://example.com/ap');
|
||||
const actor = Actor.create({
|
||||
username: 'Testing',
|
||||
outbox: [],
|
||||
publicKey: keypair.publicKey
|
||||
.export({type: 'pkcs1', format: 'pem'})
|
||||
.toString(),
|
||||
privateKey: keypair.privateKey
|
||||
.export({type: 'pkcs1', format: 'pem'})
|
||||
.toString()
|
||||
});
|
||||
|
||||
const url = new URL('https://some-server.com/users/username/inbox');
|
||||
const date = new Date();
|
||||
const request = new Request(url, {
|
||||
headers: {
|
||||
Host: url.host,
|
||||
Date: date.toISOString(),
|
||||
Accept: 'application/ld+json; profile="https://www.w3.org/ns/activitystreams"'
|
||||
}
|
||||
});
|
||||
|
||||
const signedRequest = await actor.sign(request, baseUrl);
|
||||
|
||||
const publicKey = actor.getJSONLD(baseUrl).publicKey;
|
||||
|
||||
class MockHTTPSignature extends HTTPSignature {
|
||||
protected static async getPublicKey() {
|
||||
return crypto.createPublicKey(publicKey.publicKeyPem);
|
||||
}
|
||||
}
|
||||
|
||||
const signedRequestURL = new URL(signedRequest.url);
|
||||
|
||||
const actual = await MockHTTPSignature.validate(
|
||||
signedRequest.method,
|
||||
signedRequestURL.pathname,
|
||||
signedRequest.headers
|
||||
);
|
||||
|
||||
const expected = true;
|
||||
|
||||
assert.equal(actual, expected, 'The signature should have been valid');
|
||||
});
|
||||
});
|
||||
});
|
@ -1,9 +1,11 @@
|
||||
import crypto from 'crypto';
|
||||
import ObjectID from 'bson-objectid';
|
||||
import {Entity} from '../../common/entity.base';
|
||||
import {ActivityPub} from './types';
|
||||
import {Activity} from './activity.object';
|
||||
import {Article} from './article.object';
|
||||
import {ActivityEvent} from './activity.event';
|
||||
import {HTTPSignature} from './http-signature.service';
|
||||
|
||||
type ActorData = {
|
||||
username: string;
|
||||
@ -25,6 +27,12 @@ export class Actor extends Entity<ActorData> {
|
||||
return this.attr.outbox;
|
||||
}
|
||||
|
||||
async sign(request: Request, baseUrl: URL): Promise<Request> {
|
||||
const keyId = new URL(this.getJSONLD(baseUrl).publicKey.id);
|
||||
const key = crypto.createPrivateKey(this.attr.privateKey);
|
||||
return HTTPSignature.sign(request, keyId, key);
|
||||
}
|
||||
|
||||
private activities: Activity[] = [];
|
||||
|
||||
static getActivitiesToSave(actor: Actor, fn: (activities: Activity[]) => void) {
|
||||
|
Loading…
Reference in New Issue
Block a user