diff options
Diffstat (limited to 'server/helpers/peertube-crypto.ts')
-rw-r--r-- | server/helpers/peertube-crypto.ts | 171 |
1 files changed, 171 insertions, 0 deletions
diff --git a/server/helpers/peertube-crypto.ts b/server/helpers/peertube-crypto.ts new file mode 100644 index 000000000..a4e9672e6 --- /dev/null +++ b/server/helpers/peertube-crypto.ts | |||
@@ -0,0 +1,171 @@ | |||
1 | import crypto = require('crypto') | ||
2 | import bcrypt = require('bcrypt') | ||
3 | import fs = require('fs') | ||
4 | import openssl = require('openssl-wrapper') | ||
5 | import { join } from 'path' | ||
6 | |||
7 | import { | ||
8 | SIGNATURE_ALGORITHM, | ||
9 | SIGNATURE_ENCODING, | ||
10 | PRIVATE_CERT_NAME, | ||
11 | CONFIG, | ||
12 | BCRYPT_SALT_SIZE, | ||
13 | PUBLIC_CERT_NAME | ||
14 | } from '../initializers' | ||
15 | import { logger } from './logger' | ||
16 | |||
17 | function checkSignature (publicKey, data, hexSignature) { | ||
18 | const verify = crypto.createVerify(SIGNATURE_ALGORITHM) | ||
19 | |||
20 | let dataString | ||
21 | if (typeof data === 'string') { | ||
22 | dataString = data | ||
23 | } else { | ||
24 | try { | ||
25 | dataString = JSON.stringify(data) | ||
26 | } catch (err) { | ||
27 | logger.error('Cannot check signature.', { error: err }) | ||
28 | return false | ||
29 | } | ||
30 | } | ||
31 | |||
32 | verify.update(dataString, 'utf8') | ||
33 | |||
34 | const isValid = verify.verify(publicKey, hexSignature, SIGNATURE_ENCODING) | ||
35 | return isValid | ||
36 | } | ||
37 | |||
38 | function sign (data) { | ||
39 | const sign = crypto.createSign(SIGNATURE_ALGORITHM) | ||
40 | |||
41 | let dataString | ||
42 | if (typeof data === 'string') { | ||
43 | dataString = data | ||
44 | } else { | ||
45 | try { | ||
46 | dataString = JSON.stringify(data) | ||
47 | } catch (err) { | ||
48 | logger.error('Cannot sign data.', { error: err }) | ||
49 | return '' | ||
50 | } | ||
51 | } | ||
52 | |||
53 | sign.update(dataString, 'utf8') | ||
54 | |||
55 | // TODO: make async | ||
56 | const certPath = join(CONFIG.STORAGE.CERT_DIR, PRIVATE_CERT_NAME) | ||
57 | const myKey = fs.readFileSync(certPath) | ||
58 | const signature = sign.sign(myKey.toString(), SIGNATURE_ENCODING) | ||
59 | |||
60 | return signature | ||
61 | } | ||
62 | |||
63 | function comparePassword (plainPassword, hashPassword, callback) { | ||
64 | bcrypt.compare(plainPassword, hashPassword, function (err, isPasswordMatch) { | ||
65 | if (err) return callback(err) | ||
66 | |||
67 | return callback(null, isPasswordMatch) | ||
68 | }) | ||
69 | } | ||
70 | |||
71 | function createCertsIfNotExist (callback) { | ||
72 | certsExist(function (err, exist) { | ||
73 | if (err) return callback(err) | ||
74 | |||
75 | if (exist === true) { | ||
76 | return callback(null) | ||
77 | } | ||
78 | |||
79 | createCerts(function (err) { | ||
80 | return callback(err) | ||
81 | }) | ||
82 | }) | ||
83 | } | ||
84 | |||
85 | function cryptPassword (password, callback) { | ||
86 | bcrypt.genSalt(BCRYPT_SALT_SIZE, function (err, salt) { | ||
87 | if (err) return callback(err) | ||
88 | |||
89 | bcrypt.hash(password, salt, function (err, hash) { | ||
90 | return callback(err, hash) | ||
91 | }) | ||
92 | }) | ||
93 | } | ||
94 | |||
95 | function getMyPrivateCert (callback) { | ||
96 | const certPath = join(CONFIG.STORAGE.CERT_DIR, PRIVATE_CERT_NAME) | ||
97 | fs.readFile(certPath, 'utf8', callback) | ||
98 | } | ||
99 | |||
100 | function getMyPublicCert (callback) { | ||
101 | const certPath = join(CONFIG.STORAGE.CERT_DIR, PUBLIC_CERT_NAME) | ||
102 | fs.readFile(certPath, 'utf8', callback) | ||
103 | } | ||
104 | |||
105 | // --------------------------------------------------------------------------- | ||
106 | |||
107 | export { | ||
108 | checkSignature, | ||
109 | comparePassword, | ||
110 | createCertsIfNotExist, | ||
111 | cryptPassword, | ||
112 | getMyPrivateCert, | ||
113 | getMyPublicCert, | ||
114 | sign | ||
115 | } | ||
116 | |||
117 | // --------------------------------------------------------------------------- | ||
118 | |||
119 | function certsExist (callback) { | ||
120 | const certPath = join(CONFIG.STORAGE.CERT_DIR, PRIVATE_CERT_NAME) | ||
121 | fs.access(certPath, function (err) { | ||
122 | // If there is an error the certificates do not exist | ||
123 | const exists = !err | ||
124 | return callback(null, exists) | ||
125 | }) | ||
126 | } | ||
127 | |||
128 | function createCerts (callback) { | ||
129 | certsExist(function (err, exist) { | ||
130 | if (err) return callback(err) | ||
131 | |||
132 | if (exist === true) { | ||
133 | const string = 'Certs already exist.' | ||
134 | logger.warning(string) | ||
135 | return callback(new Error(string)) | ||
136 | } | ||
137 | |||
138 | logger.info('Generating a RSA key...') | ||
139 | |||
140 | const privateCertPath = join(CONFIG.STORAGE.CERT_DIR, PRIVATE_CERT_NAME) | ||
141 | const genRsaOptions = { | ||
142 | 'out': privateCertPath, | ||
143 | '2048': false | ||
144 | } | ||
145 | openssl.exec('genrsa', genRsaOptions, function (err) { | ||
146 | if (err) { | ||
147 | logger.error('Cannot create private key on this pod.') | ||
148 | return callback(err) | ||
149 | } | ||
150 | |||
151 | logger.info('RSA key generated.') | ||
152 | logger.info('Managing public key...') | ||
153 | |||
154 | const publicCertPath = join(CONFIG.STORAGE.CERT_DIR, 'peertube.pub') | ||
155 | const rsaOptions = { | ||
156 | 'in': privateCertPath, | ||
157 | 'pubout': true, | ||
158 | 'out': publicCertPath | ||
159 | } | ||
160 | openssl.exec('rsa', rsaOptions, function (err) { | ||
161 | if (err) { | ||
162 | logger.error('Cannot create public key on this pod.') | ||
163 | return callback(err) | ||
164 | } | ||
165 | |||
166 | logger.info('Public key managed.') | ||
167 | return callback(null) | ||
168 | }) | ||
169 | }) | ||
170 | }) | ||
171 | } | ||