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