Cleanup tests imports
[oweals/peertube.git] / server / tests / api / activitypub / security.ts
1 /* tslint:disable:no-unused-expression */
2
3 import 'mocha'
4
5 import { flushAndRunMultipleServers, flushTests, killallServers, 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'
11 import { makeFollowRequest, makePOSTAPRequest } from '../../utils/requests/activitypub'
12
13 const expect = chai.expect
14
15 function setKeysOfServer2 (serverNumber: number, publicKey: string, privateKey: string) {
16   return Promise.all([
17     setActorField(serverNumber, 'http://localhost:9002/accounts/peertube', 'publicKey', publicKey),
18     setActorField(serverNumber, 'http://localhost:9002/accounts/peertube', 'privateKey', privateKey)
19   ])
20 }
21
22 function setKeysOfServer3 (serverNumber: number, publicKey: string, privateKey: string) {
23   return Promise.all([
24     setActorField(serverNumber, 'http://localhost:9003/accounts/peertube', 'publicKey', publicKey),
25     setActorField(serverNumber, 'http://localhost:9003/accounts/peertube', 'privateKey', privateKey)
26   ])
27 }
28
29 describe('Test ActivityPub security', function () {
30   let servers: ServerInfo[]
31   let url: string
32
33   const keys = require('./json/peertube/keys.json')
34   const invalidKeys = require('./json/peertube/invalid-keys.json')
35   const baseHttpSignature = {
36     algorithm: HTTP_SIGNATURE.ALGORITHM,
37     authorizationHeaderName: HTTP_SIGNATURE.HEADER_NAME,
38     keyId: 'acct:peertube@localhost:9002',
39     key: keys.privateKey,
40     headers: HTTP_SIGNATURE.HEADERS_TO_SIGN
41   }
42
43   // ---------------------------------------------------------------
44
45   before(async function () {
46     this.timeout(60000)
47
48     servers = await flushAndRunMultipleServers(3)
49
50     url = servers[0].url + '/inbox'
51
52     await setKeysOfServer2(1, keys.publicKey, keys.privateKey)
53
54     const to = { url: 'http://localhost:9001/accounts/peertube' }
55     const by = { url: 'http://localhost:9002/accounts/peertube', privateKey: keys.privateKey }
56     await makeFollowRequest(to, by)
57   })
58
59   describe('When checking HTTP signature', function () {
60
61     it('Should fail with an invalid digest', async function () {
62       const body = activityPubContextify(require('./json/peertube/announce-without-context.json'))
63       const headers = {
64         Digest: buildDigest({ hello: 'coucou' })
65       }
66
67       const { response } = await makePOSTAPRequest(url, body, baseHttpSignature, headers)
68
69       expect(response.statusCode).to.equal(403)
70     })
71
72     it('Should fail with an invalid date', async function () {
73       const body = activityPubContextify(require('./json/peertube/announce-without-context.json'))
74       const headers = buildGlobalHeaders(body)
75       headers['date'] = 'Wed, 21 Oct 2015 07:28:00 GMT'
76
77       const { response } = await makePOSTAPRequest(url, body, baseHttpSignature, headers)
78
79       expect(response.statusCode).to.equal(403)
80     })
81
82     it('Should fail with bad keys', async function () {
83       await setKeysOfServer2(1, invalidKeys.publicKey, invalidKeys.privateKey)
84       await setKeysOfServer2(2, invalidKeys.publicKey, invalidKeys.privateKey)
85
86       const body = activityPubContextify(require('./json/peertube/announce-without-context.json'))
87       const headers = buildGlobalHeaders(body)
88
89       const { response } = await makePOSTAPRequest(url, body, baseHttpSignature, headers)
90
91       expect(response.statusCode).to.equal(403)
92     })
93
94     it('Should succeed with a valid HTTP signature', async function () {
95       await setKeysOfServer2(1, keys.publicKey, keys.privateKey)
96       await setKeysOfServer2(2, keys.publicKey, keys.privateKey)
97
98       const body = activityPubContextify(require('./json/peertube/announce-without-context.json'))
99       const headers = buildGlobalHeaders(body)
100
101       const { response } = await makePOSTAPRequest(url, body, baseHttpSignature, headers)
102
103       expect(response.statusCode).to.equal(204)
104     })
105   })
106
107   describe('When checking Linked Data Signature', function () {
108     before(async () => {
109       await setKeysOfServer3(3, keys.publicKey, keys.privateKey)
110
111       const to = { url: 'http://localhost:9001/accounts/peertube' }
112       const by = { url: 'http://localhost:9003/accounts/peertube', privateKey: keys.privateKey }
113       await makeFollowRequest(to, by)
114     })
115
116     it('Should fail with bad keys', async function () {
117       this.timeout(10000)
118
119       await setKeysOfServer3(1, invalidKeys.publicKey, invalidKeys.privateKey)
120       await setKeysOfServer3(3, invalidKeys.publicKey, invalidKeys.privateKey)
121
122       const body = require('./json/peertube/announce-without-context.json')
123       body.actor = 'http://localhost:9003/accounts/peertube'
124
125       const signer: any = { privateKey: invalidKeys.privateKey, url: 'http://localhost:9003/accounts/peertube' }
126       const signedBody = await buildSignedActivity(signer, body)
127
128       const headers = buildGlobalHeaders(signedBody)
129
130       const { response } = await makePOSTAPRequest(url, signedBody, baseHttpSignature, headers)
131
132       expect(response.statusCode).to.equal(403)
133     })
134
135     it('Should fail with an altered body', async function () {
136       this.timeout(10000)
137
138       await setKeysOfServer3(1, keys.publicKey, keys.privateKey)
139       await setKeysOfServer3(3, keys.publicKey, keys.privateKey)
140
141       const body = require('./json/peertube/announce-without-context.json')
142       body.actor = 'http://localhost:9003/accounts/peertube'
143
144       const signer: any = { privateKey: keys.privateKey, url: 'http://localhost:9003/accounts/peertube' }
145       const signedBody = await buildSignedActivity(signer, body)
146
147       signedBody.actor = 'http://localhost:9003/account/peertube'
148
149       const headers = buildGlobalHeaders(signedBody)
150
151       const { response } = await makePOSTAPRequest(url, signedBody, baseHttpSignature, headers)
152
153       expect(response.statusCode).to.equal(403)
154     })
155
156     it('Should succeed with a valid signature', async function () {
157       this.timeout(10000)
158
159       const body = require('./json/peertube/announce-without-context.json')
160       body.actor = 'http://localhost:9003/accounts/peertube'
161
162       const signer: any = { privateKey: keys.privateKey, url: 'http://localhost:9003/accounts/peertube' }
163       const signedBody = await buildSignedActivity(signer, body)
164
165       const headers = buildGlobalHeaders(signedBody)
166
167       const { response } = await makePOSTAPRequest(url, signedBody, baseHttpSignature, headers)
168
169       expect(response.statusCode).to.equal(204)
170     })
171   })
172
173   after(async function () {
174     killallServers(servers)
175
176     // Keep the logs if the test failed
177     if (this['ok']) {
178       await flushTests()
179     }
180   })
181 })