1 /* tslint:disable:no-unused-expression */
8 flushAndRunMultipleServers,
12 } from '../../../../shared/extra-utils'
13 import { HTTP_SIGNATURE } from '../../../initializers/constants'
14 import { buildDigest, buildGlobalHeaders } from '../../../lib/job-queue/handlers/utils/activitypub-http-utils'
15 import * as chai from 'chai'
16 import { activityPubContextify, buildSignedActivity } from '../../../helpers/activitypub'
17 import { makeFollowRequest, makePOSTAPRequest } from '../../../../shared/extra-utils/requests/activitypub'
19 const expect = chai.expect
21 function setKeysOfServer (onServer: ServerInfo, ofServer: ServerInfo, publicKey: string, privateKey: string) {
23 setActorField(onServer.internalServerNumber, 'http://localhost:' + ofServer.port + '/accounts/peertube', 'publicKey', publicKey),
24 setActorField(onServer.internalServerNumber, 'http://localhost:' + ofServer.port + '/accounts/peertube', 'privateKey', privateKey)
28 function getAnnounceWithoutContext (server2: ServerInfo) {
29 const json = require('./json/peertube/announce-without-context.json')
30 const result: typeof json = {}
32 for (const key of Object.keys(json)) {
33 if (Array.isArray(json[key])) {
34 result[key] = json[key].map(v => v.replace(':9002', `:${server2.port}`))
36 result[ key ] = json[ key ].replace(':9002', `:${server2.port}`)
43 describe('Test ActivityPub security', function () {
44 let servers: ServerInfo[]
47 const keys = require('./json/peertube/keys.json')
48 const invalidKeys = require('./json/peertube/invalid-keys.json')
49 const baseHttpSignature = () => ({
50 algorithm: HTTP_SIGNATURE.ALGORITHM,
51 authorizationHeaderName: HTTP_SIGNATURE.HEADER_NAME,
52 keyId: 'acct:peertube@localhost:' + servers[1].port,
54 headers: HTTP_SIGNATURE.HEADERS_TO_SIGN
57 // ---------------------------------------------------------------
59 before(async function () {
62 servers = await flushAndRunMultipleServers(3)
64 url = servers[0].url + '/inbox'
66 await setKeysOfServer(servers[0], servers[1], keys.publicKey, keys.privateKey)
68 const to = { url: 'http://localhost:' + servers[0].port + '/accounts/peertube' }
69 const by = { url: 'http://localhost:' + servers[1].port + '/accounts/peertube', privateKey: keys.privateKey }
70 await makeFollowRequest(to, by)
73 describe('When checking HTTP signature', function () {
75 it('Should fail with an invalid digest', async function () {
76 const body = activityPubContextify(getAnnounceWithoutContext(servers[1]))
78 Digest: buildDigest({ hello: 'coucou' })
81 const { response } = await makePOSTAPRequest(url, body, baseHttpSignature(), headers)
83 expect(response.statusCode).to.equal(403)
86 it('Should fail with an invalid date', async function () {
87 const body = activityPubContextify(getAnnounceWithoutContext(servers[1]))
88 const headers = buildGlobalHeaders(body)
89 headers['date'] = 'Wed, 21 Oct 2015 07:28:00 GMT'
91 const { response } = await makePOSTAPRequest(url, body, baseHttpSignature(), headers)
93 expect(response.statusCode).to.equal(403)
96 it('Should fail with bad keys', async function () {
97 await setKeysOfServer(servers[0], servers[1], invalidKeys.publicKey, invalidKeys.privateKey)
98 await setKeysOfServer(servers[1], servers[1], invalidKeys.publicKey, invalidKeys.privateKey)
100 const body = activityPubContextify(getAnnounceWithoutContext(servers[1]))
101 const headers = buildGlobalHeaders(body)
103 const { response } = await makePOSTAPRequest(url, body, baseHttpSignature(), headers)
105 expect(response.statusCode).to.equal(403)
108 it('Should succeed with a valid HTTP signature', async function () {
109 await setKeysOfServer(servers[0], servers[1], keys.publicKey, keys.privateKey)
110 await setKeysOfServer(servers[1], servers[1], keys.publicKey, keys.privateKey)
112 const body = activityPubContextify(getAnnounceWithoutContext(servers[1]))
113 const headers = buildGlobalHeaders(body)
115 const { response } = await makePOSTAPRequest(url, body, baseHttpSignature(), headers)
117 expect(response.statusCode).to.equal(204)
121 describe('When checking Linked Data Signature', function () {
123 await setKeysOfServer(servers[2], servers[2], keys.publicKey, keys.privateKey)
125 const to = { url: 'http://localhost:' + servers[0].port + '/accounts/peertube' }
126 const by = { url: 'http://localhost:' + servers[2].port + '/accounts/peertube', privateKey: keys.privateKey }
127 await makeFollowRequest(to, by)
130 it('Should fail with bad keys', async function () {
133 await setKeysOfServer(servers[0], servers[2], invalidKeys.publicKey, invalidKeys.privateKey)
134 await setKeysOfServer(servers[2], servers[2], invalidKeys.publicKey, invalidKeys.privateKey)
136 const body = getAnnounceWithoutContext(servers[1])
137 body.actor = 'http://localhost:' + servers[2].port + '/accounts/peertube'
139 const signer: any = { privateKey: invalidKeys.privateKey, url: 'http://localhost:' + servers[2].port + '/accounts/peertube' }
140 const signedBody = await buildSignedActivity(signer, body)
142 const headers = buildGlobalHeaders(signedBody)
144 const { response } = await makePOSTAPRequest(url, signedBody, baseHttpSignature(), headers)
146 expect(response.statusCode).to.equal(403)
149 it('Should fail with an altered body', async function () {
152 await setKeysOfServer(servers[0], servers[2], keys.publicKey, keys.privateKey)
153 await setKeysOfServer(servers[0], servers[2], keys.publicKey, keys.privateKey)
155 const body = getAnnounceWithoutContext(servers[1])
156 body.actor = 'http://localhost:' + servers[2].port + '/accounts/peertube'
158 const signer: any = { privateKey: keys.privateKey, url: 'http://localhost:' + servers[2].port + '/accounts/peertube' }
159 const signedBody = await buildSignedActivity(signer, body)
161 signedBody.actor = 'http://localhost:' + servers[2].port + '/account/peertube'
163 const headers = buildGlobalHeaders(signedBody)
165 const { response } = await makePOSTAPRequest(url, signedBody, baseHttpSignature(), headers)
167 expect(response.statusCode).to.equal(403)
170 it('Should succeed with a valid signature', async function () {
173 const body = getAnnounceWithoutContext(servers[1])
174 body.actor = 'http://localhost:' + servers[2].port + '/accounts/peertube'
176 const signer: any = { privateKey: keys.privateKey, url: 'http://localhost:' + servers[2].port + '/accounts/peertube' }
177 const signedBody = await buildSignedActivity(signer, body)
179 const headers = buildGlobalHeaders(signedBody)
181 const { response } = await makePOSTAPRequest(url, signedBody, baseHttpSignature(), headers)
183 expect(response.statusCode).to.equal(204)
187 after(async function () {
190 await cleanupTests(servers)
192 await closeAllSequelize(servers)