]>
Commit | Line | Data |
---|---|---|
1 | import * as crypto from 'crypto' | |
2 | import * as bcrypt from 'bcrypt' | |
3 | import * as fs from 'fs' | |
4 | import * as openssl from '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: string, data: string, hexSignature: string) { | |
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: string|Object) { | |
39 | const sign = crypto.createSign(SIGNATURE_ALGORITHM) | |
40 | ||
41 | let dataString: string | |
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: string, hashPassword: string, callback: (err: Error, match?: boolean) => void) { | |
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: (err: Error) => void) { | |
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: string, callback: (err: Error, hash?: string) => void) { | |
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: (err: Error, privateCert: string) => void) { | |
96 | const certPath = join(CONFIG.STORAGE.CERT_DIR, PRIVATE_CERT_NAME) | |
97 | fs.readFile(certPath, 'utf8', callback) | |
98 | } | |
99 | ||
100 | function getMyPublicCert (callback: (err: Error, publicCert: string) => void) { | |
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: (err: Error, certsExist: boolean) => void) { | |
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: (err: Error) => void) { | |
129 | certsExist(function (err, exist) { | |
130 | if (err) return callback(err) | |
131 | ||
132 | if (exist === true) { | |
133 | const errorMessage = 'Certs already exist.' | |
134 | logger.warning(errorMessage) | |
135 | return callback(new Error(errorMessage)) | |
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 | } |