@@ -8,18 +8,41 @@ const https = require('https');
88const Semaphore = require ( '../util/semaphore' ) ;
99const dbg = require ( './debug_module' ) ( __filename ) ;
1010const nb_native = require ( './nb_native' ) ;
11+ const { EventEmitter } = require ( 'events' ) ;
1112
12- const init_cert_info = dir => ( {
13- dir,
14- cert : null ,
15- is_loaded : false ,
16- is_generated : false ,
17- sem : new Semaphore ( 1 )
18- } ) ;
13+ class CertInfo extends EventEmitter {
14+
15+ constructor ( dir ) {
16+ super ( ) ;
17+ this . dir = dir ;
18+ this . cert = null ;
19+ this . is_loaded = false ;
20+ this . is_generated = false ;
21+ this . sem = new Semaphore ( 1 ) ;
22+ }
23+
24+ async file_notification ( event , filename ) {
25+ try {
26+ const cert_on_disk = await _read_ssl_certificate ( this . dir ) ;
27+ if ( this . cert . key === cert_on_disk . key ) {
28+ return ;
29+ }
30+
31+ this . cert = cert_on_disk ;
32+ this . is_generated = false ;
33+
34+ this . emit ( 'update' , this ) ;
35+ } catch ( err ) {
36+ if ( err . code !== 'ENOENT' ) {
37+ dbg . warn ( `SSL certificate failed to update from dir ${ this . dir } :` , err . message ) ;
38+ }
39+ }
40+ }
41+ }
1942
2043const certs = {
21- MGMT : init_cert_info ( '/etc/mgmt-secret' ) ,
22- S3 : init_cert_info ( '/etc/s3-secret' ) ,
44+ MGMT : new CertInfo ( '/etc/mgmt-secret' ) ,
45+ S3 : new CertInfo ( '/etc/s3-secret' ) ,
2346} ;
2447
2548function generate_ssl_certificate ( ) {
@@ -36,19 +59,19 @@ function verify_ssl_certificate(certificate) {
3659}
3760
3861// Get SSL certificate (load once then serve from cache)
39- function get_ssl_certificate ( service ) {
62+ function get_ssl_cert_info ( service ) {
4063 const cert_info = certs [ service ] ;
4164 if ( ! cert_info ) {
4265 throw new Error ( `Invalid service name, got: ${ service } ` ) ;
4366 }
4467
4568 if ( cert_info . is_loaded ) {
46- return cert_info . cert ;
69+ return cert_info ;
4770 }
4871
4972 return cert_info . sem . surround ( async ( ) => {
5073 if ( cert_info . is_loaded ) {
51- return cert_info . cert ;
74+ return cert_info ;
5275 }
5376
5477 try {
@@ -68,40 +91,19 @@ function get_ssl_certificate(service) {
6891 }
6992
7093 cert_info . is_loaded = true ;
71- return cert_info . cert ;
72- } ) ;
73- }
74-
75- // For each cert that was loaded into memory we check if the cert was changed on disk.
76- // If so we update it. If any of the certs was updated we return true else we return false.
77- async function update_certs_from_disk ( ) {
78- const promiseList = Object . values ( certs ) . map ( cert_info =>
79- cert_info . sem . surround ( async ( ) => {
80- if ( ! cert_info . is_loaded ) {
81- return false ;
82- }
8394
84- try {
85- const cert_on_disk = await _read_ssl_certificate ( cert_info . dir ) ;
86- if ( cert_info . cert . key === cert_on_disk . key ) {
87- return false ;
88- }
89-
90- cert_info . cert = cert_on_disk ;
91- cert_info . is_generated = false ;
92- return true ;
93-
94- } catch ( err ) {
95- if ( err . code !== 'ENOENT' ) {
96- dbg . warn ( `SSL certificate failed to update from dir ${ cert_info . dir } :` , err . message ) ;
97- }
98- return false ;
95+ try {
96+ fs . watch ( cert_info . dir , { } , cert_info . file_notification . bind ( cert_info ) ) ;
97+ } catch ( err ) {
98+ if ( err . code === 'ENOENT' ) {
99+ dbg . warn ( "Certificate folder " , cert_info . dir , " does not exist. New certificate won't be loaded." ) ;
100+ } else {
101+ dbg . error ( "Failed to watch certificate dir " , cert_info . dir , ". err = " , err ) ;
99102 }
100- } )
101- ) ;
103+ }
102104
103- const updatedList = await Promise . all ( promiseList ) ;
104- return updatedList . some ( Boolean ) ;
105+ return cert_info ;
106+ } ) ;
105107}
106108
107109// Read SSL certificate form disk
@@ -125,6 +127,15 @@ function is_using_generated_certs() {
125127 ) ;
126128}
127129
130+ function get_cert_dir ( service ) {
131+ const cert_info = certs [ service ] ;
132+ if ( ! cert_info ) {
133+ throw new Error ( `Invalid service name, got: ${ service } ` ) ;
134+ }
135+
136+ return cert_info . dir ;
137+ }
138+
128139// create a default certificate and start an https server to test it in the browser
129140function run_https_test_server ( ) {
130141 const server = https . createServer ( generate_ssl_certificate ( ) ) ;
@@ -144,8 +155,8 @@ function run_https_test_server() {
144155
145156exports . generate_ssl_certificate = generate_ssl_certificate ;
146157exports . verify_ssl_certificate = verify_ssl_certificate ;
147- exports . get_ssl_certificate = get_ssl_certificate ;
158+ exports . get_ssl_cert_info = get_ssl_cert_info ;
148159exports . is_using_generated_certs = is_using_generated_certs ;
149- exports . update_certs_from_disk = update_certs_from_disk ;
160+ exports . get_cert_dir = get_cert_dir ;
150161
151162if ( require . main === module ) run_https_test_server ( ) ;
0 commit comments