aboutsummaryrefslogtreecommitdiffhomepage
path: root/server/helpers
diff options
context:
space:
mode:
Diffstat (limited to 'server/helpers')
-rw-r--r--server/helpers/activitypub.ts11
-rw-r--r--server/helpers/custom-jsonld-signature.ts4
-rw-r--r--server/helpers/ffmpeg-utils.ts1
-rw-r--r--server/helpers/peertube-crypto.ts71
-rw-r--r--server/helpers/requests.ts4
5 files changed, 79 insertions, 12 deletions
diff --git a/server/helpers/activitypub.ts b/server/helpers/activitypub.ts
index 278010e78..4bf6e387d 100644
--- a/server/helpers/activitypub.ts
+++ b/server/helpers/activitypub.ts
@@ -6,6 +6,7 @@ import { ACTIVITY_PUB } from '../initializers'
6import { ActorModel } from '../models/activitypub/actor' 6import { ActorModel } from '../models/activitypub/actor'
7import { signJsonLDObject } from './peertube-crypto' 7import { signJsonLDObject } from './peertube-crypto'
8import { pageToStartAndCount } from './core-utils' 8import { pageToStartAndCount } from './core-utils'
9import { parse } from 'url'
9 10
10function activityPubContextify <T> (data: T) { 11function activityPubContextify <T> (data: T) {
11 return Object.assign(data, { 12 return Object.assign(data, {
@@ -24,7 +25,7 @@ function activityPubContextify <T> (data: T) {
24 sensitive: 'as:sensitive', 25 sensitive: 'as:sensitive',
25 language: 'sc:inLanguage', 26 language: 'sc:inLanguage',
26 views: 'sc:Number', 27 views: 'sc:Number',
27 stats: 'sc:Number', 28 state: 'sc:Number',
28 size: 'sc:Number', 29 size: 'sc:Number',
29 fps: 'sc:Number', 30 fps: 'sc:Number',
30 commentsEnabled: 'sc:Boolean', 31 commentsEnabled: 'sc:Boolean',
@@ -111,9 +112,17 @@ function getActorUrl (activityActor: string | ActivityPubActor) {
111 return activityActor.id 112 return activityActor.id
112} 113}
113 114
115function checkUrlsSameHost (url1: string, url2: string) {
116 const idHost = parse(url1).host
117 const actorHost = parse(url2).host
118
119 return idHost && actorHost && idHost.toLowerCase() === actorHost.toLowerCase()
120}
121
114// --------------------------------------------------------------------------- 122// ---------------------------------------------------------------------------
115 123
116export { 124export {
125 checkUrlsSameHost,
117 getActorUrl, 126 getActorUrl,
118 activityPubContextify, 127 activityPubContextify,
119 activityPubCollectionPagination, 128 activityPubCollectionPagination,
diff --git a/server/helpers/custom-jsonld-signature.ts b/server/helpers/custom-jsonld-signature.ts
index e4f28018e..27a187db1 100644
--- a/server/helpers/custom-jsonld-signature.ts
+++ b/server/helpers/custom-jsonld-signature.ts
@@ -1,5 +1,5 @@
1import * as AsyncLRU from 'async-lru' 1import * as AsyncLRU from 'async-lru'
2import * as jsonld from 'jsonld/' 2import * as jsonld from 'jsonld'
3import * as jsig from 'jsonld-signatures' 3import * as jsig from 'jsonld-signatures'
4 4
5const nodeDocumentLoader = jsonld.documentLoaders.node() 5const nodeDocumentLoader = jsonld.documentLoaders.node()
@@ -17,4 +17,4 @@ jsonld.documentLoader = (url, cb) => {
17 17
18jsig.use('jsonld', jsonld) 18jsig.use('jsonld', jsonld)
19 19
20export { jsig } 20export { jsig, jsonld }
diff --git a/server/helpers/ffmpeg-utils.ts b/server/helpers/ffmpeg-utils.ts
index a108d46a0..8b9045038 100644
--- a/server/helpers/ffmpeg-utils.ts
+++ b/server/helpers/ffmpeg-utils.ts
@@ -310,6 +310,7 @@ async function presetH264 (command: ffmpeg.FfmpegCommand, resolution: VideoResol
310 .outputOption('-level 3.1') // 3.1 is the minimal ressource allocation for our highest supported resolution 310 .outputOption('-level 3.1') // 3.1 is the minimal ressource allocation for our highest supported resolution
311 .outputOption('-b_strategy 1') // NOTE: b-strategy 1 - heuristic algorythm, 16 is optimal B-frames for it 311 .outputOption('-b_strategy 1') // NOTE: b-strategy 1 - heuristic algorythm, 16 is optimal B-frames for it
312 .outputOption('-bf 16') // NOTE: Why 16: https://github.com/Chocobozzz/PeerTube/pull/774. b-strategy 2 -> B-frames<16 312 .outputOption('-bf 16') // NOTE: Why 16: https://github.com/Chocobozzz/PeerTube/pull/774. b-strategy 2 -> B-frames<16
313 .outputOption('-pix_fmt yuv420p') // allows import of source material with incompatible pixel formats (e.g. MJPEG video)
313 .outputOption('-map_metadata -1') // strip all metadata 314 .outputOption('-map_metadata -1') // strip all metadata
314 .outputOption('-movflags faststart') 315 .outputOption('-movflags faststart')
315 316
diff --git a/server/helpers/peertube-crypto.ts b/server/helpers/peertube-crypto.ts
index 8ef7b1359..ab9ec077e 100644
--- a/server/helpers/peertube-crypto.ts
+++ b/server/helpers/peertube-crypto.ts
@@ -1,9 +1,12 @@
1import { Request } from 'express' 1import { Request } from 'express'
2import { BCRYPT_SALT_SIZE, HTTP_SIGNATURE, PRIVATE_RSA_KEY_SIZE } from '../initializers' 2import { BCRYPT_SALT_SIZE, HTTP_SIGNATURE, PRIVATE_RSA_KEY_SIZE } from '../initializers'
3import { ActorModel } from '../models/activitypub/actor' 3import { ActorModel } from '../models/activitypub/actor'
4import { bcryptComparePromise, bcryptGenSaltPromise, bcryptHashPromise, createPrivateKey, getPublicKey } from './core-utils' 4import { bcryptComparePromise, bcryptGenSaltPromise, bcryptHashPromise, createPrivateKey, getPublicKey, sha256 } from './core-utils'
5import { jsig } from './custom-jsonld-signature' 5import { jsig, jsonld } from './custom-jsonld-signature'
6import { logger } from './logger' 6import { logger } from './logger'
7import { cloneDeep } from 'lodash'
8import { createVerify } from 'crypto'
9import { buildDigest } from '../lib/job-queue/handlers/utils/activitypub-http-utils'
7 10
8const httpSignature = require('http-signature') 11const httpSignature = require('http-signature')
9 12
@@ -30,21 +33,36 @@ async function cryptPassword (password: string) {
30 33
31// HTTP Signature 34// HTTP Signature
32 35
33function isHTTPSignatureVerified (httpSignatureParsed: any, actor: ActorModel) { 36function isHTTPSignatureDigestValid (rawBody: Buffer, req: Request): boolean {
37 if (req.headers[HTTP_SIGNATURE.HEADER_NAME] && req.headers['digest']) {
38 return buildDigest(rawBody.toString()) === req.headers['digest']
39 }
40
41 return true
42}
43
44function isHTTPSignatureVerified (httpSignatureParsed: any, actor: ActorModel): boolean {
34 return httpSignature.verifySignature(httpSignatureParsed, actor.publicKey) === true 45 return httpSignature.verifySignature(httpSignatureParsed, actor.publicKey) === true
35} 46}
36 47
37function parseHTTPSignature (req: Request) { 48function parseHTTPSignature (req: Request, clockSkew?: number) {
38 return httpSignature.parse(req, { authorizationHeaderName: HTTP_SIGNATURE.HEADER_NAME }) 49 return httpSignature.parse(req, { authorizationHeaderName: HTTP_SIGNATURE.HEADER_NAME, clockSkew })
39} 50}
40 51
41// JSONLD 52// JSONLD
42 53
43function isJsonLDSignatureVerified (fromActor: ActorModel, signedDocument: any) { 54async function isJsonLDSignatureVerified (fromActor: ActorModel, signedDocument: any): Promise<boolean> {
55 if (signedDocument.signature.type === 'RsaSignature2017') {
56 // Mastodon algorithm
57 const res = await isJsonLDRSA2017Verified(fromActor, signedDocument)
58 // Success? If no, try with our library
59 if (res === true) return true
60 }
61
44 const publicKeyObject = { 62 const publicKeyObject = {
45 '@context': jsig.SECURITY_CONTEXT_URL, 63 '@context': jsig.SECURITY_CONTEXT_URL,
46 id: fromActor.url, 64 id: fromActor.url,
47 type: 'CryptographicKey', 65 type: 'CryptographicKey',
48 owner: fromActor.url, 66 owner: fromActor.url,
49 publicKeyPem: fromActor.publicKey 67 publicKeyPem: fromActor.publicKey
50 } 68 }
@@ -69,6 +87,44 @@ function isJsonLDSignatureVerified (fromActor: ActorModel, signedDocument: any)
69 }) 87 })
70} 88}
71 89
90// Backward compatibility with "other" implementations
91async function isJsonLDRSA2017Verified (fromActor: ActorModel, signedDocument: any) {
92 function hash (obj: any): Promise<any> {
93 return jsonld.promises
94 .normalize(obj, {
95 algorithm: 'URDNA2015',
96 format: 'application/n-quads'
97 })
98 .then(res => sha256(res))
99 }
100
101 const signatureCopy = cloneDeep(signedDocument.signature)
102 Object.assign(signatureCopy, {
103 '@context': [
104 'https://w3id.org/security/v1',
105 { RsaSignature2017: 'https://w3id.org/security#RsaSignature2017' }
106 ]
107 })
108 delete signatureCopy.type
109 delete signatureCopy.id
110 delete signatureCopy.signatureValue
111
112 const docWithoutSignature = cloneDeep(signedDocument)
113 delete docWithoutSignature.signature
114
115 const [ documentHash, optionsHash ] = await Promise.all([
116 hash(docWithoutSignature),
117 hash(signatureCopy)
118 ])
119
120 const toVerify = optionsHash + documentHash
121
122 const verify = createVerify('RSA-SHA256')
123 verify.update(toVerify, 'utf8')
124
125 return verify.verify(fromActor.publicKey, signedDocument.signature.signatureValue, 'base64')
126}
127
72function signJsonLDObject (byActor: ActorModel, data: any) { 128function signJsonLDObject (byActor: ActorModel, data: any) {
73 const options = { 129 const options = {
74 privateKeyPem: byActor.privateKey, 130 privateKeyPem: byActor.privateKey,
@@ -82,6 +138,7 @@ function signJsonLDObject (byActor: ActorModel, data: any) {
82// --------------------------------------------------------------------------- 138// ---------------------------------------------------------------------------
83 139
84export { 140export {
141 isHTTPSignatureDigestValid,
85 parseHTTPSignature, 142 parseHTTPSignature,
86 isHTTPSignatureVerified, 143 isHTTPSignatureVerified,
87 isJsonLDSignatureVerified, 144 isJsonLDSignatureVerified,
diff --git a/server/helpers/requests.ts b/server/helpers/requests.ts
index ee9e80404..51facc9e0 100644
--- a/server/helpers/requests.ts
+++ b/server/helpers/requests.ts
@@ -3,7 +3,7 @@ import { createWriteStream } from 'fs-extra'
3import * as request from 'request' 3import * as request from 'request'
4import { ACTIVITY_PUB } from '../initializers' 4import { ACTIVITY_PUB } from '../initializers'
5 5
6function doRequest ( 6function doRequest <T> (
7 requestOptions: request.CoreOptions & request.UriOptions & { activityPub?: boolean } 7 requestOptions: request.CoreOptions & request.UriOptions & { activityPub?: boolean }
8): Bluebird<{ response: request.RequestResponse, body: any }> { 8): Bluebird<{ response: request.RequestResponse, body: any }> {
9 if (requestOptions.activityPub === true) { 9 if (requestOptions.activityPub === true) {
@@ -11,7 +11,7 @@ function doRequest (
11 requestOptions.headers['accept'] = ACTIVITY_PUB.ACCEPT_HEADER 11 requestOptions.headers['accept'] = ACTIVITY_PUB.ACCEPT_HEADER
12 } 12 }
13 13
14 return new Bluebird<{ response: request.RequestResponse, body: any }>((res, rej) => { 14 return new Bluebird<{ response: request.RequestResponse, body: T }>((res, rej) => {
15 request(requestOptions, (err, response, body) => err ? rej(err) : res({ response, body })) 15 request(requestOptions, (err, response, body) => err ? rej(err) : res({ response, body }))
16 }) 16 })
17} 17}