@@ -17,7 +17,9 @@ import { PuppetHTTP } from "./http"
1717import { isArray } from "util" ;
1818import { WorkspaceSettings } from "./workspace_settings" ;
1919import { EnvironmentTreeDump , NodeDump } from "../ipc/objects"
20+ import { HIERA_EDITOR_FIELD , HIERA_EDITOR_VALUE } from "./cert"
2021
22+ const forge = require ( "node-forge" ) ;
2123const PromisePool = require ( 'es6-promise-pool' ) ;
2224
2325export class Environment
@@ -33,6 +35,7 @@ export class Environment
3335 private readonly _warnings : WorkspaceError [ ] ;
3436 private readonly _offline : boolean ;
3537 private readonly _nodeFacts : Dictionary < string , any > ;
38+ private readonly _certificates : Dictionary < string , any > ;
3639 private _modulesInfo : PuppetModulesInfo ;
3740
3841 constructor ( workspace : Workspace , name : string , _path : string , cachePath : string , offline : boolean = false )
@@ -48,6 +51,7 @@ export class Environment
4851 this . _global . put ( "environment" , name ) ;
4952 this . _nodes = new Dictionary ( ) ;
5053 this . _nodeFacts = new Dictionary ( ) ;
54+ this . _certificates = new Dictionary ( ) ;
5155 this . _offline = offline ;
5256 }
5357
@@ -96,6 +100,11 @@ export class Environment
96100 return path . join ( this . _cachePath , "facts" , certName + ".json" )
97101 }
98102
103+ public get certificateCachePath ( ) : string
104+ {
105+ return path . join ( this . _cachePath , "certs" )
106+ }
107+
99108 public get certListCachePath ( ) : string
100109 {
101110 return path . join ( this . _cachePath , "certnames.json" )
@@ -436,6 +445,69 @@ export class Environment
436445
437446 }
438447
448+ public getCertificate ( certname : string ) : any
449+ {
450+ return this . _certificates . get ( certname ) ;
451+ }
452+
453+ private async loadCertificates ( updateProgressCategory : any , certList : string [ ] , settings : WorkspaceSettings )
454+ {
455+
456+ if ( ! await async . isDirectory ( this . certificateCachePath ) )
457+ {
458+ await async . makeDirectory ( this . certificateCachePath ) ;
459+ }
460+
461+ const certsExist = [ ] ;
462+
463+ for ( const certname of certList )
464+ {
465+ certsExist . push ( async . isFile ( path . join ( this . certificateCachePath , certname + ".txt" ) ) ) ;
466+ }
467+
468+ const ex = await Promise . all ( certsExist . map ( p => p . catch ( ( ) => undefined ) ) ) ;
469+ const loadCerts = [ ] ;
470+
471+ for ( let i = 0 , t = certList . length ; i < t ; i ++ )
472+ {
473+ const certname = certList [ i ] ;
474+ const exists = ex [ i ] ;
475+
476+ if ( exists )
477+ {
478+ loadCerts . push ( async . readFile ( path . join ( this . certificateCachePath , certname + ".txt" ) ) ) ;
479+ }
480+ else
481+ {
482+ loadCerts . push ( Promise . resolve ( null ) ) ;
483+ }
484+ }
485+
486+ const certs = await Promise . all ( loadCerts . map ( p => p . catch ( ( e : any ) : any => undefined ) ) ) ;
487+
488+ for ( let i = 0 , t = certList . length ; i < t ; i ++ )
489+ {
490+ const certname = certList [ i ] ;
491+ let certificate = certs [ i ] ;
492+
493+ if ( certificate == null )
494+ {
495+ if ( updateProgressCategory ) updateProgressCategory (
496+ "[" + this . name + "] Downloading certificate for node " + certname + "..." , false ) ;
497+
498+ certificate = await PuppetHTTP . GetCertificate ( certname , this . name , settings ) ;
499+ await async . writeFile ( path . join ( this . certificateCachePath , certname + ".txt" ) , certificate ) ;
500+ }
501+
502+ const cert = forge . pki . certificateFromPem ( certificate ) ;
503+
504+ if ( cert == null )
505+ continue ;
506+
507+ this . _certificates . put ( certname , cert ) ;
508+ }
509+ }
510+
439511 private async updateCertList ( updateProgressCategory : any , settings : WorkspaceSettings ) : Promise < string [ ] >
440512 {
441513 if ( updateProgressCategory ) updateProgressCategory ( "[" + this . name + "] Updating certificate list..." , false ) ;
@@ -451,12 +523,16 @@ export class Environment
451523 throw new WorkspaceError ( "Failed to obtain certificate list" , e . toString ( ) ) ;
452524 }
453525
526+ await this . loadCertificates ( updateProgressCategory , certList , settings ) ;
527+
454528 await async . writeJSON ( this . certListCachePath , certList ) ;
455529 return certList ;
456530 }
457531
458532 public async init ( progressCallback : any = null , updateProgressCategory : any = null ) : Promise < any >
459533 {
534+ const zis = this ;
535+
460536 this . _warnings . length = 0 ;
461537
462538 if ( ! await async . isDirectory ( this . cachePath ) )
@@ -519,7 +595,26 @@ export class Environment
519595 }
520596
521597 const nodeIgnoreList = this . workspace . getNodeIgnoreList ( ) ;
522- nodeList = nodeList . filter ( ( value : string ) => nodeIgnoreList . indexOf ( value ) < 0 ) ;
598+ nodeList = nodeList . filter ( ( certname : string ) =>
599+ {
600+ if ( nodeIgnoreList . indexOf ( certname ) >= 0 )
601+ return false ;
602+
603+ const cert = zis . _certificates . get ( certname ) ;
604+ if ( cert != null )
605+ {
606+ const ext = cert . getExtension ( { id : HIERA_EDITOR_FIELD } ) ;
607+ if ( ext != null )
608+ {
609+ // cut the fist two characters
610+ // https://puppet.com/docs/puppet/6.0/ssl_attributes_extensions.html#manually-checking-for-extensions-in-csrs-and-certificates
611+ if ( ext . value . substr ( 2 ) == HIERA_EDITOR_VALUE )
612+ return false ;
613+ }
614+ }
615+
616+ return true ;
617+ } ) ;
523618 this . _nodeFacts . clear ( ) ;
524619
525620 if ( ! this . _offline )
0 commit comments