diff options
author | Chocobozzz <me@florianbigard.com> | 2018-10-19 11:41:19 +0200 |
---|---|---|
committer | Chocobozzz <me@florianbigard.com> | 2018-10-19 12:59:52 +0200 |
commit | f7509cbec875ec4ee3201cce08839f2a02676c1c (patch) | |
tree | 5dbfcff41a175aa7d4b7d396ca90fe26049d0164 /server/helpers | |
parent | 333210d862fdba4bb114b756d4f964789f480196 (diff) | |
download | PeerTube-f7509cbec875ec4ee3201cce08839f2a02676c1c.tar.gz PeerTube-f7509cbec875ec4ee3201cce08839f2a02676c1c.tar.zst PeerTube-f7509cbec875ec4ee3201cce08839f2a02676c1c.zip |
Add HTTP signature check before linked signature
It's faster, and will allow us to use RSA signature 2018 (with upstream
jsonld-signature module) without too much incompatibilities in the
peertube federation
Diffstat (limited to 'server/helpers')
-rw-r--r-- | server/helpers/activitypub.ts | 32 | ||||
-rw-r--r-- | server/helpers/peertube-crypto.ts | 70 |
2 files changed, 63 insertions, 39 deletions
diff --git a/server/helpers/activitypub.ts b/server/helpers/activitypub.ts index 1304c7559..278010e78 100644 --- a/server/helpers/activitypub.ts +++ b/server/helpers/activitypub.ts | |||
@@ -4,7 +4,7 @@ import { ResultList } from '../../shared/models' | |||
4 | import { Activity, ActivityPubActor } from '../../shared/models/activitypub' | 4 | import { Activity, ActivityPubActor } from '../../shared/models/activitypub' |
5 | import { ACTIVITY_PUB } from '../initializers' | 5 | import { ACTIVITY_PUB } from '../initializers' |
6 | import { ActorModel } from '../models/activitypub/actor' | 6 | import { ActorModel } from '../models/activitypub/actor' |
7 | import { signObject } from './peertube-crypto' | 7 | import { signJsonLDObject } from './peertube-crypto' |
8 | import { pageToStartAndCount } from './core-utils' | 8 | import { pageToStartAndCount } from './core-utils' |
9 | 9 | ||
10 | function activityPubContextify <T> (data: T) { | 10 | function activityPubContextify <T> (data: T) { |
@@ -15,22 +15,22 @@ function activityPubContextify <T> (data: T) { | |||
15 | { | 15 | { |
16 | RsaSignature2017: 'https://w3id.org/security#RsaSignature2017', | 16 | RsaSignature2017: 'https://w3id.org/security#RsaSignature2017', |
17 | pt: 'https://joinpeertube.org/ns', | 17 | pt: 'https://joinpeertube.org/ns', |
18 | schema: 'http://schema.org#', | 18 | sc: 'http://schema.org#', |
19 | Hashtag: 'as:Hashtag', | 19 | Hashtag: 'as:Hashtag', |
20 | uuid: 'schema:identifier', | 20 | uuid: 'sc:identifier', |
21 | category: 'schema:category', | 21 | category: 'sc:category', |
22 | licence: 'schema:license', | 22 | licence: 'sc:license', |
23 | subtitleLanguage: 'schema:subtitleLanguage', | 23 | subtitleLanguage: 'sc:subtitleLanguage', |
24 | sensitive: 'as:sensitive', | 24 | sensitive: 'as:sensitive', |
25 | language: 'schema:inLanguage', | 25 | language: 'sc:inLanguage', |
26 | views: 'schema:Number', | 26 | views: 'sc:Number', |
27 | stats: 'schema:Number', | 27 | stats: 'sc:Number', |
28 | size: 'schema:Number', | 28 | size: 'sc:Number', |
29 | fps: 'schema:Number', | 29 | fps: 'sc:Number', |
30 | commentsEnabled: 'schema:Boolean', | 30 | commentsEnabled: 'sc:Boolean', |
31 | waitTranscoding: 'schema:Boolean', | 31 | waitTranscoding: 'sc:Boolean', |
32 | expires: 'schema:expires', | 32 | expires: 'sc:expires', |
33 | support: 'schema:Text', | 33 | support: 'sc:Text', |
34 | CacheFile: 'pt:CacheFile' | 34 | CacheFile: 'pt:CacheFile' |
35 | }, | 35 | }, |
36 | { | 36 | { |
@@ -102,7 +102,7 @@ async function activityPubCollectionPagination (url: string, handler: ActivityPu | |||
102 | function buildSignedActivity (byActor: ActorModel, data: Object) { | 102 | function buildSignedActivity (byActor: ActorModel, data: Object) { |
103 | const activity = activityPubContextify(data) | 103 | const activity = activityPubContextify(data) |
104 | 104 | ||
105 | return signObject(byActor, activity) as Promise<Activity> | 105 | return signJsonLDObject(byActor, activity) as Promise<Activity> |
106 | } | 106 | } |
107 | 107 | ||
108 | function getActorUrl (activityActor: string | ActivityPubActor) { | 108 | function getActorUrl (activityActor: string | ActivityPubActor) { |
diff --git a/server/helpers/peertube-crypto.ts b/server/helpers/peertube-crypto.ts index 5c182961d..cb5f27240 100644 --- a/server/helpers/peertube-crypto.ts +++ b/server/helpers/peertube-crypto.ts | |||
@@ -1,9 +1,12 @@ | |||
1 | import { BCRYPT_SALT_SIZE, PRIVATE_RSA_KEY_SIZE } from '../initializers' | 1 | import { Request } from 'express' |
2 | import { BCRYPT_SALT_SIZE, HTTP_SIGNATURE, PRIVATE_RSA_KEY_SIZE } from '../initializers' | ||
2 | import { ActorModel } from '../models/activitypub/actor' | 3 | import { ActorModel } from '../models/activitypub/actor' |
3 | import { bcryptComparePromise, bcryptGenSaltPromise, bcryptHashPromise, createPrivateKey, getPublicKey } from './core-utils' | 4 | import { bcryptComparePromise, bcryptGenSaltPromise, bcryptHashPromise, createPrivateKey, getPublicKey } from './core-utils' |
4 | import { jsig } from './custom-jsonld-signature' | 5 | import { jsig } from './custom-jsonld-signature' |
5 | import { logger } from './logger' | 6 | import { logger } from './logger' |
6 | 7 | ||
8 | const httpSignature = require('http-signature') | ||
9 | |||
7 | async function createPrivateAndPublicKeys () { | 10 | async function createPrivateAndPublicKeys () { |
8 | logger.info('Generating a RSA key...') | 11 | logger.info('Generating a RSA key...') |
9 | 12 | ||
@@ -13,18 +16,42 @@ async function createPrivateAndPublicKeys () { | |||
13 | return { privateKey: key, publicKey } | 16 | return { privateKey: key, publicKey } |
14 | } | 17 | } |
15 | 18 | ||
16 | function isSignatureVerified (fromActor: ActorModel, signedDocument: object) { | 19 | // User password checks |
20 | |||
21 | function comparePassword (plainPassword: string, hashPassword: string) { | ||
22 | return bcryptComparePromise(plainPassword, hashPassword) | ||
23 | } | ||
24 | |||
25 | async function cryptPassword (password: string) { | ||
26 | const salt = await bcryptGenSaltPromise(BCRYPT_SALT_SIZE) | ||
27 | |||
28 | return bcryptHashPromise(password, salt) | ||
29 | } | ||
30 | |||
31 | // HTTP Signature | ||
32 | |||
33 | function isHTTPSignatureVerified (httpSignatureParsed: any, actor: ActorModel) { | ||
34 | return httpSignature.verifySignature(httpSignatureParsed, actor.publicKey) === true | ||
35 | } | ||
36 | |||
37 | function parseHTTPSignature (req: Request) { | ||
38 | return httpSignature.parse(req, { authorizationHeaderName: HTTP_SIGNATURE.HEADER_NAME }) | ||
39 | } | ||
40 | |||
41 | // JSONLD | ||
42 | |||
43 | function isJsonLDSignatureVerified (fromActor: ActorModel, signedDocument: any) { | ||
17 | const publicKeyObject = { | 44 | const publicKeyObject = { |
18 | '@context': jsig.SECURITY_CONTEXT_URL, | 45 | '@context': jsig.SECURITY_CONTEXT_URL, |
19 | '@id': fromActor.url, | 46 | id: fromActor.url, |
20 | '@type': 'CryptographicKey', | 47 | type: 'CryptographicKey', |
21 | owner: fromActor.url, | 48 | owner: fromActor.url, |
22 | publicKeyPem: fromActor.publicKey | 49 | publicKeyPem: fromActor.publicKey |
23 | } | 50 | } |
24 | 51 | ||
25 | const publicKeyOwnerObject = { | 52 | const publicKeyOwnerObject = { |
26 | '@context': jsig.SECURITY_CONTEXT_URL, | 53 | '@context': jsig.SECURITY_CONTEXT_URL, |
27 | '@id': fromActor.url, | 54 | id: fromActor.url, |
28 | publicKey: [ publicKeyObject ] | 55 | publicKey: [ publicKeyObject ] |
29 | } | 56 | } |
30 | 57 | ||
@@ -33,14 +60,19 @@ function isSignatureVerified (fromActor: ActorModel, signedDocument: object) { | |||
33 | publicKeyOwner: publicKeyOwnerObject | 60 | publicKeyOwner: publicKeyOwnerObject |
34 | } | 61 | } |
35 | 62 | ||
36 | return jsig.promises.verify(signedDocument, options) | 63 | return jsig.promises |
37 | .catch(err => { | 64 | .verify(signedDocument, options) |
38 | logger.error('Cannot check signature.', { err }) | 65 | .then((result: { verified: boolean }) => { |
39 | return false | 66 | logger.info('coucou', result) |
40 | }) | 67 | return result.verified |
68 | }) | ||
69 | .catch(err => { | ||
70 | logger.error('Cannot check signature.', { err }) | ||
71 | return false | ||
72 | }) | ||
41 | } | 73 | } |
42 | 74 | ||
43 | function signObject (byActor: ActorModel, data: any) { | 75 | function signJsonLDObject (byActor: ActorModel, data: any) { |
44 | const options = { | 76 | const options = { |
45 | privateKeyPem: byActor.privateKey, | 77 | privateKeyPem: byActor.privateKey, |
46 | creator: byActor.url, | 78 | creator: byActor.url, |
@@ -50,22 +82,14 @@ function signObject (byActor: ActorModel, data: any) { | |||
50 | return jsig.promises.sign(data, options) | 82 | return jsig.promises.sign(data, options) |
51 | } | 83 | } |
52 | 84 | ||
53 | function comparePassword (plainPassword: string, hashPassword: string) { | ||
54 | return bcryptComparePromise(plainPassword, hashPassword) | ||
55 | } | ||
56 | |||
57 | async function cryptPassword (password: string) { | ||
58 | const salt = await bcryptGenSaltPromise(BCRYPT_SALT_SIZE) | ||
59 | |||
60 | return bcryptHashPromise(password, salt) | ||
61 | } | ||
62 | |||
63 | // --------------------------------------------------------------------------- | 85 | // --------------------------------------------------------------------------- |
64 | 86 | ||
65 | export { | 87 | export { |
66 | isSignatureVerified, | 88 | parseHTTPSignature, |
89 | isHTTPSignatureVerified, | ||
90 | isJsonLDSignatureVerified, | ||
67 | comparePassword, | 91 | comparePassword, |
68 | createPrivateAndPublicKeys, | 92 | createPrivateAndPublicKeys, |
69 | cryptPassword, | 93 | cryptPassword, |
70 | signObject | 94 | signJsonLDObject |
71 | } | 95 | } |