From b83b8dd5aef03084133c5983de6f312e7d1654b8 Mon Sep 17 00:00:00 2001 From: Rigel Kent Date: Wed, 14 Nov 2018 15:27:47 +0100 Subject: add cli option to run without client --- server/tests/api/server/index.ts | 1 + server/tests/api/server/no-client.ts | 36 ++++++++++++++++++++++++++++++++++++ server/tests/utils/server/servers.ts | 4 ++-- 3 files changed, 39 insertions(+), 2 deletions(-) create mode 100644 server/tests/api/server/no-client.ts (limited to 'server/tests') diff --git a/server/tests/api/server/index.ts b/server/tests/api/server/index.ts index eeb8b7a28..78ab7e18b 100644 --- a/server/tests/api/server/index.ts +++ b/server/tests/api/server/index.ts @@ -6,3 +6,4 @@ import './jobs' import './reverse-proxy' import './stats' import './tracker' +import './no-client' diff --git a/server/tests/api/server/no-client.ts b/server/tests/api/server/no-client.ts new file mode 100644 index 000000000..6d6ce8532 --- /dev/null +++ b/server/tests/api/server/no-client.ts @@ -0,0 +1,36 @@ +import 'mocha' +import * as request from 'supertest' +import { + flushTests, + killallServers, + ServerInfo +} from '../../utils/index' +import { runServer } from '../../utils/server/servers' + +describe('Start and stop server without web client routes', function () { + let server: ServerInfo + + before(async function () { + this.timeout(30000) + + await flushTests() + + server = await runServer(1, {}, ['--no-client']) + }) + + it('Should fail getting the client', function () { + const req = request(server.url) + .get('/') + + return req.expect(404) + }) + + after(async function () { + killallServers([ server ]) + + // Keep the logs if the test failed + if (this['ok']) { + await flushTests() + } + }) +}) diff --git a/server/tests/utils/server/servers.ts b/server/tests/utils/server/servers.ts index 3c946db27..f358a21f1 100644 --- a/server/tests/utils/server/servers.ts +++ b/server/tests/utils/server/servers.ts @@ -69,7 +69,7 @@ function flushTests () { }) } -function runServer (serverNumber: number, configOverride?: Object) { +function runServer (serverNumber: number, configOverride?: Object, args = []) { const server: ServerInfo = { app: null, serverNumber: serverNumber, @@ -115,7 +115,7 @@ function runServer (serverNumber: number, configOverride?: Object) { } return new Promise(res => { - server.app = fork(join(__dirname, '..', '..', '..', '..', 'dist', 'server.js'), [], options) + server.app = fork(join(__dirname, '..', '..', '..', '..', 'dist', 'server.js'), args, options) server.app.stdout.on('data', function onStdout (data) { let dontContinue = false -- cgit v1.2.3 From df66d81583e07ce049daeeef1edc6a87b57b3684 Mon Sep 17 00:00:00 2001 From: Chocobozzz Date: Tue, 23 Oct 2018 11:38:48 +0200 Subject: Add compatibility with other Linked Signature algorithms --- server/tests/activitypub.ts | 35 ---- server/tests/api/activitypub/client.ts | 35 ++++ server/tests/api/activitypub/helpers.ts | 182 +++++++++++++++++++++ server/tests/api/activitypub/index.ts | 3 + .../json/mastodon/bad-body-http-signature.json | 93 +++++++++++ .../json/mastodon/bad-http-signature.json | 93 +++++++++++ .../activitypub/json/mastodon/bad-public-key.json | 3 + .../json/mastodon/create-bad-signature.json | 81 +++++++++ .../api/activitypub/json/mastodon/create.json | 81 +++++++++ .../activitypub/json/mastodon/http-signature.json | 93 +++++++++++ .../api/activitypub/json/mastodon/public-key.json | 3 + .../json/peertube/announce-without-context.json | 13 ++ .../activitypub/json/peertube/invalid-keys.json | 6 + .../tests/api/activitypub/json/peertube/keys.json | 4 + server/tests/api/activitypub/security.ts | 180 ++++++++++++++++++++ server/tests/api/index-4.ts | 1 + server/tests/index.ts | 1 - server/tests/utils/index.ts | 2 + server/tests/utils/miscs/sql.ts | 29 ++++ server/tests/utils/miscs/stubs.ts | 14 ++ server/tests/utils/requests/activitypub.ts | 43 +++++ 21 files changed, 959 insertions(+), 36 deletions(-) delete mode 100644 server/tests/activitypub.ts create mode 100644 server/tests/api/activitypub/client.ts create mode 100644 server/tests/api/activitypub/helpers.ts create mode 100644 server/tests/api/activitypub/index.ts create mode 100644 server/tests/api/activitypub/json/mastodon/bad-body-http-signature.json create mode 100644 server/tests/api/activitypub/json/mastodon/bad-http-signature.json create mode 100644 server/tests/api/activitypub/json/mastodon/bad-public-key.json create mode 100644 server/tests/api/activitypub/json/mastodon/create-bad-signature.json create mode 100644 server/tests/api/activitypub/json/mastodon/create.json create mode 100644 server/tests/api/activitypub/json/mastodon/http-signature.json create mode 100644 server/tests/api/activitypub/json/mastodon/public-key.json create mode 100644 server/tests/api/activitypub/json/peertube/announce-without-context.json create mode 100644 server/tests/api/activitypub/json/peertube/invalid-keys.json create mode 100644 server/tests/api/activitypub/json/peertube/keys.json create mode 100644 server/tests/api/activitypub/security.ts create mode 100644 server/tests/utils/miscs/sql.ts create mode 100644 server/tests/utils/miscs/stubs.ts create mode 100644 server/tests/utils/requests/activitypub.ts (limited to 'server/tests') diff --git a/server/tests/activitypub.ts b/server/tests/activitypub.ts deleted file mode 100644 index 53a04d363..000000000 --- a/server/tests/activitypub.ts +++ /dev/null @@ -1,35 +0,0 @@ -/* tslint:disable:no-unused-expression */ - -import * as chai from 'chai' -import 'mocha' -import { flushTests, killallServers, makeActivityPubGetRequest, runServer, ServerInfo, setAccessTokensToServers } from './utils' - -const expect = chai.expect - -describe('Test activitypub', function () { - let server: ServerInfo = null - - before(async function () { - this.timeout(30000) - - await flushTests() - - server = await runServer(1) - - await setAccessTokensToServers([ server ]) - }) - - it('Should return the account object', async function () { - const res = await makeActivityPubGetRequest(server.url, '/accounts/root') - const object = res.body - - expect(object.type).to.equal('Person') - expect(object.id).to.equal('http://localhost:9001/accounts/root') - expect(object.name).to.equal('root') - expect(object.preferredUsername).to.equal('root') - }) - - after(async function () { - killallServers([ server ]) - }) -}) diff --git a/server/tests/api/activitypub/client.ts b/server/tests/api/activitypub/client.ts new file mode 100644 index 000000000..5ca8bdfd3 --- /dev/null +++ b/server/tests/api/activitypub/client.ts @@ -0,0 +1,35 @@ +/* tslint:disable:no-unused-expression */ + +import * as chai from 'chai' +import 'mocha' +import { flushTests, killallServers, makeActivityPubGetRequest, runServer, ServerInfo, setAccessTokensToServers } from '../../utils' + +const expect = chai.expect + +describe('Test activitypub', function () { + let server: ServerInfo = null + + before(async function () { + this.timeout(30000) + + await flushTests() + + server = await runServer(1) + + await setAccessTokensToServers([ server ]) + }) + + it('Should return the account object', async function () { + const res = await makeActivityPubGetRequest(server.url, '/accounts/root') + const object = res.body + + expect(object.type).to.equal('Person') + expect(object.id).to.equal('http://localhost:9001/accounts/root') + expect(object.name).to.equal('root') + expect(object.preferredUsername).to.equal('root') + }) + + after(async function () { + killallServers([ server ]) + }) +}) diff --git a/server/tests/api/activitypub/helpers.ts b/server/tests/api/activitypub/helpers.ts new file mode 100644 index 000000000..610846247 --- /dev/null +++ b/server/tests/api/activitypub/helpers.ts @@ -0,0 +1,182 @@ +/* tslint:disable:no-unused-expression */ + +import 'mocha' +import { expect } from 'chai' +import { buildRequestStub } from '../../utils' +import { isHTTPSignatureVerified, isJsonLDSignatureVerified, parseHTTPSignature } from '../../../helpers/peertube-crypto' +import { cloneDeep } from 'lodash' +import { buildSignedActivity } from '../../../helpers/activitypub' + +describe('Test activity pub helpers', function () { + describe('When checking the Linked Signature', function () { + + it('Should fail with an invalid Mastodon signature', async function () { + const body = require('./json/mastodon/create-bad-signature.json') + const publicKey = require('./json/mastodon/public-key.json').publicKey + const fromActor = { publicKey, url: 'http://localhost:9002/accounts/peertube' } + + const result = await isJsonLDSignatureVerified(fromActor as any, body) + + expect(result).to.be.false + }) + + it('Should fail with an invalid public key', async function () { + const body = require('./json/mastodon/create.json') + const publicKey = require('./json/mastodon/bad-public-key.json').publicKey + const fromActor = { publicKey, url: 'http://localhost:9002/accounts/peertube' } + + const result = await isJsonLDSignatureVerified(fromActor as any, body) + + expect(result).to.be.false + }) + + it('Should succeed with a valid Mastodon signature', async function () { + const body = require('./json/mastodon/create.json') + const publicKey = require('./json/mastodon/public-key.json').publicKey + const fromActor = { publicKey, url: 'http://localhost:9002/accounts/peertube' } + + const result = await isJsonLDSignatureVerified(fromActor as any, body) + + expect(result).to.be.true + }) + + it('Should fail with an invalid PeerTube signature', async function () { + const keys = require('./json/peertube/invalid-keys.json') + const body = require('./json/peertube/announce-without-context.json') + + const actorSignature = { url: 'http://localhost:9002/accounts/peertube', privateKey: keys.privateKey } + const signedBody = await buildSignedActivity(actorSignature as any, body) + + const fromActor = { publicKey: keys.publicKey, url: 'http://localhost:9002/accounts/peertube' } + const result = await isJsonLDSignatureVerified(fromActor as any, signedBody) + + expect(result).to.be.false + }) + + it('Should fail with an invalid PeerTube URL', async function () { + const keys = require('./json/peertube/keys.json') + const body = require('./json/peertube/announce-without-context.json') + + const actorSignature = { url: 'http://localhost:9002/accounts/peertube', privateKey: keys.privateKey } + const signedBody = await buildSignedActivity(actorSignature as any, body) + + const fromActor = { publicKey: keys.publicKey, url: 'http://localhost:9003/accounts/peertube' } + const result = await isJsonLDSignatureVerified(fromActor as any, signedBody) + + expect(result).to.be.false + }) + + it('Should succeed with a valid PeerTube signature', async function () { + const keys = require('./json/peertube/keys.json') + const body = require('./json/peertube/announce-without-context.json') + + const actorSignature = { url: 'http://localhost:9002/accounts/peertube', privateKey: keys.privateKey } + const signedBody = await buildSignedActivity(actorSignature as any, body) + + const fromActor = { publicKey: keys.publicKey, url: 'http://localhost:9002/accounts/peertube' } + const result = await isJsonLDSignatureVerified(fromActor as any, signedBody) + + expect(result).to.be.true + }) + }) + + describe('When checking HTTP signature', function () { + it('Should fail with an invalid http signature', async function () { + const req = buildRequestStub() + req.method = 'POST' + req.url = '/accounts/ronan/inbox' + + const mastodonObject = cloneDeep(require('./json/mastodon/bad-http-signature.json')) + req.body = mastodonObject.body + req.headers = mastodonObject.headers + req.headers.signature = 'Signature ' + req.headers.signature + + const parsed = parseHTTPSignature(req, 3600 * 365 * 3) + const publicKey = require('./json/mastodon/public-key.json').publicKey + + const actor = { publicKey } + const verified = isHTTPSignatureVerified(parsed, actor as any) + + expect(verified).to.be.false + }) + + it('Should fail with an invalid public key', async function () { + const req = buildRequestStub() + req.method = 'POST' + req.url = '/accounts/ronan/inbox' + + const mastodonObject = cloneDeep(require('./json/mastodon/http-signature.json')) + req.body = mastodonObject.body + req.headers = mastodonObject.headers + req.headers.signature = 'Signature ' + req.headers.signature + + const parsed = parseHTTPSignature(req, 3600 * 365 * 3) + const publicKey = require('./json/mastodon/bad-public-key.json').publicKey + + const actor = { publicKey } + const verified = isHTTPSignatureVerified(parsed, actor as any) + + expect(verified).to.be.false + }) + + it('Should fail because of clock skew', async function () { + const req = buildRequestStub() + req.method = 'POST' + req.url = '/accounts/ronan/inbox' + + const mastodonObject = cloneDeep(require('./json/mastodon/http-signature.json')) + req.body = mastodonObject.body + req.headers = mastodonObject.headers + req.headers.signature = 'Signature ' + req.headers.signature + + let errored = false + try { + parseHTTPSignature(req) + } catch { + errored = true + } + + expect(errored).to.be.true + }) + + it('Should fail without scheme', async function () { + const req = buildRequestStub() + req.method = 'POST' + req.url = '/accounts/ronan/inbox' + + const mastodonObject = cloneDeep(require('./json/mastodon/http-signature.json')) + req.body = mastodonObject.body + req.headers = mastodonObject.headers + + let errored = false + try { + parseHTTPSignature(req, 3600 * 365 * 3) + } catch { + errored = true + } + + expect(errored).to.be.true + }) + + it('Should succeed with a valid signature', async function () { + const req = buildRequestStub() + req.method = 'POST' + req.url = '/accounts/ronan/inbox' + + const mastodonObject = cloneDeep(require('./json/mastodon/http-signature.json')) + req.body = mastodonObject.body + req.headers = mastodonObject.headers + req.headers.signature = 'Signature ' + req.headers.signature + + const parsed = parseHTTPSignature(req, 3600 * 365 * 3) + const publicKey = require('./json/mastodon/public-key.json').publicKey + + const actor = { publicKey } + const verified = isHTTPSignatureVerified(parsed, actor as any) + + expect(verified).to.be.true + }) + + }) + +}) diff --git a/server/tests/api/activitypub/index.ts b/server/tests/api/activitypub/index.ts new file mode 100644 index 000000000..de8a59978 --- /dev/null +++ b/server/tests/api/activitypub/index.ts @@ -0,0 +1,3 @@ +import './client' +import './helpers' +import './security' diff --git a/server/tests/api/activitypub/json/mastodon/bad-body-http-signature.json b/server/tests/api/activitypub/json/mastodon/bad-body-http-signature.json new file mode 100644 index 000000000..4e7bc3af5 --- /dev/null +++ b/server/tests/api/activitypub/json/mastodon/bad-body-http-signature.json @@ -0,0 +1,93 @@ +{ + "headers": { + "user-agent": "http.rb/3.3.0 (Mastodon/2.5.0; +http://localhost:3000/)", + "host": "localhost", + "date": "Mon, 22 Oct 2018 13:34:22 GMT", + "accept-encoding": "gzip", + "digest": "SHA-256=FEr5j2WSSfdEMcG3NTOXuGU0lUchfTJx4+BtUlWOwDk=", + "content-type": "application/activity+json", + "signature": "keyId=\"http://localhost:3000/users/ronan2#main-key\",algorithm=\"rsa-sha256\",headers=\"(request-target) host date digest content-type\",signature=\"oLKbgxdFXdXsHJ3x/UsG9Svu7oa8Dyqiy6Jif4wqNuhAqRVMRaG18f+dd2OcfFX3XRGF8p8flZkU6vvoEQBauTwGRGcgXAJuKC1zYIWGk+PeiW8lNUnE4qGapWcTiFnIo7FKauNdsgqg/tvgs1pQIdHkDDjZMI64twP7sTN/4vG1PCq+kyqi/DM+ORLi/W7vFuLVHt2Iz7ikfw/R3/mMtS4FwLops+tVYBQ2iQ9DVRhTwLKVbeL/LLVB/tdGzNZ4F4nImBAQQ9I7WpPM6J/k+cBmoEbrUKs8ptx9gbX3OSsl5wlvPVMNzU9F9yb2MrB/Y/J4qssKz+LbiaktKGj7OQ==\"", + "content-length": "2815" + }, + "body": { + "@context": [ + "https://www.w3.org/ns/activitystreams", + "https://w3id.org/security/v1", + { + "manuallyApprovesFollowers": "as:manuallyApprovesFollowers", + "sensitive": "as:sensitive", + "movedTo": { + "@id": "as:movedTo", + "@type": "@id" + }, + "Hashtag": "as:Hashtag", + "ostatus": "http://ostatus.org#", + "atomUri": "ostatus:atomUri", + "inReplyToAtomUri": "ostatus:inReplyToAtomUri", + "conversation": "ostatus:conversation", + "toot": "http://joinmastodon.org/ns#", + "Emoji": "toot:Emoji", + "focalPoint": { + "@container": "@list", + "@id": "toot:focalPoint" + }, + "featured": { + "@id": "toot:featured", + "@type": "@id" + }, + "schema": "http://schema.org#", + "PropertyValue": "schema:PropertyValue", + "value": "schema:value" + } + ], + "id": "http://localhost:3000/users/ronan2/statuses/100939547203370948/activity", + "type": "Create", + "actor": "http://localhost:3000/users/ronan2", + "published": "2018-10-22T13:34:18Z", + "to": [ + "https://www.w3.org/ns/activitystreams#Public" + ], + "cc": [ + "http://localhost:3000/users/ronan2/followers", + "http://localhost:9000/accounts/ronan" + ], + "object": { + "id": "http://localhost:3000/users/ronan2/statuses/100939547203370948", + "type": "Note", + "summary": null, + "inReplyTo": "http://localhost:9000/videos/watch/90e6f8ed-b369-423c-b0c8-f44e5350c752", + "published": "2018-10-22T13:34:18Z", + "url": "http://localhost:3000/@ronan2/100939547203370948", + "attributedTo": "http://localhost:3000/users/ronan2", + "to": [ + "https://www.w3.org/ns/activitystreams#Public" + ], + "cc": [ + "http://localhost:3000/users/ronan2/followers", + "http://localhost:9000/accounts/ronan" + ], + "sensitive": false, + "atomUri": "http://localhost:3000/users/ronan2/statuses/100939547203370948", + "inReplyToAtomUri": "http://localhost:9000/videos/watch/90e6f8ed-b369-423c-b0c8-f44e5350c752", + "conversation": "tag:localhost:3000,2018-10-19:objectId=72:objectType=Conversation", + "content": "

@ronan zergzerg

", + "contentMap": { + "en": "

@ronan zergzerg

" + }, + "attachment": [], + "tag": [ + { + "type": "Mention", + "href": "http://localhost:9000/accounts/ronan", + "name": "@ronan@localhost:9000" + } + ] + }, + "signature": { + "type": "RsaSignature2017", + "creator": "http://localhost:3000/users/ronan2#main-key", + "created": "2018-10-22T13:34:19Z", + "signatureValue": "x+xL4l8ERziYVhwEafHJyBQOInvNZ0gV4ccYd9AtFYeGJagc8fY6jjjhbDRCD7yMhgTjBX69z20MXnDuwpmM6wej3dt1wLKdIyXVViO84nAlqFz7KmNxtk5lDnAVX/vttscT5YUFvw4dbPT2mQiEd1lKbaLftRiIPEomZpQ37+fUkQdcPrnhruPAISO/Sof1n1LFW4mYIffozteQSZBH6HaCVp+MRMIhdMi5e8w7PD48/cZz8D/EU8Vqi91FM76/3tMqg6nLqQ+8bq74Jvt2kzwZlIufe+I55QMpZOmF6hGIJEt+R0JXdjQbtgcELONmNj2dr8sAlzu7zKlAGuJ24Q==" + } + } +} diff --git a/server/tests/api/activitypub/json/mastodon/bad-http-signature.json b/server/tests/api/activitypub/json/mastodon/bad-http-signature.json new file mode 100644 index 000000000..098597db0 --- /dev/null +++ b/server/tests/api/activitypub/json/mastodon/bad-http-signature.json @@ -0,0 +1,93 @@ +{ + "headers": { + "user-agent": "http.rb/3.3.0 (Mastodon/2.5.0; +http://localhost:3000/)", + "host": "localhost", + "date": "Mon, 22 Oct 2018 13:34:22 GMT", + "accept-encoding": "gzip", + "digest": "SHA-256=FEr5j2WSSfdEMcG3NTOXuGU0lUchfTJx4+BtUlWOwDk=", + "content-type": "application/activity+json", + "signature": "keyId=\"http://localhost:3000/users/ronan2#main-key\",algorithm=\"rsa-sha256\",headers=\"(request-target) host date digest content-type\",signature=\"oLKbgxdFXdXsHJ3x/UsG9Svu7oa8Dyqiy6Jif4wqNuhAqRVMRaG18f+dd2OcfFX3XRGF8p8flZkU6vvoEQBauTwGRGcgXAJuKC1zYIWGk+PeiW8lNUnE4qGapWcTiFnIo7FKauNdsgqg/tvgs1pQIdHkDDjZMI64twP7sTN/4vG1PCq+kyqi/DM+ORLi/W7vFuLVHt2Iz7ikfw/R3/mMtS4FwLops+tVYBQ2iQ9DVRhTwLKVbeL/LLVB/tdGzNZ4F4nImBAQQ9I7WpPM6J/k+cBmoEbrUKs8ptx9gbX3OSsl4wlvPVMNzU9F9yb2MrB/Y/J4qssKz+LbiaktKGj7OQ==\"", + "content-length": "2815" + }, + "body": { + "@context": [ + "https://www.w3.org/ns/activitystreams", + "https://w3id.org/security/v1", + { + "manuallyApprovesFollowers": "as:manuallyApprovesFollowers", + "sensitive": "as:sensitive", + "movedTo": { + "@id": "as:movedTo", + "@type": "@id" + }, + "Hashtag": "as:Hashtag", + "ostatus": "http://ostatus.org#", + "atomUri": "ostatus:atomUri", + "inReplyToAtomUri": "ostatus:inReplyToAtomUri", + "conversation": "ostatus:conversation", + "toot": "http://joinmastodon.org/ns#", + "Emoji": "toot:Emoji", + "focalPoint": { + "@container": "@list", + "@id": "toot:focalPoint" + }, + "featured": { + "@id": "toot:featured", + "@type": "@id" + }, + "schema": "http://schema.org#", + "PropertyValue": "schema:PropertyValue", + "value": "schema:value" + } + ], + "id": "http://localhost:3000/users/ronan2/statuses/100939547203370948/activity", + "type": "Create", + "actor": "http://localhost:3000/users/ronan2", + "published": "2018-10-22T13:34:18Z", + "to": [ + "https://www.w3.org/ns/activitystreams#Public" + ], + "cc": [ + "http://localhost:3000/users/ronan2/followers", + "http://localhost:9000/accounts/ronan" + ], + "object": { + "id": "http://localhost:3000/users/ronan2/statuses/100939547203370948", + "type": "Note", + "summary": null, + "inReplyTo": "http://localhost:9000/videos/watch/90e6f8ed-b369-423c-b0c8-f44e5350c752", + "published": "2018-10-22T13:34:18Z", + "url": "http://localhost:3000/@ronan2/100939547203370948", + "attributedTo": "http://localhost:3000/users/ronan2", + "to": [ + "https://www.w3.org/ns/activitystreams#Public" + ], + "cc": [ + "http://localhost:3000/users/ronan2/followers", + "http://localhost:9000/accounts/ronan" + ], + "sensitive": false, + "atomUri": "http://localhost:3000/users/ronan2/statuses/100939547203370948", + "inReplyToAtomUri": "http://localhost:9000/videos/watch/90e6f8ed-b369-423c-b0c8-f44e5350c752", + "conversation": "tag:localhost:3000,2018-10-19:objectId=72:objectType=Conversation", + "content": "

@ronan zergzerg

", + "contentMap": { + "en": "

@ronan zergzerg

" + }, + "attachment": [], + "tag": [ + { + "type": "Mention", + "href": "http://localhost:9000/accounts/ronan", + "name": "@ronan@localhost:9000" + } + ] + }, + "signature": { + "type": "RsaSignature2017", + "creator": "http://localhost:3000/users/ronan2#main-key", + "created": "2018-10-22T13:34:19Z", + "signatureValue": "x+xL4l8ERziYVhwEafHJyBQOInvNZ0gV4ccYd9AtFYeGJagc8fY6jjjhbDRCD7yMhgTjBX69z20MXnDuwpmM6wej3dt1wLKdIyXVViO84nAlqFz7KmNxtk5lDnAVX/vttscT5YUFvw4dbPT2mQiEd1lKbaLftRiIPEomZpQ37+fUkQdcPrnhruPAISO/Sof1n1LFW4mYIffozteQSZBH6HaCVp+MRMIhdMi5e8w7PD48/cZz8D/EU8Vqi91FM76/3tMqg6nLqQ+8bq74Jvt2kzwZlIufe+I55QMpZOmF6hGIJEt+R0JXdjQbtgcELONmNj2dr8sAlzu7zKlAGuJ24Q==" + } + } +} diff --git a/server/tests/api/activitypub/json/mastodon/bad-public-key.json b/server/tests/api/activitypub/json/mastodon/bad-public-key.json new file mode 100644 index 000000000..73d18b3ad --- /dev/null +++ b/server/tests/api/activitypub/json/mastodon/bad-public-key.json @@ -0,0 +1,3 @@ +{ + "publicKey": "-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA0YyuthHtWWgDe0Fdgdp2\ndC5dTJsRqW6pFw5omIYYYjoES/WRewhVxEA54BhmxD3L1zChfx131N1TS8jVowhW\nm999jpUffKCCvLgYKIXETJDHiDeMONVx8wp7v9fS1HiFXo/E5und39gUMs14CMFZ\n6PE5jRV3r4XIKQJHQl7/X5n5FOb2934K+1TKUeBkbft/AushlKatYQakt3qHxpwx\nFvE+JjGo7QTnzdjaOx/e5QvojdGi2Kx4+jl77j2WVcSo5lOBz04OAVJtChtn82vS\nulPdDh3hZcDn+WK67yAhGP6AnzvOybZZS4zowlKiQ3kqjVVXKdl8gAsL4Y7MZ40R\nJQIDAQAB\n-----END PUBLIC KEY-----\n" +} diff --git a/server/tests/api/activitypub/json/mastodon/create-bad-signature.json b/server/tests/api/activitypub/json/mastodon/create-bad-signature.json new file mode 100644 index 000000000..2cd037241 --- /dev/null +++ b/server/tests/api/activitypub/json/mastodon/create-bad-signature.json @@ -0,0 +1,81 @@ +{ + "@context": [ + "https://www.w3.org/ns/activitystreams", + "https://w3id.org/security/v1", + { + "manuallyApprovesFollowers": "as:manuallyApprovesFollowers", + "sensitive": "as:sensitive", + "movedTo": { + "@id": "as:movedTo", + "@type": "@id" + }, + "Hashtag": "as:Hashtag", + "ostatus": "http://ostatus.org#", + "atomUri": "ostatus:atomUri", + "inReplyToAtomUri": "ostatus:inReplyToAtomUri", + "conversation": "ostatus:conversation", + "toot": "http://joinmastodon.org/ns#", + "Emoji": "toot:Emoji", + "focalPoint": { + "@container": "@list", + "@id": "toot:focalPoint" + }, + "featured": { + "@id": "toot:featured", + "@type": "@id" + }, + "schema": "http://schema.org#", + "PropertyValue": "schema:PropertyValue", + "value": "schema:value" + } + ], + "id": "http://localhost:3000/users/ronan2/statuses/100939345950887698/activity", + "type": "Create", + "actor": "http://localhost:3000/users/ronan2", + "published": "2018-10-22T12:43:07Z", + "to": [ + "https://www.w3.org/ns/activitystreams#Public" + ], + "cc": [ + "http://localhost:3000/users/ronan2/followers", + "http://localhost:9000/accounts/ronan" + ], + "object": { + "id": "http://localhost:3000/users/ronan2/statuses/100939345950887698", + "type": "Note", + "summary": null, + "inReplyTo": "http://localhost:9000/videos/watch/90e6f8ed-b369-423c-b0c8-f44e5350c752", + "published": "2018-10-22T12:43:07Z", + "url": "http://localhost:3000/@ronan2/100939345950887698", + "attributedTo": "http://localhost:3000/users/ronan2", + "to": [ + "https://www.w3.org/ns/activitystreams#Public" + ], + "cc": [ + "http://localhost:3000/users/ronan2/followers", + "http://localhost:9000/accounts/ronan" + ], + "sensitive": false, + "atomUri": "http://localhost:3000/users/ronan2/statuses/100939345950887698", + "inReplyToAtomUri": "http://localhost:9000/videos/watch/90e6f8ed-b369-423c-b0c8-f44e5350c752", + "conversation": "tag:localhost:3000,2018-10-19:objectId=72:objectType=Conversation", + "content": "

@ronan zerg

", + "contentMap": { + "en": "

@ronan zerg

" + }, + "attachment": [], + "tag": [ + { + "type": "Mention", + "href": "http://localhost:9000/accounts/ronan", + "name": "@ronan@localhost:9000" + } + ] + }, + "signature": { + "type": "RsaSignature2017", + "creator": "http://localhost:3000/users/ronan2#main-key", + "created": "2018-10-22T12:43:08Z", + "signatureValue": "Vgr8nA0agPr9TcA4BlX+MWhmuE+rBcoIJLpnPbm3E5SnOCXbgjEfEaTLqfuzzkKNsR3PBbkvi3YWK4/DxJ0zmpzSB7yy4NRzluQMVQHqJiFKXAX3Sr3fIrK24xkWW9/F207c1NpFajSGbgnFKBdtFE0e5VqwSrSoOJkZukZW/2ATSnsyzblieuUmvTWpD0PqpUOsynPjw+RqZnqPn0cjw1z2Dm7ZRt3trnyMTXFYZw5U/YuqMY2kpadD6vq780md8kXlJIylxG6ZrlO2jz9fJdnfuVq43d4QFNsBm1K1r2WtNqX+i+wiqh+u3PjF4pzXtl/a3hJOH18IfZnK7I21mQ==" + } +} diff --git a/server/tests/api/activitypub/json/mastodon/create.json b/server/tests/api/activitypub/json/mastodon/create.json new file mode 100644 index 000000000..0be271bb8 --- /dev/null +++ b/server/tests/api/activitypub/json/mastodon/create.json @@ -0,0 +1,81 @@ +{ + "@context": [ + "https://www.w3.org/ns/activitystreams", + "https://w3id.org/security/v1", + { + "manuallyApprovesFollowers": "as:manuallyApprovesFollowers", + "sensitive": "as:sensitive", + "movedTo": { + "@id": "as:movedTo", + "@type": "@id" + }, + "Hashtag": "as:Hashtag", + "ostatus": "http://ostatus.org#", + "atomUri": "ostatus:atomUri", + "inReplyToAtomUri": "ostatus:inReplyToAtomUri", + "conversation": "ostatus:conversation", + "toot": "http://joinmastodon.org/ns#", + "Emoji": "toot:Emoji", + "focalPoint": { + "@container": "@list", + "@id": "toot:focalPoint" + }, + "featured": { + "@id": "toot:featured", + "@type": "@id" + }, + "schema": "http://schema.org#", + "PropertyValue": "schema:PropertyValue", + "value": "schema:value" + } + ], + "id": "http://localhost:3000/users/ronan2/statuses/100939345950887698/activity", + "type": "Create", + "actor": "http://localhost:3000/users/ronan2", + "published": "2018-10-22T12:43:07Z", + "to": [ + "https://www.w3.org/ns/activitystreams#Public" + ], + "cc": [ + "http://localhost:3000/users/ronan2/followers", + "http://localhost:9000/accounts/ronan" + ], + "object": { + "id": "http://localhost:3000/users/ronan2/statuses/100939345950887698", + "type": "Note", + "summary": null, + "inReplyTo": "http://localhost:9000/videos/watch/90e6f8ed-b369-423c-b0c8-f44e5350c752", + "published": "2018-10-22T12:43:07Z", + "url": "http://localhost:3000/@ronan2/100939345950887698", + "attributedTo": "http://localhost:3000/users/ronan2", + "to": [ + "https://www.w3.org/ns/activitystreams#Public" + ], + "cc": [ + "http://localhost:3000/users/ronan2/followers", + "http://localhost:9000/accounts/ronan" + ], + "sensitive": false, + "atomUri": "http://localhost:3000/users/ronan2/statuses/100939345950887698", + "inReplyToAtomUri": "http://localhost:9000/videos/watch/90e6f8ed-b369-423c-b0c8-f44e5350c752", + "conversation": "tag:localhost:3000,2018-10-19:objectId=72:objectType=Conversation", + "content": "

@ronan zerg

", + "contentMap": { + "en": "

@ronan zerg

" + }, + "attachment": [], + "tag": [ + { + "type": "Mention", + "href": "http://localhost:9000/accounts/ronan", + "name": "@ronan@localhost:9000" + } + ] + }, + "signature": { + "type": "RsaSignature2017", + "creator": "http://localhost:3000/users/ronan2#main-key", + "created": "2018-10-22T12:43:08Z", + "signatureValue": "VgR8nA0agPr9TcA4BlX+MWhmuE+rBcoIJLpnPbm3E5SnOCXbgjEfEaTLqfuzzkKNsR3PBbkvi3YWK4/DxJ0zmpzSB7yy4NRzluQMVQHqJiFKXAX3Sr3fIrK24xkWW9/F207c1NpFajSGbgnFKBdtFE0e5VqwSrSoOJkZukZW/2ATSnsyzblieuUmvTWpD0PqpUOsynPjw+RqZnqPn0cjw1z2Dm7ZRt3trnyMTXFYZw5U/YuqMY2kpadD6vq780md8kXlJIylxG6ZrlO2jz9fJdnfuVq43d4QFNsBm1K1r2WtNqX+i+wiqh+u3PjF4pzXtl/a3hJOH18IfZnK7I21mQ==" + } +} diff --git a/server/tests/api/activitypub/json/mastodon/http-signature.json b/server/tests/api/activitypub/json/mastodon/http-signature.json new file mode 100644 index 000000000..4e7bc3af5 --- /dev/null +++ b/server/tests/api/activitypub/json/mastodon/http-signature.json @@ -0,0 +1,93 @@ +{ + "headers": { + "user-agent": "http.rb/3.3.0 (Mastodon/2.5.0; +http://localhost:3000/)", + "host": "localhost", + "date": "Mon, 22 Oct 2018 13:34:22 GMT", + "accept-encoding": "gzip", + "digest": "SHA-256=FEr5j2WSSfdEMcG3NTOXuGU0lUchfTJx4+BtUlWOwDk=", + "content-type": "application/activity+json", + "signature": "keyId=\"http://localhost:3000/users/ronan2#main-key\",algorithm=\"rsa-sha256\",headers=\"(request-target) host date digest content-type\",signature=\"oLKbgxdFXdXsHJ3x/UsG9Svu7oa8Dyqiy6Jif4wqNuhAqRVMRaG18f+dd2OcfFX3XRGF8p8flZkU6vvoEQBauTwGRGcgXAJuKC1zYIWGk+PeiW8lNUnE4qGapWcTiFnIo7FKauNdsgqg/tvgs1pQIdHkDDjZMI64twP7sTN/4vG1PCq+kyqi/DM+ORLi/W7vFuLVHt2Iz7ikfw/R3/mMtS4FwLops+tVYBQ2iQ9DVRhTwLKVbeL/LLVB/tdGzNZ4F4nImBAQQ9I7WpPM6J/k+cBmoEbrUKs8ptx9gbX3OSsl5wlvPVMNzU9F9yb2MrB/Y/J4qssKz+LbiaktKGj7OQ==\"", + "content-length": "2815" + }, + "body": { + "@context": [ + "https://www.w3.org/ns/activitystreams", + "https://w3id.org/security/v1", + { + "manuallyApprovesFollowers": "as:manuallyApprovesFollowers", + "sensitive": "as:sensitive", + "movedTo": { + "@id": "as:movedTo", + "@type": "@id" + }, + "Hashtag": "as:Hashtag", + "ostatus": "http://ostatus.org#", + "atomUri": "ostatus:atomUri", + "inReplyToAtomUri": "ostatus:inReplyToAtomUri", + "conversation": "ostatus:conversation", + "toot": "http://joinmastodon.org/ns#", + "Emoji": "toot:Emoji", + "focalPoint": { + "@container": "@list", + "@id": "toot:focalPoint" + }, + "featured": { + "@id": "toot:featured", + "@type": "@id" + }, + "schema": "http://schema.org#", + "PropertyValue": "schema:PropertyValue", + "value": "schema:value" + } + ], + "id": "http://localhost:3000/users/ronan2/statuses/100939547203370948/activity", + "type": "Create", + "actor": "http://localhost:3000/users/ronan2", + "published": "2018-10-22T13:34:18Z", + "to": [ + "https://www.w3.org/ns/activitystreams#Public" + ], + "cc": [ + "http://localhost:3000/users/ronan2/followers", + "http://localhost:9000/accounts/ronan" + ], + "object": { + "id": "http://localhost:3000/users/ronan2/statuses/100939547203370948", + "type": "Note", + "summary": null, + "inReplyTo": "http://localhost:9000/videos/watch/90e6f8ed-b369-423c-b0c8-f44e5350c752", + "published": "2018-10-22T13:34:18Z", + "url": "http://localhost:3000/@ronan2/100939547203370948", + "attributedTo": "http://localhost:3000/users/ronan2", + "to": [ + "https://www.w3.org/ns/activitystreams#Public" + ], + "cc": [ + "http://localhost:3000/users/ronan2/followers", + "http://localhost:9000/accounts/ronan" + ], + "sensitive": false, + "atomUri": "http://localhost:3000/users/ronan2/statuses/100939547203370948", + "inReplyToAtomUri": "http://localhost:9000/videos/watch/90e6f8ed-b369-423c-b0c8-f44e5350c752", + "conversation": "tag:localhost:3000,2018-10-19:objectId=72:objectType=Conversation", + "content": "

@ronan zergzerg

", + "contentMap": { + "en": "

@ronan zergzerg

" + }, + "attachment": [], + "tag": [ + { + "type": "Mention", + "href": "http://localhost:9000/accounts/ronan", + "name": "@ronan@localhost:9000" + } + ] + }, + "signature": { + "type": "RsaSignature2017", + "creator": "http://localhost:3000/users/ronan2#main-key", + "created": "2018-10-22T13:34:19Z", + "signatureValue": "x+xL4l8ERziYVhwEafHJyBQOInvNZ0gV4ccYd9AtFYeGJagc8fY6jjjhbDRCD7yMhgTjBX69z20MXnDuwpmM6wej3dt1wLKdIyXVViO84nAlqFz7KmNxtk5lDnAVX/vttscT5YUFvw4dbPT2mQiEd1lKbaLftRiIPEomZpQ37+fUkQdcPrnhruPAISO/Sof1n1LFW4mYIffozteQSZBH6HaCVp+MRMIhdMi5e8w7PD48/cZz8D/EU8Vqi91FM76/3tMqg6nLqQ+8bq74Jvt2kzwZlIufe+I55QMpZOmF6hGIJEt+R0JXdjQbtgcELONmNj2dr8sAlzu7zKlAGuJ24Q==" + } + } +} diff --git a/server/tests/api/activitypub/json/mastodon/public-key.json b/server/tests/api/activitypub/json/mastodon/public-key.json new file mode 100644 index 000000000..b7b9b8308 --- /dev/null +++ b/server/tests/api/activitypub/json/mastodon/public-key.json @@ -0,0 +1,3 @@ +{ + "publicKey": "-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA0YyuthHtWWgDe0Fdgdp2\ndC5dTJsRqW6pFw5omIYYYjoES/WRewhVxEA54BhmxD3L1zChfx131N1TS8jVowhW\nm999jpUffKCCvLgYKIXETJDHiDeMONVx8wp7v9fS1HiFXo/E5und39gUMs14CMFZ\n6PE5jRV3r4XIKQJHQl7/X5n5FOb2934K+1TKUeBkbft/AushlKatYQakt3qHxpwx\nFvE+JjGo7QTnzdjaOx/e5QvojdGi2Kx4+jl87j2WVcSo5lOBz04OAVJtChtn82vS\nulPdDh3hZcDn+WK67yAhGP6AnzvOybZZS4zowlKiQ3kqjVVXKdl8gAsL4Y7MZ40R\nJQIDAQAB\n-----END PUBLIC KEY-----\n" +} diff --git a/server/tests/api/activitypub/json/peertube/announce-without-context.json b/server/tests/api/activitypub/json/peertube/announce-without-context.json new file mode 100644 index 000000000..5f2af0cde --- /dev/null +++ b/server/tests/api/activitypub/json/peertube/announce-without-context.json @@ -0,0 +1,13 @@ +{ + "type": "Announce", + "id": "http://localhost:9002/videos/watch/997111d4-e8d8-4f45-99d3-857905785d05/announces/1", + "actor": "http://localhost:9002/accounts/peertube", + "object": "http://localhost:9002/videos/watch/997111d4-e8d8-4f45-99d3-857905785d05", + "to": [ + "https://www.w3.org/ns/activitystreams#Public", + "http://localhost:9002/accounts/peertube/followers", + "http://localhost:9002/video-channels/root_channel/followers", + "http://localhost:9002/accounts/root/followers" + ], + "cc": [] +} diff --git a/server/tests/api/activitypub/json/peertube/invalid-keys.json b/server/tests/api/activitypub/json/peertube/invalid-keys.json new file mode 100644 index 000000000..0544e96b9 --- /dev/null +++ b/server/tests/api/activitypub/json/peertube/invalid-keys.json @@ -0,0 +1,6 @@ +{ + "publicKey": "-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAqjQGdH6D3naKmSbbr/Df\nEh1H42F3WlHYXuxKLkm5Bemjdde+GwHYdz5m3fcIWw3HTzfA+y9Of8epGdfSrtYO\nwAyc3Zoy7afPNa4bZXqhJ1Im41rMGieiCuUn4uTPPucIjC0gCkVwvuQr3Elbk55s\nIkczDkseJuadTvG+A1e4uNY2lnRmVhf4g5B90u6CLe2KdbPpifRoKlw9zaUBj4/F\npP5S75TS5l1DfJQIq2lp8RwrH6FvGKLnWlbGeNYX96DDvlA5Sxoxz6a+bTV9OopM\n7mS7eP8zF8lKXYUu8cjIscKm+XqGmyRoPyw2Pp53tew29idRUocVQHGBnlNbpKdd\naQIDAQAB\n-----END PUBLIC KEY-----\n", + "privateKey": "-----BEGIN RSA PRIVATE KEY-----\nMIIEpAIBAAKCAQEAqjQGdH6D3naKmSbbr/DfEh1H42F3WlHYXuxKLkm5Bemjdde+\nGwHYdz5m3fcIWw3HTzfA+y9Of8epGdfSrtYOwAyc3Zoy7afPNa4bZXqhJ1Im41rM\nGieiCuUn4uTPPucIjC0gCkVwvuQr3Elbk55sIkczDkseJuadTvG+A1e4uNY2lnRm\nVhf4g5B90u6CLe2KdbPpifRoKlw9zaUBj4/FpP5S75TS5l1DfJQIq2lp8RwrH6Fv\nGKLnWlbGeNYX96DDvlA5Sxoxz6a+bTV9OopM7mS7eP8zF8lKXYUu8cjIscKm+XqG\nmyRoPyw3Pp53tew29idRUocVQHGBnlNbpKddaQIDAQABAoIBAQCnBZawCtbtH/ay\ng+dhqEW/SOyavbKZ92cU/1tsQPxISRYXNjdf2VfK7HmVqC2S7NqBanz+AVZPHmda\n7OfamkSvQbFN5VvEy8ATNV+9HbG3HG78/MT9hZcGigmyJkcZuy4wILgoXCxfpxlD\netla60PB/4yioiRcmEIWjjOgpByphDJ7RuuuptyEvgjUjpPtvHK47O/loaD2HFJk\nbIYbRirbjUjITRjQxGVIvanqiwPG9pB26YDLxDOoXEumcnzRcEFWNdvoleaLgquS\nn/zVsXWEq4+1i7t44DDstWUt/2Bw5ksIkSdayQ6oy3vzre3YFHwvbVZ7qtQQgpru\nx+NIolZhAoGBAN1RgNj8zy9Py3SJdsoXtnuCItfD7eo7LWXUa06cM/NS695Q+/to\naa5i3cJnRlv+b+b3VvnhkhIBLfFQW+hWwPnnxJEehcm09ddN9zbWrZ4Yv9yYu+8d\nTLGyWL8kPFF1dz+29DcrSv3tXEOwxByX/O4U/X/i3wl2WhkybxVFnCuvAoGBAMTf\n91BgLzvcYKOxH+vRPOJY7g2HKGFe35R91M4E+9Eq1rq4LUQHBb3fhRh4+scNu0yb\nNfN1Zdx2nbgCXdTKomF1Ahxp58/A2iU65vVzL6hYfWXEGSmoBqsGCIpIxQ9jgB9k\nCl7t/Ban8Z/ORHTjI9fpHlSZyCWJ3ajepiM2a1ZnAoGAPpDO6wi1DXvyWVSPF1yS\nwuGsNfD2rjPihpoBZ+yypwP3GBcu1QjUb28Vn+KQOmt4eQPNO8DwCVT6BvEfulPk\nJAHISPom+jnFEgPBcmhIFpyKiLNI1bUjvExd2FNHFgQuHP38ligQAC782Un8dtTk\ntO2MKH4bbVJe8CaYzpuqJZMCgYABZyMpBHZxs8FQiUuT75rCdiXEHOlxwC5RrY/d\no/VzaR28mOFhsbcdwkD9iqcm0fc6tYRt5rFCH+pBzGqEwKjljuLj9vE67sHfMAtD\nRn3Zcj/6gKo5PMRHZbSb36bf1DKuhpT4VjPMqYe0PtEIEDJKMJQRwELH2bKlqGiA\nqbucEwKBgQCkS85JnpHEV/tSylsEEn2W3CQCx58zl7iZNV7h/tWMR4AyrcI0HqP6\nllJ7V/Cfw66MgelPnosKgagwLVI6gsqDtjnzYo3XuMRVlYIySJ/jV3eiUNkV2Ky2\nfp/gA9sVgp38QSr+xB9E0LNStcbqDzoCCcDRws/SK7PbkQH9KV47tQ==\n-----END RSA PRIVATE KEY-----" +} + + diff --git a/server/tests/api/activitypub/json/peertube/keys.json b/server/tests/api/activitypub/json/peertube/keys.json new file mode 100644 index 000000000..1a7700865 --- /dev/null +++ b/server/tests/api/activitypub/json/peertube/keys.json @@ -0,0 +1,4 @@ +{ + "publicKey": "-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAqjQGdH6D3naKmSbbr/Df\nEh1H42F3WlHYXuxKLkm5Bemjdde+GwHYdz5m3fcIWw3HTzfA+y9Of8epGdfSrtYO\nwAyc3Zoy7afPNa4bZXqhJ1Im41rMGieiCuUn4uTPPucIjC0gCkVwvuQr3Elbk55s\nIkczDkseJuadTvG+A1e4uNY2lnRmVhf4g5B90u6CLe2KdbPpifRoKlw9zaUBj4/F\npP5S75TS5l1DfJQIq2lp8RwrH6FvGKLnWlbGeNYX96DDvlA5Sxoxz6a+bTV9OopM\n7mS7eP8zF8lKXYUu8cjIscKm+XqGmyRoPyw3Pp53tew29idRUocVQHGBnlNbpKdd\naQIDAQAB\n-----END PUBLIC KEY-----\n", + "privateKey": "-----BEGIN RSA PRIVATE KEY-----\nMIIEpAIBAAKCAQEAqjQGdH6D3naKmSbbr/DfEh1H42F3WlHYXuxKLkm5Bemjdde+\nGwHYdz5m3fcIWw3HTzfA+y9Of8epGdfSrtYOwAyc3Zoy7afPNa4bZXqhJ1Im41rM\nGieiCuUn4uTPPucIjC0gCkVwvuQr3Elbk55sIkczDkseJuadTvG+A1e4uNY2lnRm\nVhf4g5B90u6CLe2KdbPpifRoKlw9zaUBj4/FpP5S75TS5l1DfJQIq2lp8RwrH6Fv\nGKLnWlbGeNYX96DDvlA5Sxoxz6a+bTV9OopM7mS7eP8zF8lKXYUu8cjIscKm+XqG\nmyRoPyw3Pp53tew29idRUocVQHGBnlNbpKddaQIDAQABAoIBAQCnBZawCtbtH/ay\ng+dhqEW/SOyavbKZ92cU/1tsQPxISRYXNjdf2VfK7HmVqC2S7NqBanz+AVZPHmda\n7OfamkSvQbFN5VvEy8ATNV+9HbG3HG78/MT9hZcGigmyJkcZuy4wILgoXCxfpxlD\netla60PB/4yioiRcmEIWjjOgpByphDJ7RuuuptyEvgjUjpPtvHK47O/loaD2HFJk\nbIYbRirbjUjITRjQxGVIvanqiwPG9pB26YDLxDOoXEumcnzRcEFWNdvoleaLgquS\nn/zVsXWEq4+1i7t44DDstWUt/2Bw5ksIkSdayQ6oy3vzre3YFHwvbVZ7qtQQgpru\nx+NIolZhAoGBAN1RgNj8zy9Py3SJdsoXtnuCItfD7eo7LWXUa06cM/NS695Q+/to\naa5i3cJnRlv+b+b3VvnhkhIBLfFQW+hWwPnnxJEehcm09ddN9zbWrZ4Yv9yYu+8d\nTLGyWL8kPFF1dz+29DcrSv3tXEOwxByX/O4U/X/i3wl2WhkybxVFnCuvAoGBAMTf\n91BgLzvcYKOxH+vRPOJY7g2HKGFe35R91M4E+9Eq1rq4LUQHBb3fhRh4+scNu0yb\nNfN1Zdx2nbgCXdTKomF1Ahxp58/A2iU65vVzL6hYfWXEGSmoBqsGCIpIxQ9jgB9k\nCl7t/Ban8Z/ORHTjI9fpHlSZyCWJ3ajepiM2a1ZnAoGAPpDO6wi1DXvyWVSPF1yS\nwuGsNfD2rjPihpoBZ+yypwP3GBcu1QjUb28Vn+KQOmt4eQPNO8DwCVT6BvEfulPk\nJAHISPom+jnFEgPBcmhIFpyKiLNI1bUjvExd2FNHFgQuHP38ligQAC782Un8dtTk\ntO2MKH4bbVJe8CaYzpuqJZMCgYABZyMpBHZxs8FQiUuT75rCdiXEHOlxwC5RrY/d\no/VzaR28mOFhsbcdwkD9iqcm0fc6tYRt5rFCH+pBzGqEwKjljuLj9vE67sHfMAtD\nRn3Zcj/6gKo5PMRHZbSb36bf1DKuhpT4VjPMqYe0PtEIEDJKMJQRwELH2bKlqGiA\nqbucEwKBgQCkS85JnpHEV/tSylsEEn2W3CQCx58zl7iZNV7h/tWMR4AyrcI0HqP6\nllJ7V/Cfw66MgelPnosKgagwLVI6gsqDtjnzYo3XuMRVlYIySJ/jV3eiUNkV2Ky2\nfp/gA9sVgp38QSr+xB9E0LNStcbqDzoCCcDRws/SK7PbkQH9KV47tQ==\n-----END RSA PRIVATE KEY-----" +} 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 @@ +/* tslint:disable:no-unused-expression */ + +import 'mocha' + +import { flushAndRunMultipleServers, flushTests, killallServers, makeAPRequest, makeFollowRequest, ServerInfo } from '../../utils' +import { HTTP_SIGNATURE } from '../../../initializers' +import { buildDigest, buildGlobalHeaders } from '../../../lib/job-queue/handlers/utils/activitypub-http-utils' +import * as chai from 'chai' +import { setActorField } from '../../utils/miscs/sql' +import { activityPubContextify, buildSignedActivity } from '../../../helpers/activitypub' + +const expect = chai.expect + +function setKeysOfServer2 (serverNumber: number, publicKey: string, privateKey: string) { + return Promise.all([ + setActorField(serverNumber, 'http://localhost:9002/accounts/peertube', 'publicKey', publicKey), + setActorField(serverNumber, 'http://localhost:9002/accounts/peertube', 'privateKey', privateKey) + ]) +} + +function setKeysOfServer3 (serverNumber: number, publicKey: string, privateKey: string) { + return Promise.all([ + setActorField(serverNumber, 'http://localhost:9003/accounts/peertube', 'publicKey', publicKey), + setActorField(serverNumber, 'http://localhost:9003/accounts/peertube', 'privateKey', privateKey) + ]) +} + +describe('Test ActivityPub security', function () { + let servers: ServerInfo[] + let url: string + + const keys = require('./json/peertube/keys.json') + const invalidKeys = require('./json/peertube/invalid-keys.json') + const baseHttpSignature = { + algorithm: HTTP_SIGNATURE.ALGORITHM, + authorizationHeaderName: HTTP_SIGNATURE.HEADER_NAME, + keyId: 'acct:peertube@localhost:9002', + key: keys.privateKey, + headers: HTTP_SIGNATURE.HEADERS_TO_SIGN + } + + // --------------------------------------------------------------- + + before(async function () { + this.timeout(60000) + + servers = await flushAndRunMultipleServers(3) + + url = servers[0].url + '/inbox' + + await setKeysOfServer2(1, keys.publicKey, keys.privateKey) + + const to = { url: 'http://localhost:9001/accounts/peertube' } + const by = { url: 'http://localhost:9002/accounts/peertube', privateKey: keys.privateKey } + await makeFollowRequest(to, by) + }) + + describe('When checking HTTP signature', function () { + + it('Should fail with an invalid digest', async function () { + const body = activityPubContextify(require('./json/peertube/announce-without-context.json')) + const headers = { + Digest: buildDigest({ hello: 'coucou' }) + } + + const { response } = await makeAPRequest(url, body, baseHttpSignature, headers) + + expect(response.statusCode).to.equal(403) + }) + + it('Should fail with an invalid date', async function () { + const body = activityPubContextify(require('./json/peertube/announce-without-context.json')) + const headers = buildGlobalHeaders(body) + headers['date'] = 'Wed, 21 Oct 2015 07:28:00 GMT' + + const { response } = await makeAPRequest(url, body, baseHttpSignature, headers) + + expect(response.statusCode).to.equal(403) + }) + + it('Should fail with bad keys', async function () { + await setKeysOfServer2(1, invalidKeys.publicKey, invalidKeys.privateKey) + await setKeysOfServer2(2, invalidKeys.publicKey, invalidKeys.privateKey) + + const body = activityPubContextify(require('./json/peertube/announce-without-context.json')) + const headers = buildGlobalHeaders(body) + + const { response } = await makeAPRequest(url, body, baseHttpSignature, headers) + + expect(response.statusCode).to.equal(403) + }) + + it('Should succeed with a valid HTTP signature', async function () { + await setKeysOfServer2(1, keys.publicKey, keys.privateKey) + await setKeysOfServer2(2, keys.publicKey, keys.privateKey) + + const body = activityPubContextify(require('./json/peertube/announce-without-context.json')) + const headers = buildGlobalHeaders(body) + + const { response } = await makeAPRequest(url, body, baseHttpSignature, headers) + + expect(response.statusCode).to.equal(204) + }) + }) + + describe('When checking Linked Data Signature', function () { + before(async () => { + await setKeysOfServer3(3, keys.publicKey, keys.privateKey) + + const to = { url: 'http://localhost:9001/accounts/peertube' } + const by = { url: 'http://localhost:9003/accounts/peertube', privateKey: keys.privateKey } + await makeFollowRequest(to, by) + }) + + it('Should fail with bad keys', async function () { + this.timeout(10000) + + await setKeysOfServer3(1, invalidKeys.publicKey, invalidKeys.privateKey) + await setKeysOfServer3(3, invalidKeys.publicKey, invalidKeys.privateKey) + + const body = require('./json/peertube/announce-without-context.json') + body.actor = 'http://localhost:9003/accounts/peertube' + + const signer: any = { privateKey: invalidKeys.privateKey, url: 'http://localhost:9003/accounts/peertube' } + const signedBody = await buildSignedActivity(signer, body) + + const headers = buildGlobalHeaders(signedBody) + + const { response } = await makeAPRequest(url, signedBody, baseHttpSignature, headers) + + expect(response.statusCode).to.equal(403) + }) + + it('Should fail with an altered body', async function () { + this.timeout(10000) + + await setKeysOfServer3(1, keys.publicKey, keys.privateKey) + await setKeysOfServer3(3, keys.publicKey, keys.privateKey) + + const body = require('./json/peertube/announce-without-context.json') + body.actor = 'http://localhost:9003/accounts/peertube' + + const signer: any = { privateKey: keys.privateKey, url: 'http://localhost:9003/accounts/peertube' } + const signedBody = await buildSignedActivity(signer, body) + + signedBody.actor = 'http://localhost:9003/account/peertube' + + const headers = buildGlobalHeaders(signedBody) + + const { response } = await makeAPRequest(url, signedBody, baseHttpSignature, headers) + + expect(response.statusCode).to.equal(403) + }) + + it('Should succeed with a valid signature', async function () { + this.timeout(10000) + + const body = require('./json/peertube/announce-without-context.json') + body.actor = 'http://localhost:9003/accounts/peertube' + + const signer: any = { privateKey: keys.privateKey, url: 'http://localhost:9003/accounts/peertube' } + const signedBody = await buildSignedActivity(signer, body) + + const headers = buildGlobalHeaders(signedBody) + + const { response } = await makeAPRequest(url, signedBody, baseHttpSignature, headers) + + expect(response.statusCode).to.equal(204) + }) + }) + + after(async function () { + killallServers(servers) + + // Keep the logs if the test failed + if (this['ok']) { + await flushTests() + } + }) +}) diff --git a/server/tests/api/index-4.ts b/server/tests/api/index-4.ts index 8e69b95a6..7d8be2b3d 100644 --- a/server/tests/api/index-4.ts +++ b/server/tests/api/index-4.ts @@ -1 +1,2 @@ import './redundancy' +import './activitypub' diff --git a/server/tests/index.ts b/server/tests/index.ts index e659fd3df..ed16d65dd 100644 --- a/server/tests/index.ts +++ b/server/tests/index.ts @@ -1,6 +1,5 @@ // Order of the tests we want to execute import './client' -import './activitypub' import './feeds/' import './cli/' import './api/' diff --git a/server/tests/utils/index.ts b/server/tests/utils/index.ts index 897389824..905d93823 100644 --- a/server/tests/utils/index.ts +++ b/server/tests/utils/index.ts @@ -4,8 +4,10 @@ export * from './server/clients' export * from './server/config' export * from './users/login' export * from './miscs/miscs' +export * from './miscs/stubs' export * from './server/follows' export * from './requests/requests' +export * from './requests/activitypub' export * from './server/servers' export * from './videos/services' export * from './users/users' diff --git a/server/tests/utils/miscs/sql.ts b/server/tests/utils/miscs/sql.ts new file mode 100644 index 000000000..204ff5163 --- /dev/null +++ b/server/tests/utils/miscs/sql.ts @@ -0,0 +1,29 @@ +import * as Sequelize from 'sequelize' + +function getSequelize (serverNumber: number) { + const dbname = 'peertube_test' + serverNumber + const username = 'peertube' + const password = 'peertube' + const host = 'localhost' + const port = 5432 + + return new Sequelize(dbname, username, password, { + dialect: 'postgres', + host, + port, + operatorsAliases: false, + logging: false + }) +} + +function setActorField (serverNumber: number, to: string, field: string, value: string) { + const seq = getSequelize(serverNumber) + + const options = { type: Sequelize.QueryTypes.UPDATE } + + return seq.query(`UPDATE actor SET "${field}" = '${value}' WHERE url = '${to}'`, options) +} + +export { + setActorField +} diff --git a/server/tests/utils/miscs/stubs.ts b/server/tests/utils/miscs/stubs.ts new file mode 100644 index 000000000..d1eb0e3b2 --- /dev/null +++ b/server/tests/utils/miscs/stubs.ts @@ -0,0 +1,14 @@ +function buildRequestStub (): any { + return { } +} + +function buildResponseStub (): any { + return { + locals: {} + } +} + +export { + buildResponseStub, + buildRequestStub +} diff --git a/server/tests/utils/requests/activitypub.ts b/server/tests/utils/requests/activitypub.ts new file mode 100644 index 000000000..e3e08ce67 --- /dev/null +++ b/server/tests/utils/requests/activitypub.ts @@ -0,0 +1,43 @@ +import { doRequest } from '../../../helpers/requests' +import { HTTP_SIGNATURE } from '../../../initializers' +import { buildGlobalHeaders } from '../../../lib/job-queue/handlers/utils/activitypub-http-utils' +import { activityPubContextify } from '../../../helpers/activitypub' + +function makeAPRequest (url: string, body: any, httpSignature: any, headers: any) { + const options = { + method: 'POST', + uri: url, + json: body, + httpSignature, + headers + } + + return doRequest(options) +} + +async function makeFollowRequest (to: { url: string }, by: { url: string, privateKey }) { + const follow = { + type: 'Follow', + id: by.url + '/toto', + actor: by.url, + object: to.url + } + + const body = activityPubContextify(follow) + + const httpSignature = { + algorithm: HTTP_SIGNATURE.ALGORITHM, + authorizationHeaderName: HTTP_SIGNATURE.HEADER_NAME, + keyId: by.url, + key: by.privateKey, + headers: HTTP_SIGNATURE.HEADERS_TO_SIGN + } + const headers = buildGlobalHeaders(body) + + return makeAPRequest(to.url, body, httpSignature, headers) +} + +export { + makeAPRequest, + makeFollowRequest +} -- cgit v1.2.3 From 5c6d985faeef1d6793d3f44ca6374f1a9b722806 Mon Sep 17 00:00:00 2001 From: Chocobozzz Date: Wed, 14 Nov 2018 15:01:28 +0100 Subject: Check activities host --- server/tests/api/activitypub/security.ts | 16 ++++++++-------- server/tests/utils/requests/activitypub.ts | 6 +++--- 2 files changed, 11 insertions(+), 11 deletions(-) (limited to 'server/tests') diff --git a/server/tests/api/activitypub/security.ts b/server/tests/api/activitypub/security.ts index c5428abbb..e7899bb14 100644 --- a/server/tests/api/activitypub/security.ts +++ b/server/tests/api/activitypub/security.ts @@ -2,7 +2,7 @@ import 'mocha' -import { flushAndRunMultipleServers, flushTests, killallServers, makeAPRequest, makeFollowRequest, ServerInfo } from '../../utils' +import { flushAndRunMultipleServers, flushTests, killallServers, makePOSTAPRequest, makeFollowRequest, ServerInfo } from '../../utils' import { HTTP_SIGNATURE } from '../../../initializers' import { buildDigest, buildGlobalHeaders } from '../../../lib/job-queue/handlers/utils/activitypub-http-utils' import * as chai from 'chai' @@ -63,7 +63,7 @@ describe('Test ActivityPub security', function () { Digest: buildDigest({ hello: 'coucou' }) } - const { response } = await makeAPRequest(url, body, baseHttpSignature, headers) + const { response } = await makePOSTAPRequest(url, body, baseHttpSignature, headers) expect(response.statusCode).to.equal(403) }) @@ -73,7 +73,7 @@ describe('Test ActivityPub security', function () { const headers = buildGlobalHeaders(body) headers['date'] = 'Wed, 21 Oct 2015 07:28:00 GMT' - const { response } = await makeAPRequest(url, body, baseHttpSignature, headers) + const { response } = await makePOSTAPRequest(url, body, baseHttpSignature, headers) expect(response.statusCode).to.equal(403) }) @@ -85,7 +85,7 @@ describe('Test ActivityPub security', function () { const body = activityPubContextify(require('./json/peertube/announce-without-context.json')) const headers = buildGlobalHeaders(body) - const { response } = await makeAPRequest(url, body, baseHttpSignature, headers) + const { response } = await makePOSTAPRequest(url, body, baseHttpSignature, headers) expect(response.statusCode).to.equal(403) }) @@ -97,7 +97,7 @@ describe('Test ActivityPub security', function () { const body = activityPubContextify(require('./json/peertube/announce-without-context.json')) const headers = buildGlobalHeaders(body) - const { response } = await makeAPRequest(url, body, baseHttpSignature, headers) + const { response } = await makePOSTAPRequest(url, body, baseHttpSignature, headers) expect(response.statusCode).to.equal(204) }) @@ -126,7 +126,7 @@ describe('Test ActivityPub security', function () { const headers = buildGlobalHeaders(signedBody) - const { response } = await makeAPRequest(url, signedBody, baseHttpSignature, headers) + const { response } = await makePOSTAPRequest(url, signedBody, baseHttpSignature, headers) expect(response.statusCode).to.equal(403) }) @@ -147,7 +147,7 @@ describe('Test ActivityPub security', function () { const headers = buildGlobalHeaders(signedBody) - const { response } = await makeAPRequest(url, signedBody, baseHttpSignature, headers) + const { response } = await makePOSTAPRequest(url, signedBody, baseHttpSignature, headers) expect(response.statusCode).to.equal(403) }) @@ -163,7 +163,7 @@ describe('Test ActivityPub security', function () { const headers = buildGlobalHeaders(signedBody) - const { response } = await makeAPRequest(url, signedBody, baseHttpSignature, headers) + const { response } = await makePOSTAPRequest(url, signedBody, baseHttpSignature, headers) expect(response.statusCode).to.equal(204) }) diff --git a/server/tests/utils/requests/activitypub.ts b/server/tests/utils/requests/activitypub.ts index e3e08ce67..96fee60a8 100644 --- a/server/tests/utils/requests/activitypub.ts +++ b/server/tests/utils/requests/activitypub.ts @@ -3,7 +3,7 @@ import { HTTP_SIGNATURE } from '../../../initializers' import { buildGlobalHeaders } from '../../../lib/job-queue/handlers/utils/activitypub-http-utils' import { activityPubContextify } from '../../../helpers/activitypub' -function makeAPRequest (url: string, body: any, httpSignature: any, headers: any) { +function makePOSTAPRequest (url: string, body: any, httpSignature: any, headers: any) { const options = { method: 'POST', uri: url, @@ -34,10 +34,10 @@ async function makeFollowRequest (to: { url: string }, by: { url: string, privat } const headers = buildGlobalHeaders(body) - return makeAPRequest(to.url, body, httpSignature, headers) + return makePOSTAPRequest(to.url, body, httpSignature, headers) } export { - makeAPRequest, + makePOSTAPRequest, makeFollowRequest } -- cgit v1.2.3 From e5cb43e071924b8cbc77731d3a0511b4f7bcff9d Mon Sep 17 00:00:00 2001 From: Chocobozzz Date: Wed, 14 Nov 2018 15:45:50 +0100 Subject: Clean up peertube auth --- server/tests/cli/peertube.ts | 2 ++ 1 file changed, 2 insertions(+) (limited to 'server/tests') diff --git a/server/tests/cli/peertube.ts b/server/tests/cli/peertube.ts index 65cb05a1a..7a712bc4e 100644 --- a/server/tests/cli/peertube.ts +++ b/server/tests/cli/peertube.ts @@ -44,6 +44,8 @@ describe('Test CLI wrapper', function () { }) after(async function () { + this.timeout(10000) + await execCLI(cmd + ` auth del ${server.url}`) killallServers([ server ]) -- cgit v1.2.3 From a130f33c9c07ffaf2f11a5e629d686a158b9e1c7 Mon Sep 17 00:00:00 2001 From: Chocobozzz Date: Wed, 14 Nov 2018 16:32:12 +0100 Subject: Add AP fetch tests --- server/tests/api/activitypub/fetch.ts | 86 +++++++++++++++++++++++++++++++++++ server/tests/api/activitypub/index.ts | 1 + server/tests/utils/miscs/sql.ts | 9 ++++ 3 files changed, 96 insertions(+) create mode 100644 server/tests/api/activitypub/fetch.ts (limited to 'server/tests') diff --git a/server/tests/api/activitypub/fetch.ts b/server/tests/api/activitypub/fetch.ts new file mode 100644 index 000000000..a42c606c6 --- /dev/null +++ b/server/tests/api/activitypub/fetch.ts @@ -0,0 +1,86 @@ +/* tslint:disable:no-unused-expression */ + +import 'mocha' + +import { + createUser, + doubleFollow, + flushAndRunMultipleServers, + flushTests, + getVideosListSort, + killallServers, + ServerInfo, + setAccessTokensToServers, + uploadVideo, + userLogin +} from '../../utils' +import * as chai from 'chai' +import { setActorField, setVideoField } from '../../utils/miscs/sql' +import { waitJobs } from '../../utils/server/jobs' +import { Video } from '../../../../shared/models/videos' + +const expect = chai.expect + +describe('Test ActivityPub fetcher', function () { + let servers: ServerInfo[] + + // --------------------------------------------------------------- + + before(async function () { + this.timeout(60000) + + servers = await flushAndRunMultipleServers(3) + + // Get the access tokens + await setAccessTokensToServers(servers) + + const user = { username: 'user1', password: 'password' } + for (const server of servers) { + await createUser(server.url, server.accessToken, user.username, user.password) + } + + const userAccessToken = await userLogin(servers[0], user) + + await uploadVideo(servers[0].url, servers[0].accessToken, { name: 'video root' }) + const res = await uploadVideo(servers[0].url, servers[0].accessToken, { name: 'bad video root' }) + const badVideoUUID = res.body.video.uuid + await uploadVideo(servers[0].url, userAccessToken, { name: 'video user' }) + + await setActorField(1, 'http://localhost:9001/accounts/user1', 'url', 'http://localhost:9002/accounts/user1') + await setVideoField(1, badVideoUUID, 'url', 'http://localhost:9003/videos/watch/' + badVideoUUID) + }) + + it('Should add only the video with a valid actor URL', async function () { + this.timeout(60000) + + await doubleFollow(servers[0], servers[1]) + await waitJobs(servers) + + { + const res = await getVideosListSort(servers[0].url, 'createdAt') + expect(res.body.total).to.equal(3) + + const data: Video[] = res.body.data + expect(data[0].name).to.equal('video root') + expect(data[1].name).to.equal('bad video root') + expect(data[2].name).to.equal('video user') + } + + { + const res = await getVideosListSort(servers[1].url, 'createdAt') + expect(res.body.total).to.equal(1) + + const data: Video[] = res.body.data + expect(data[0].name).to.equal('video root') + } + }) + + after(async function () { + killallServers(servers) + + // Keep the logs if the test failed + if (this['ok']) { + await flushTests() + } + }) +}) diff --git a/server/tests/api/activitypub/index.ts b/server/tests/api/activitypub/index.ts index de8a59978..e748f32e9 100644 --- a/server/tests/api/activitypub/index.ts +++ b/server/tests/api/activitypub/index.ts @@ -1,3 +1,4 @@ import './client' +import './fetch' import './helpers' import './security' diff --git a/server/tests/utils/miscs/sql.ts b/server/tests/utils/miscs/sql.ts index 204ff5163..027f78131 100644 --- a/server/tests/utils/miscs/sql.ts +++ b/server/tests/utils/miscs/sql.ts @@ -24,6 +24,15 @@ function setActorField (serverNumber: number, to: string, field: string, value: return seq.query(`UPDATE actor SET "${field}" = '${value}' WHERE url = '${to}'`, options) } +function setVideoField (serverNumber: number, uuid: string, field: string, value: string) { + const seq = getSequelize(serverNumber) + + const options = { type: Sequelize.QueryTypes.UPDATE } + + return seq.query(`UPDATE video SET "${field}" = '${value}' WHERE uuid = '${uuid}'`, options) +} + export { + setVideoField, setActorField } -- cgit v1.2.3 From 742ddee1f131e6a2d701f2eeeb2851e8e1020cb2 Mon Sep 17 00:00:00 2001 From: Chocobozzz Date: Thu, 15 Nov 2018 10:07:44 +0100 Subject: Fix server redundancy tests --- server/tests/api/server/redundancy.ts | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) (limited to 'server/tests') diff --git a/server/tests/api/server/redundancy.ts b/server/tests/api/server/redundancy.ts index f50d6e3cf..77a2d61a4 100644 --- a/server/tests/api/server/redundancy.ts +++ b/server/tests/api/server/redundancy.ts @@ -54,7 +54,7 @@ async function runServers (strategy: VideoRedundancyStrategy, additionalParams: immutableAssign({ min_lifetime: '1 hour', strategy: strategy, - size: '100KB' + size: '200KB' }, additionalParams) ] } @@ -111,8 +111,8 @@ async function checkStatsWith2Webseed (strategy: VideoRedundancyStrategy) { const stat = data.videosRedundancy[0] expect(stat.strategy).to.equal(strategy) - expect(stat.totalSize).to.equal(102400) - expect(stat.totalUsed).to.be.at.least(1).and.below(102401) + expect(stat.totalSize).to.equal(204800) + expect(stat.totalUsed).to.be.at.least(1).and.below(204800) expect(stat.totalVideoFiles).to.equal(4) expect(stat.totalVideos).to.equal(1) } @@ -125,7 +125,7 @@ async function checkStatsWith1Webseed (strategy: VideoRedundancyStrategy) { const stat = data.videosRedundancy[0] expect(stat.strategy).to.equal(strategy) - expect(stat.totalSize).to.equal(102400) + expect(stat.totalSize).to.equal(204800) expect(stat.totalUsed).to.equal(0) expect(stat.totalVideoFiles).to.equal(0) expect(stat.totalVideos).to.equal(0) @@ -223,7 +223,7 @@ describe('Test videos redundancy', function () { return enableRedundancyOnServer1() }) - it('Should have 2 webseed on the first video', async function () { + it('Should have 2 webseeds on the first video', async function () { this.timeout(40000) await waitJobs(servers) @@ -270,7 +270,7 @@ describe('Test videos redundancy', function () { return enableRedundancyOnServer1() }) - it('Should have 2 webseed on the first video', async function () { + it('Should have 2 webseeds on the first video', async function () { this.timeout(40000) await waitJobs(servers) @@ -338,7 +338,7 @@ describe('Test videos redundancy', function () { await waitJobs(servers) }) - it('Should have 2 webseed on the first video', async function () { + it('Should have 2 webseeds on the first video', async function () { this.timeout(40000) await waitJobs(servers) @@ -399,7 +399,7 @@ describe('Test videos redundancy', function () { await enableRedundancyOnServer1() }) - it('Should still have 2 webseeds after 10 seconds', async function () { + it('Should still have 2 webseedss after 10 seconds', async function () { this.timeout(40000) await wait(10000) @@ -451,7 +451,7 @@ describe('Test videos redundancy', function () { video2Server2UUID = res.body.video.uuid }) - it('Should cache video 2 webseed on the first video', async function () { + it('Should cache video 2 webseeds on the first video', async function () { this.timeout(120000) await waitJobs(servers) -- cgit v1.2.3 From 6cb3482ceba2e0564a05b525699f29a1f5ff20a2 Mon Sep 17 00:00:00 2001 From: Chocobozzz Date: Thu, 15 Nov 2018 11:20:23 +0100 Subject: Remove wrong redundancy test --- server/tests/api/redundancy/redundancy.ts | 36 +-- server/tests/api/server/redundancy.ts | 479 ------------------------------ 2 files changed, 16 insertions(+), 499 deletions(-) delete mode 100644 server/tests/api/server/redundancy.ts (limited to 'server/tests') diff --git a/server/tests/api/redundancy/redundancy.ts b/server/tests/api/redundancy/redundancy.ts index 1960854b6..47f4e59fc 100644 --- a/server/tests/api/redundancy/redundancy.ts +++ b/server/tests/api/redundancy/redundancy.ts @@ -54,7 +54,7 @@ async function runServers (strategy: VideoRedundancyStrategy, additionalParams: immutableAssign({ min_lifetime: '1 hour', strategy: strategy, - size: '100KB' + size: '200KB' }, additionalParams) ] } @@ -111,8 +111,8 @@ async function checkStatsWith2Webseed (strategy: VideoRedundancyStrategy) { const stat = data.videosRedundancy[0] expect(stat.strategy).to.equal(strategy) - expect(stat.totalSize).to.equal(102400) - expect(stat.totalUsed).to.be.at.least(1).and.below(102401) + expect(stat.totalSize).to.equal(204800) + expect(stat.totalUsed).to.be.at.least(1).and.below(204801) expect(stat.totalVideoFiles).to.equal(4) expect(stat.totalVideos).to.equal(1) } @@ -125,7 +125,7 @@ async function checkStatsWith1Webseed (strategy: VideoRedundancyStrategy) { const stat = data.videosRedundancy[0] expect(stat.strategy).to.equal(strategy) - expect(stat.totalSize).to.equal(102400) + expect(stat.totalSize).to.equal(204800) expect(stat.totalUsed).to.equal(0) expect(stat.totalVideoFiles).to.equal(0) expect(stat.totalVideos).to.equal(0) @@ -223,7 +223,7 @@ describe('Test videos redundancy', function () { return enableRedundancyOnServer1() }) - it('Should have 2 webseed on the first video', async function () { + it('Should have 2 webseeds on the first video', async function () { this.timeout(40000) await waitJobs(servers) @@ -270,7 +270,7 @@ describe('Test videos redundancy', function () { return enableRedundancyOnServer1() }) - it('Should have 2 webseed on the first video', async function () { + it('Should have 2 webseeds on the first video', async function () { this.timeout(40000) await waitJobs(servers) @@ -338,7 +338,7 @@ describe('Test videos redundancy', function () { await waitJobs(servers) }) - it('Should have 2 webseed on the first video', async function () { + it('Should have 2 webseeds on the first video', async function () { this.timeout(40000) await waitJobs(servers) @@ -419,7 +419,7 @@ describe('Test videos redundancy', function () { killallServers([ servers[0] ]) - await wait(10000) + await wait(15000) await checkNotContains([ servers[1], servers[2] ], 'http%3A%2F%2Flocalhost%3A9001') }) @@ -451,27 +451,23 @@ describe('Test videos redundancy', function () { video2Server2UUID = res.body.video.uuid }) - it('Should cache video 2 webseed on the first video', async function () { - this.timeout(50000) + it('Should cache video 2 webseeds on the first video', async function () { + this.timeout(120000) await waitJobs(servers) - await wait(7000) + let checked = false - try { - await check1WebSeed(strategy, video1Server2UUID) - await check2Webseeds(strategy, video2Server2UUID) - } catch { - await wait(3000) + while (checked === false) { + await wait(1000) try { await check1WebSeed(strategy, video1Server2UUID) await check2Webseeds(strategy, video2Server2UUID) - } catch { - await wait(5000) - await check1WebSeed(strategy, video1Server2UUID) - await check2Webseeds(strategy, video2Server2UUID) + checked = true + } catch { + checked = false } } }) diff --git a/server/tests/api/server/redundancy.ts b/server/tests/api/server/redundancy.ts deleted file mode 100644 index 77a2d61a4..000000000 --- a/server/tests/api/server/redundancy.ts +++ /dev/null @@ -1,479 +0,0 @@ -/* tslint:disable:no-unused-expression */ - -import * as chai from 'chai' -import 'mocha' -import { VideoDetails } from '../../../../shared/models/videos' -import { - doubleFollow, - flushAndRunMultipleServers, - getFollowingListPaginationAndSort, - getVideo, - immutableAssign, - killallServers, makeGetRequest, - root, - ServerInfo, - setAccessTokensToServers, unfollow, - uploadVideo, - viewVideo, - wait, - waitUntilLog, - checkVideoFilesWereRemoved, removeVideo -} from '../../utils' -import { waitJobs } from '../../utils/server/jobs' -import * as magnetUtil from 'magnet-uri' -import { updateRedundancy } from '../../utils/server/redundancy' -import { ActorFollow } from '../../../../shared/models/actors' -import { readdir } from 'fs-extra' -import { join } from 'path' -import { VideoRedundancyStrategy } from '../../../../shared/models/redundancy' -import { getStats } from '../../utils/server/stats' -import { ServerStats } from '../../../../shared/models/server/server-stats.model' - -const expect = chai.expect - -let servers: ServerInfo[] = [] -let video1Server2UUID: string - -function checkMagnetWebseeds (file: { magnetUri: string, resolution: { id: number } }, baseWebseeds: string[], server: ServerInfo) { - const parsed = magnetUtil.decode(file.magnetUri) - - for (const ws of baseWebseeds) { - const found = parsed.urlList.find(url => url === `${ws}-${file.resolution.id}.mp4`) - expect(found, `Webseed ${ws} not found in ${file.magnetUri} on server ${server.url}`).to.not.be.undefined - } - - expect(parsed.urlList).to.have.lengthOf(baseWebseeds.length) -} - -async function runServers (strategy: VideoRedundancyStrategy, additionalParams: any = {}) { - const config = { - redundancy: { - videos: { - check_interval: '5 seconds', - strategies: [ - immutableAssign({ - min_lifetime: '1 hour', - strategy: strategy, - size: '200KB' - }, additionalParams) - ] - } - } - } - servers = await flushAndRunMultipleServers(3, config) - - // Get the access tokens - await setAccessTokensToServers(servers) - - { - const res = await uploadVideo(servers[ 1 ].url, servers[ 1 ].accessToken, { name: 'video 1 server 2' }) - video1Server2UUID = res.body.video.uuid - - await viewVideo(servers[ 1 ].url, video1Server2UUID) - } - - await waitJobs(servers) - - // Server 1 and server 2 follow each other - await doubleFollow(servers[ 0 ], servers[ 1 ]) - // Server 1 and server 3 follow each other - await doubleFollow(servers[ 0 ], servers[ 2 ]) - // Server 2 and server 3 follow each other - await doubleFollow(servers[ 1 ], servers[ 2 ]) - - await waitJobs(servers) -} - -async function check1WebSeed (strategy: VideoRedundancyStrategy, videoUUID?: string) { - if (!videoUUID) videoUUID = video1Server2UUID - - const webseeds = [ - 'http://localhost:9002/static/webseed/' + videoUUID - ] - - for (const server of servers) { - { - const res = await getVideo(server.url, videoUUID) - - const video: VideoDetails = res.body - for (const f of video.files) { - checkMagnetWebseeds(f, webseeds, server) - } - } - } -} - -async function checkStatsWith2Webseed (strategy: VideoRedundancyStrategy) { - const res = await getStats(servers[0].url) - const data: ServerStats = res.body - - expect(data.videosRedundancy).to.have.lengthOf(1) - const stat = data.videosRedundancy[0] - - expect(stat.strategy).to.equal(strategy) - expect(stat.totalSize).to.equal(204800) - expect(stat.totalUsed).to.be.at.least(1).and.below(204800) - expect(stat.totalVideoFiles).to.equal(4) - expect(stat.totalVideos).to.equal(1) -} - -async function checkStatsWith1Webseed (strategy: VideoRedundancyStrategy) { - const res = await getStats(servers[0].url) - const data: ServerStats = res.body - - expect(data.videosRedundancy).to.have.lengthOf(1) - - const stat = data.videosRedundancy[0] - expect(stat.strategy).to.equal(strategy) - expect(stat.totalSize).to.equal(204800) - expect(stat.totalUsed).to.equal(0) - expect(stat.totalVideoFiles).to.equal(0) - expect(stat.totalVideos).to.equal(0) -} - -async function check2Webseeds (strategy: VideoRedundancyStrategy, videoUUID?: string) { - if (!videoUUID) videoUUID = video1Server2UUID - - const webseeds = [ - 'http://localhost:9001/static/webseed/' + videoUUID, - 'http://localhost:9002/static/webseed/' + videoUUID - ] - - for (const server of servers) { - const res = await getVideo(server.url, videoUUID) - - const video: VideoDetails = res.body - - for (const file of video.files) { - checkMagnetWebseeds(file, webseeds, server) - - // Only servers 1 and 2 have the video - if (server.serverNumber !== 3) { - await makeGetRequest({ - url: server.url, - statusCodeExpected: 200, - path: '/static/webseed/' + `${videoUUID}-${file.resolution.id}.mp4`, - contentType: null - }) - } - } - } - - for (const directory of [ 'test1', 'test2' ]) { - const files = await readdir(join(root(), directory, 'videos')) - expect(files).to.have.length.at.least(4) - - for (const resolution of [ 240, 360, 480, 720 ]) { - expect(files.find(f => f === `${videoUUID}-${resolution}.mp4`)).to.not.be.undefined - } - } -} - -async function enableRedundancyOnServer1 () { - await updateRedundancy(servers[ 0 ].url, servers[ 0 ].accessToken, servers[ 1 ].host, true) - - const res = await getFollowingListPaginationAndSort(servers[ 0 ].url, 0, 5, '-createdAt') - const follows: ActorFollow[] = res.body.data - const server2 = follows.find(f => f.following.host === 'localhost:9002') - const server3 = follows.find(f => f.following.host === 'localhost:9003') - - expect(server3).to.not.be.undefined - expect(server3.following.hostRedundancyAllowed).to.be.false - - expect(server2).to.not.be.undefined - expect(server2.following.hostRedundancyAllowed).to.be.true -} - -async function disableRedundancyOnServer1 () { - await updateRedundancy(servers[ 0 ].url, servers[ 0 ].accessToken, servers[ 1 ].host, false) - - const res = await getFollowingListPaginationAndSort(servers[ 0 ].url, 0, 5, '-createdAt') - const follows: ActorFollow[] = res.body.data - const server2 = follows.find(f => f.following.host === 'localhost:9002') - const server3 = follows.find(f => f.following.host === 'localhost:9003') - - expect(server3).to.not.be.undefined - expect(server3.following.hostRedundancyAllowed).to.be.false - - expect(server2).to.not.be.undefined - expect(server2.following.hostRedundancyAllowed).to.be.false -} - -async function cleanServers () { - killallServers(servers) -} - -describe('Test videos redundancy', function () { - - describe('With most-views strategy', function () { - const strategy = 'most-views' - - before(function () { - this.timeout(120000) - - return runServers(strategy) - }) - - it('Should have 1 webseed on the first video', async function () { - await check1WebSeed(strategy) - await checkStatsWith1Webseed(strategy) - }) - - it('Should enable redundancy on server 1', function () { - return enableRedundancyOnServer1() - }) - - it('Should have 2 webseeds on the first video', async function () { - this.timeout(40000) - - await waitJobs(servers) - await waitUntilLog(servers[0], 'Duplicated ', 4) - await waitJobs(servers) - - await check2Webseeds(strategy) - await checkStatsWith2Webseed(strategy) - }) - - it('Should undo redundancy on server 1 and remove duplicated videos', async function () { - this.timeout(40000) - - await disableRedundancyOnServer1() - - await waitJobs(servers) - await wait(5000) - - await check1WebSeed(strategy) - - await checkVideoFilesWereRemoved(video1Server2UUID, servers[0].serverNumber, [ 'videos' ]) - }) - - after(function () { - return cleanServers() - }) - }) - - describe('With trending strategy', function () { - const strategy = 'trending' - - before(function () { - this.timeout(120000) - - return runServers(strategy) - }) - - it('Should have 1 webseed on the first video', async function () { - await check1WebSeed(strategy) - await checkStatsWith1Webseed(strategy) - }) - - it('Should enable redundancy on server 1', function () { - return enableRedundancyOnServer1() - }) - - it('Should have 2 webseeds on the first video', async function () { - this.timeout(40000) - - await waitJobs(servers) - await waitUntilLog(servers[0], 'Duplicated ', 4) - await waitJobs(servers) - - await check2Webseeds(strategy) - await checkStatsWith2Webseed(strategy) - }) - - it('Should unfollow on server 1 and remove duplicated videos', async function () { - this.timeout(40000) - - await unfollow(servers[0].url, servers[0].accessToken, servers[1]) - - await waitJobs(servers) - await wait(5000) - - await check1WebSeed(strategy) - - await checkVideoFilesWereRemoved(video1Server2UUID, servers[0].serverNumber, [ 'videos' ]) - }) - - after(function () { - return cleanServers() - }) - }) - - describe('With recently added strategy', function () { - const strategy = 'recently-added' - - before(function () { - this.timeout(120000) - - return runServers(strategy, { min_views: 3 }) - }) - - it('Should have 1 webseed on the first video', async function () { - await check1WebSeed(strategy) - await checkStatsWith1Webseed(strategy) - }) - - it('Should enable redundancy on server 1', function () { - return enableRedundancyOnServer1() - }) - - it('Should still have 1 webseed on the first video', async function () { - this.timeout(40000) - - await waitJobs(servers) - await wait(15000) - await waitJobs(servers) - - await check1WebSeed(strategy) - await checkStatsWith1Webseed(strategy) - }) - - it('Should view 2 times the first video to have > min_views config', async function () { - this.timeout(40000) - - await viewVideo(servers[ 0 ].url, video1Server2UUID) - await viewVideo(servers[ 2 ].url, video1Server2UUID) - - await wait(10000) - await waitJobs(servers) - }) - - it('Should have 2 webseeds on the first video', async function () { - this.timeout(40000) - - await waitJobs(servers) - await waitUntilLog(servers[0], 'Duplicated ', 4) - await waitJobs(servers) - - await check2Webseeds(strategy) - await checkStatsWith2Webseed(strategy) - }) - - it('Should remove the video and the redundancy files', async function () { - this.timeout(20000) - - await removeVideo(servers[1].url, servers[1].accessToken, video1Server2UUID) - - await waitJobs(servers) - - for (const server of servers) { - await checkVideoFilesWereRemoved(video1Server2UUID, server.serverNumber) - } - }) - - after(function () { - return cleanServers() - }) - }) - - describe('Test expiration', function () { - const strategy = 'recently-added' - - async function checkContains (servers: ServerInfo[], str: string) { - for (const server of servers) { - const res = await getVideo(server.url, video1Server2UUID) - const video: VideoDetails = res.body - - for (const f of video.files) { - expect(f.magnetUri).to.contain(str) - } - } - } - - async function checkNotContains (servers: ServerInfo[], str: string) { - for (const server of servers) { - const res = await getVideo(server.url, video1Server2UUID) - const video: VideoDetails = res.body - - for (const f of video.files) { - expect(f.magnetUri).to.not.contain(str) - } - } - } - - before(async function () { - this.timeout(120000) - - await runServers(strategy, { min_lifetime: '7 seconds', min_views: 0 }) - - await enableRedundancyOnServer1() - }) - - it('Should still have 2 webseedss after 10 seconds', async function () { - this.timeout(40000) - - await wait(10000) - - try { - await checkContains(servers, 'http%3A%2F%2Flocalhost%3A9001') - } catch { - // Maybe a server deleted a redundancy in the scheduler - await wait(2000) - - await checkContains(servers, 'http%3A%2F%2Flocalhost%3A9001') - } - }) - - it('Should stop server 1 and expire video redundancy', async function () { - this.timeout(40000) - - killallServers([ servers[0] ]) - - await wait(15000) - - await checkNotContains([ servers[1], servers[2] ], 'http%3A%2F%2Flocalhost%3A9001') - }) - - after(function () { - return killallServers([ servers[1], servers[2] ]) - }) - }) - - describe('Test file replacement', function () { - let video2Server2UUID: string - const strategy = 'recently-added' - - before(async function () { - this.timeout(120000) - - await runServers(strategy, { min_lifetime: '7 seconds', min_views: 0 }) - - await enableRedundancyOnServer1() - - await waitJobs(servers) - await waitUntilLog(servers[0], 'Duplicated ', 4) - await waitJobs(servers) - - await check2Webseeds(strategy) - await checkStatsWith2Webseed(strategy) - - const res = await uploadVideo(servers[ 1 ].url, servers[ 1 ].accessToken, { name: 'video 2 server 2' }) - video2Server2UUID = res.body.video.uuid - }) - - it('Should cache video 2 webseeds on the first video', async function () { - this.timeout(120000) - - await waitJobs(servers) - - let checked = false - - while (checked === false) { - await wait(1000) - - try { - await check1WebSeed(strategy, video1Server2UUID) - await check2Webseeds(strategy, video2Server2UUID) - - checked = true - } catch { - checked = false - } - } - }) - - after(function () { - return cleanServers() - }) - }) -}) -- cgit v1.2.3 From 8cf998733496d44fa564e2e252356b871756c984 Mon Sep 17 00:00:00 2001 From: Chocobozzz Date: Thu, 15 Nov 2018 17:12:41 +0100 Subject: Fix video channel videos url when scrolling --- server/tests/api/server/handle-down.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'server/tests') diff --git a/server/tests/api/server/handle-down.ts b/server/tests/api/server/handle-down.ts index ed15c8090..0421b2b40 100644 --- a/server/tests/api/server/handle-down.ts +++ b/server/tests/api/server/handle-down.ts @@ -5,7 +5,7 @@ import 'mocha' import { JobState, Video } from '../../../../shared/models' import { VideoPrivacy } from '../../../../shared/models/videos' import { VideoCommentThreadTree } from '../../../../shared/models/videos/video-comment.model' -import { completeVideoCheck, getVideo, immutableAssign, reRunServer, unfollow, viewVideo } from '../../utils' +import { completeVideoCheck, getVideo, immutableAssign, reRunServer, unfollow, updateVideo, viewVideo } from '../../utils' import { flushAndRunMultipleServers, getVideosList, @@ -194,15 +194,15 @@ describe('Test handle downs', function () { expect(res.body.data).to.have.lengthOf(2) }) - it('Should send a view to server 3, and automatically fetch the video', async function () { + it('Should send an update to server 3, and automatically fetch the video', async function () { this.timeout(15000) const res1 = await getVideosList(servers[2].url) expect(res1.body.data).to.be.an('array') expect(res1.body.data).to.have.lengthOf(11) - await viewVideo(servers[0].url, missedVideo1.uuid) - await viewVideo(servers[0].url, unlistedVideo.uuid) + await updateVideo(servers[0].url, servers[0].accessToken, missedVideo1.uuid, { }) + await updateVideo(servers[0].url, servers[0].accessToken, unlistedVideo.uuid, { }) await waitJobs(servers) -- cgit v1.2.3