diff options
Diffstat (limited to 'server/helpers/peertube-crypto.ts')
-rw-r--r-- | server/helpers/peertube-crypto.ts | 158 |
1 files changed, 46 insertions, 112 deletions
diff --git a/server/helpers/peertube-crypto.ts b/server/helpers/peertube-crypto.ts index 10a226af4..6d50e446f 100644 --- a/server/helpers/peertube-crypto.ts +++ b/server/helpers/peertube-crypto.ts | |||
@@ -1,77 +1,68 @@ | |||
1 | import * as crypto from 'crypto' | 1 | import * as jsig from 'jsonld-signatures' |
2 | import { join } from 'path' | ||
3 | 2 | ||
4 | import { | 3 | import { |
5 | SIGNATURE_ALGORITHM, | 4 | PRIVATE_RSA_KEY_SIZE, |
6 | SIGNATURE_ENCODING, | 5 | BCRYPT_SALT_SIZE |
7 | PRIVATE_CERT_NAME, | ||
8 | CONFIG, | ||
9 | BCRYPT_SALT_SIZE, | ||
10 | PUBLIC_CERT_NAME | ||
11 | } from '../initializers' | 6 | } from '../initializers' |
12 | import { | 7 | import { |
13 | readFilePromise, | ||
14 | bcryptComparePromise, | 8 | bcryptComparePromise, |
15 | bcryptGenSaltPromise, | 9 | bcryptGenSaltPromise, |
16 | bcryptHashPromise, | 10 | bcryptHashPromise, |
17 | accessPromise, | 11 | createPrivateKey, |
18 | opensslExecPromise | 12 | getPublicKey, |
13 | jsonldSignPromise, | ||
14 | jsonldVerifyPromise | ||
19 | } from './core-utils' | 15 | } from './core-utils' |
20 | import { logger } from './logger' | 16 | import { logger } from './logger' |
17 | import { AccountInstance } from '../models/account/account-interface' | ||
21 | 18 | ||
22 | function checkSignature (publicKey: string, data: string, hexSignature: string) { | 19 | async function createPrivateAndPublicKeys () { |
23 | const verify = crypto.createVerify(SIGNATURE_ALGORITHM) | 20 | logger.info('Generating a RSA key...') |
24 | |||
25 | let dataString | ||
26 | if (typeof data === 'string') { | ||
27 | dataString = data | ||
28 | } else { | ||
29 | try { | ||
30 | dataString = JSON.stringify(data) | ||
31 | } catch (err) { | ||
32 | logger.error('Cannot check signature.', err) | ||
33 | return false | ||
34 | } | ||
35 | } | ||
36 | 21 | ||
37 | verify.update(dataString, 'utf8') | 22 | const { key } = await createPrivateKey(PRIVATE_RSA_KEY_SIZE) |
23 | const { publicKey } = await getPublicKey(key) | ||
38 | 24 | ||
39 | const isValid = verify.verify(publicKey, hexSignature, SIGNATURE_ENCODING) | 25 | return { privateKey: key, publicKey } |
40 | return isValid | ||
41 | } | 26 | } |
42 | 27 | ||
43 | async function sign (data: string | Object) { | 28 | function isSignatureVerified (fromAccount: AccountInstance, signedDocument: object) { |
44 | const sign = crypto.createSign(SIGNATURE_ALGORITHM) | 29 | const publicKeyObject = { |
45 | 30 | '@context': jsig.SECURITY_CONTEXT_URL, | |
46 | let dataString: string | 31 | '@id': fromAccount.url, |
47 | if (typeof data === 'string') { | 32 | '@type': 'CryptographicKey', |
48 | dataString = data | 33 | owner: fromAccount.url, |
49 | } else { | 34 | publicKeyPem: fromAccount.publicKey |
50 | try { | ||
51 | dataString = JSON.stringify(data) | ||
52 | } catch (err) { | ||
53 | logger.error('Cannot sign data.', err) | ||
54 | return '' | ||
55 | } | ||
56 | } | 35 | } |
57 | 36 | ||
58 | sign.update(dataString, 'utf8') | 37 | const publicKeyOwnerObject = { |
38 | '@context': jsig.SECURITY_CONTEXT_URL, | ||
39 | '@id': fromAccount.url, | ||
40 | publicKey: [ publicKeyObject ] | ||
41 | } | ||
59 | 42 | ||
60 | const myKey = await getMyPrivateCert() | 43 | const options = { |
61 | return sign.sign(myKey, SIGNATURE_ENCODING) | 44 | publicKey: publicKeyObject, |
62 | } | 45 | publicKeyOwner: publicKeyOwnerObject |
46 | } | ||
63 | 47 | ||
64 | function comparePassword (plainPassword: string, hashPassword: string) { | 48 | return jsonldVerifyPromise(signedDocument, options) |
65 | return bcryptComparePromise(plainPassword, hashPassword) | 49 | .catch(err => { |
50 | logger.error('Cannot check signature.', err) | ||
51 | return false | ||
52 | }) | ||
66 | } | 53 | } |
67 | 54 | ||
68 | async function createCertsIfNotExist () { | 55 | function signObject (byAccount: AccountInstance, data: any) { |
69 | const exist = await certsExist() | 56 | const options = { |
70 | if (exist === true) { | 57 | privateKeyPem: byAccount.privateKey, |
71 | return | 58 | creator: byAccount.url |
72 | } | 59 | } |
73 | 60 | ||
74 | return createCerts() | 61 | return jsonldSignPromise(data, options) |
62 | } | ||
63 | |||
64 | function comparePassword (plainPassword: string, hashPassword: string) { | ||
65 | return bcryptComparePromise(plainPassword, hashPassword) | ||
75 | } | 66 | } |
76 | 67 | ||
77 | async function cryptPassword (password: string) { | 68 | async function cryptPassword (password: string) { |
@@ -80,69 +71,12 @@ async function cryptPassword (password: string) { | |||
80 | return bcryptHashPromise(password, salt) | 71 | return bcryptHashPromise(password, salt) |
81 | } | 72 | } |
82 | 73 | ||
83 | function getMyPrivateCert () { | ||
84 | const certPath = join(CONFIG.STORAGE.CERT_DIR, PRIVATE_CERT_NAME) | ||
85 | return readFilePromise(certPath, 'utf8') | ||
86 | } | ||
87 | |||
88 | function getMyPublicCert () { | ||
89 | const certPath = join(CONFIG.STORAGE.CERT_DIR, PUBLIC_CERT_NAME) | ||
90 | return readFilePromise(certPath, 'utf8') | ||
91 | } | ||
92 | |||
93 | // --------------------------------------------------------------------------- | 74 | // --------------------------------------------------------------------------- |
94 | 75 | ||
95 | export { | 76 | export { |
96 | checkSignature, | 77 | isSignatureVerified, |
97 | comparePassword, | 78 | comparePassword, |
98 | createCertsIfNotExist, | 79 | createPrivateAndPublicKeys, |
99 | cryptPassword, | 80 | cryptPassword, |
100 | getMyPrivateCert, | 81 | signObject |
101 | getMyPublicCert, | ||
102 | sign | ||
103 | } | ||
104 | |||
105 | // --------------------------------------------------------------------------- | ||
106 | |||
107 | async function certsExist () { | ||
108 | const certPath = join(CONFIG.STORAGE.CERT_DIR, PRIVATE_CERT_NAME) | ||
109 | |||
110 | // If there is an error the certificates do not exist | ||
111 | try { | ||
112 | await accessPromise(certPath) | ||
113 | |||
114 | return true | ||
115 | } catch { | ||
116 | return false | ||
117 | } | ||
118 | } | ||
119 | |||
120 | async function createCerts () { | ||
121 | const exist = await certsExist() | ||
122 | if (exist === true) { | ||
123 | const errorMessage = 'Certs already exist.' | ||
124 | logger.warning(errorMessage) | ||
125 | throw new Error(errorMessage) | ||
126 | } | ||
127 | |||
128 | logger.info('Generating a RSA key...') | ||
129 | |||
130 | const privateCertPath = join(CONFIG.STORAGE.CERT_DIR, PRIVATE_CERT_NAME) | ||
131 | const genRsaOptions = { | ||
132 | 'out': privateCertPath, | ||
133 | '2048': false | ||
134 | } | ||
135 | |||
136 | await opensslExecPromise('genrsa', genRsaOptions) | ||
137 | logger.info('RSA key generated.') | ||
138 | logger.info('Managing public key...') | ||
139 | |||
140 | const publicCertPath = join(CONFIG.STORAGE.CERT_DIR, 'peertube.pub') | ||
141 | const rsaOptions = { | ||
142 | 'in': privateCertPath, | ||
143 | 'pubout': true, | ||
144 | 'out': publicCertPath | ||
145 | } | ||
146 | |||
147 | await opensslExecPromise('rsa', rsaOptions) | ||
148 | } | 82 | } |