@@ -13,6 +13,7 @@ import crypto from 'crypto';
1313import fs from 'fs' ;
1414import * as readlineSync from 'readline-sync' ;
1515import path from 'path' ;
16+ import * as chokidar from 'chokidar' ;
1617import { findSmythPath } from '../../../../helpers/Sysconfig.helper' ;
1718
1819const console = Logger ( 'JSONFileVault' ) ;
@@ -28,55 +29,18 @@ export class JSONFileVault extends VaultConnector {
2829 private vaultData : any ;
2930 private index : any ;
3031 private shared : string ;
32+ private vaultFile : string ;
33+ private watcher : chokidar . FSWatcher | null = null ;
3134
3235 constructor ( protected _settings : JSONFileVaultConfig ) {
3336 super ( _settings ) ;
3437 //if (!SmythRuntime.Instance) throw new Error('SRE not initialized');
3538
3639 this . shared = _settings . shared || '' ; //if config.shared, all keys are accessible to all teams, and they are set under the 'shared' teamId
3740
38- let vaultFile = this . findVaultFile ( _settings . file ) ;
39- this . vaultData = { } ;
40- if ( fs . existsSync ( vaultFile ) ) {
41- try {
42- if ( _settings . fileKey && fs . existsSync ( _settings . fileKey ) ) {
43- try {
44- const privateKey = fs . readFileSync ( _settings . fileKey , 'utf8' ) ;
45- const encryptedVault = fs . readFileSync ( vaultFile , 'utf8' ) . toString ( ) ;
46- const decryptedBuffer = crypto . privateDecrypt (
47- {
48- key : privateKey ,
49- padding : crypto . constants . RSA_PKCS1_OAEP_PADDING ,
50- } ,
51- Buffer . from ( encryptedVault , 'base64' )
52- ) ;
53- this . vaultData = JSON . parse ( decryptedBuffer . toString ( 'utf8' ) ) ;
54- } catch ( error ) {
55- throw new Error ( 'Failed to decrypt vault' ) ;
56- }
57- } else {
58- this . vaultData = JSON . parse ( fs . readFileSync ( vaultFile ) . toString ( ) ) ;
59- }
60- } catch ( e ) {
61- console . error ( 'Error parsing vault file:' , e ) ;
62- console . error ( '!!! Vault features might not work properly !!!' ) ;
63- this . vaultData = { } ;
64- }
65-
66- if ( this . vaultData ?. encrypted && this . vaultData ?. algorithm && this . vaultData ?. data ) {
67- //this is an encrypted vault we need to request the master key
68- this . setInteraction ( this . getMasterKeyInteractive . bind ( this ) ) ;
69- }
70-
71- for ( let teamId in this . vaultData ) {
72- for ( let resourceId in this . vaultData [ teamId ] ) {
73- if ( ! this . index ) this . index = { } ;
74- if ( ! this . index [ resourceId ] ) this . index [ resourceId ] = { } ;
75- const value = this . vaultData [ teamId ] [ resourceId ] ;
76- this . index [ resourceId ] [ teamId ] = value ;
77- }
78- }
79- }
41+ this . vaultFile = this . findVaultFile ( _settings . file ) ;
42+ this . fetchVaultData ( this . vaultFile , _settings ) ;
43+ this . initFileWatcher ( ) ;
8044 }
8145
8246 private findVaultFile ( vaultFile ) {
@@ -192,4 +156,66 @@ export class JSONFileVault extends VaultConnector {
192156
193157 return acl ;
194158 }
159+
160+ private fetchVaultData ( vaultFile : string , _settings : JSONFileVaultConfig ) {
161+ if ( fs . existsSync ( vaultFile ) ) {
162+ try {
163+ if ( _settings . fileKey && fs . existsSync ( _settings . fileKey ) ) {
164+ try {
165+ const privateKey = fs . readFileSync ( _settings . fileKey , 'utf8' ) ;
166+ const encryptedVault = fs . readFileSync ( vaultFile , 'utf8' ) . toString ( ) ;
167+ const decryptedBuffer = crypto . privateDecrypt (
168+ {
169+ key : privateKey ,
170+ padding : crypto . constants . RSA_PKCS1_OAEP_PADDING ,
171+ } ,
172+ Buffer . from ( encryptedVault , 'base64' )
173+ ) ;
174+ this . vaultData = JSON . parse ( decryptedBuffer . toString ( 'utf8' ) ) ;
175+ } catch ( error ) {
176+ throw new Error ( 'Failed to decrypt vault' ) ;
177+ }
178+ } else {
179+ this . vaultData = JSON . parse ( fs . readFileSync ( vaultFile ) . toString ( ) ) ;
180+ }
181+ } catch ( e ) {
182+ console . error ( 'Error parsing vault file:' , e ) ;
183+ console . error ( '!!! Vault features might not work properly !!!' ) ;
184+ this . vaultData = { } ;
185+ }
186+
187+ if ( this . vaultData ?. encrypted && this . vaultData ?. algorithm && this . vaultData ?. data ) {
188+ //this is an encrypted vault we need to request the master key
189+ this . setInteraction ( this . getMasterKeyInteractive . bind ( this ) ) ;
190+ }
191+
192+ for ( let teamId in this . vaultData ) {
193+ for ( let resourceId in this . vaultData [ teamId ] ) {
194+ if ( ! this . index ) this . index = { } ;
195+ if ( ! this . index [ resourceId ] ) this . index [ resourceId ] = { } ;
196+ const value = this . vaultData [ teamId ] [ resourceId ] ;
197+ this . index [ resourceId ] [ teamId ] = value ;
198+ }
199+ }
200+ }
201+ }
202+
203+ private initFileWatcher ( ) {
204+ this . watcher = chokidar . watch ( this . vaultFile , {
205+ persistent : false , // Don't keep the process running
206+ ignoreInitial : true ,
207+ } ) ;
208+
209+ this . watcher . on ( 'change' , ( ) => {
210+ this . fetchVaultData ( this . vaultFile , this . _settings ) ;
211+ } ) ;
212+ }
213+
214+ public async stop ( ) {
215+ super . stop ( ) ;
216+ if ( this . watcher ) {
217+ this . watcher . close ( ) ;
218+ this . watcher = null ;
219+ }
220+ }
195221}
0 commit comments