1 /* tslint:disable:no-unused-expression */
5 import { flushAndRunMultipleServers, flushTests, killallServers, makePOSTAPRequest, makeFollowRequest, ServerInfo } from '../../utils'
6 import { HTTP_SIGNATURE } from '../../../initializers'
7 import { buildDigest, buildGlobalHeaders } from '../../../lib/job-queue/handlers/utils/activitypub-http-utils'
8 import * as chai from 'chai'
9 import { setActorField } from '../../utils/miscs/sql'
10 import { activityPubContextify, buildSignedActivity } from '../../../helpers/activitypub'
12 const expect = chai.expect
14 function setKeysOfServer2 (serverNumber: number, publicKey: string, privateKey: string) {
16 setActorField(serverNumber, 'http://localhost:9002/accounts/peertube', 'publicKey', publicKey),
17 setActorField(serverNumber, 'http://localhost:9002/accounts/peertube', 'privateKey', privateKey)
21 function setKeysOfServer3 (serverNumber: number, publicKey: string, privateKey: string) {
23 setActorField(serverNumber, 'http://localhost:9003/accounts/peertube', 'publicKey', publicKey),
24 setActorField(serverNumber, 'http://localhost:9003/accounts/peertube', 'privateKey', privateKey)
28 describe('Test ActivityPub security', function () {
29 let servers: ServerInfo[]
32 const keys = require('./json/peertube/keys.json')
33 const invalidKeys = require('./json/peertube/invalid-keys.json')
34 const baseHttpSignature = {
35 algorithm: HTTP_SIGNATURE.ALGORITHM,
36 authorizationHeaderName: HTTP_SIGNATURE.HEADER_NAME,
37 keyId: 'acct:peertube@localhost:9002',
39 headers: HTTP_SIGNATURE.HEADERS_TO_SIGN
42 // ---------------------------------------------------------------
44 before(async function () {
47 servers = await flushAndRunMultipleServers(3)
49 url = servers[0].url + '/inbox'
51 await setKeysOfServer2(1, keys.publicKey, keys.privateKey)
53 const to = { url: 'http://localhost:9001/accounts/peertube' }
54 const by = { url: 'http://localhost:9002/accounts/peertube', privateKey: keys.privateKey }
55 await makeFollowRequest(to, by)
58 describe('When checking HTTP signature', function () {
60 it('Should fail with an invalid digest', async function () {
61 const body = activityPubContextify(require('./json/peertube/announce-without-context.json'))
63 Digest: buildDigest({ hello: 'coucou' })
66 const { response } = await makePOSTAPRequest(url, body, baseHttpSignature, headers)
68 expect(response.statusCode).to.equal(403)
71 it('Should fail with an invalid date', async function () {
72 const body = activityPubContextify(require('./json/peertube/announce-without-context.json'))
73 const headers = buildGlobalHeaders(body)
74 headers['date'] = 'Wed, 21 Oct 2015 07:28:00 GMT'
76 const { response } = await makePOSTAPRequest(url, body, baseHttpSignature, headers)
78 expect(response.statusCode).to.equal(403)
81 it('Should fail with bad keys', async function () {
82 await setKeysOfServer2(1, invalidKeys.publicKey, invalidKeys.privateKey)
83 await setKeysOfServer2(2, invalidKeys.publicKey, invalidKeys.privateKey)
85 const body = activityPubContextify(require('./json/peertube/announce-without-context.json'))
86 const headers = buildGlobalHeaders(body)
88 const { response } = await makePOSTAPRequest(url, body, baseHttpSignature, headers)
90 expect(response.statusCode).to.equal(403)
93 it('Should succeed with a valid HTTP signature', async function () {
94 await setKeysOfServer2(1, keys.publicKey, keys.privateKey)
95 await setKeysOfServer2(2, keys.publicKey, keys.privateKey)
97 const body = activityPubContextify(require('./json/peertube/announce-without-context.json'))
98 const headers = buildGlobalHeaders(body)
100 const { response } = await makePOSTAPRequest(url, body, baseHttpSignature, headers)
102 expect(response.statusCode).to.equal(204)
106 describe('When checking Linked Data Signature', function () {
108 await setKeysOfServer3(3, keys.publicKey, keys.privateKey)
110 const to = { url: 'http://localhost:9001/accounts/peertube' }
111 const by = { url: 'http://localhost:9003/accounts/peertube', privateKey: keys.privateKey }
112 await makeFollowRequest(to, by)
115 it('Should fail with bad keys', async function () {
118 await setKeysOfServer3(1, invalidKeys.publicKey, invalidKeys.privateKey)
119 await setKeysOfServer3(3, invalidKeys.publicKey, invalidKeys.privateKey)
121 const body = require('./json/peertube/announce-without-context.json')
122 body.actor = 'http://localhost:9003/accounts/peertube'
124 const signer: any = { privateKey: invalidKeys.privateKey, url: 'http://localhost:9003/accounts/peertube' }
125 const signedBody = await buildSignedActivity(signer, body)
127 const headers = buildGlobalHeaders(signedBody)
129 const { response } = await makePOSTAPRequest(url, signedBody, baseHttpSignature, headers)
131 expect(response.statusCode).to.equal(403)
134 it('Should fail with an altered body', async function () {
137 await setKeysOfServer3(1, keys.publicKey, keys.privateKey)
138 await setKeysOfServer3(3, keys.publicKey, keys.privateKey)
140 const body = require('./json/peertube/announce-without-context.json')
141 body.actor = 'http://localhost:9003/accounts/peertube'
143 const signer: any = { privateKey: keys.privateKey, url: 'http://localhost:9003/accounts/peertube' }
144 const signedBody = await buildSignedActivity(signer, body)
146 signedBody.actor = 'http://localhost:9003/account/peertube'
148 const headers = buildGlobalHeaders(signedBody)
150 const { response } = await makePOSTAPRequest(url, signedBody, baseHttpSignature, headers)
152 expect(response.statusCode).to.equal(403)
155 it('Should succeed with a valid signature', async function () {
158 const body = require('./json/peertube/announce-without-context.json')
159 body.actor = 'http://localhost:9003/accounts/peertube'
161 const signer: any = { privateKey: keys.privateKey, url: 'http://localhost:9003/accounts/peertube' }
162 const signedBody = await buildSignedActivity(signer, body)
164 const headers = buildGlobalHeaders(signedBody)
166 const { response } = await makePOSTAPRequest(url, signedBody, baseHttpSignature, headers)
168 expect(response.statusCode).to.equal(204)
172 after(async function () {
173 killallServers(servers)
175 // Keep the logs if the test failed