fix(core): update
This commit is contained in:
		
							
								
								
									
										13
									
								
								test/test.ts
									
									
									
									
									
								
							
							
						
						
									
										13
									
								
								test/test.ts
									
									
									
									
									
								
							| @@ -11,20 +11,23 @@ tap.test('should create a valid instance of SmartAcme', async () => { | ||||
|   smartAcmeInstance = new smartacme.SmartAcme({ | ||||
|     accountEmail: 'domains@lossless.org', | ||||
|     accountPrivateKey: null, | ||||
|     mongoDescriptor: { | ||||
|       mongoDbName: testQenv.getEnvVarOnDemand('MONGODB_DATABASE'), | ||||
|       mongoDbPass: testQenv.getEnvVarOnDemand('MONGODB_PASSWORD'), | ||||
|       mongoDbUrl: testQenv.getEnvVarOnDemand('MONGODB_URL') | ||||
|     }, | ||||
|     removeChallenge: async (...args) => { | ||||
|       console.log(args); | ||||
|     }, | ||||
|     setChallenge: async (...args) => { | ||||
|       console.log(args); | ||||
|     }, | ||||
|     mongoDescriptor: { | ||||
|       mongoDbName: testQenv.getEnvVarOnDemand('MONGODB_DATABASE'), | ||||
|       mongoDbPass: testQenv.getEnvVarOnDemand('MONGODB_PASSWORD'), | ||||
|       mongoDbUrl: testQenv.getEnvVarOnDemand('MONGODB_URL') | ||||
|     validateRemoteRequest: async () => { | ||||
|       return true; | ||||
|     } | ||||
|   }); | ||||
|   await smartAcmeInstance.init(); | ||||
|   await smartAcmeInstance.getCertificateForDomain('bleu.de'); | ||||
|   // await smartAcmeInstance.getCertificateForDomain('bleu.de'); | ||||
| }); | ||||
|  | ||||
| tap.start(); | ||||
|   | ||||
							
								
								
									
										9
									
								
								ts/interfaces/cert.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										9
									
								
								ts/interfaces/cert.ts
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,9 @@ | ||||
| export type TCertStatus = 'existing' | 'nonexisting' | 'pending' | 'failed'; | ||||
|  | ||||
| export interface ICert { | ||||
|   domainName: string; | ||||
|   created: number; | ||||
|   privateKey: string; | ||||
|   publicKey: string; | ||||
|   csr: string; | ||||
| } | ||||
							
								
								
									
										11
									
								
								ts/interfaces/certremote.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										11
									
								
								ts/interfaces/certremote.ts
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,11 @@ | ||||
| import { ICert, TCertStatus } from './cert'; | ||||
|  | ||||
| export interface ICertRemoteRequest { | ||||
|   secret: string; | ||||
|   domainName: string; | ||||
| } | ||||
|  | ||||
| export interface ICertRemoteResponse { | ||||
|   status: TCertStatus; | ||||
|   certificate?: ICert; | ||||
| } | ||||
| @@ -1 +1,3 @@ | ||||
| export * from './accountdata'; | ||||
| export * from './cert'; | ||||
| export * from './certremote'; | ||||
|   | ||||
| @@ -1,4 +1,7 @@ | ||||
| import * as plugins from './smartacme.plugins'; | ||||
|  | ||||
| import * as interfaces from './interfaces'; | ||||
|  | ||||
| import { CertManager } from './smartacme.classes.certmanager'; | ||||
|  | ||||
| import { Collection, svDb, unI } from '@pushrocks/smartdata'; | ||||
| @@ -6,24 +9,24 @@ import { Collection, svDb, unI } from '@pushrocks/smartdata'; | ||||
| @plugins.smartdata.Collection(() => { | ||||
|   return CertManager.activeDB; | ||||
| }) | ||||
| export class Cert extends plugins.smartdata.SmartDataDbDoc<Cert> { | ||||
| export class Cert extends plugins.smartdata.SmartDataDbDoc<Cert> implements interfaces.ICert { | ||||
|   @unI() | ||||
|   public index: string; | ||||
|  | ||||
|   @svDb() | ||||
|   domainName: string; | ||||
|   public domainName: string; | ||||
|  | ||||
|   @svDb() | ||||
|   created: number; | ||||
|   public created: number; | ||||
|  | ||||
|   @svDb() | ||||
|   privateKey: string; | ||||
|   public privateKey: string; | ||||
|    | ||||
|   @svDb() | ||||
|   publicKey: string; | ||||
|   public publicKey: string; | ||||
|    | ||||
|   @svDb() | ||||
|   csr: string; | ||||
|   public csr: string; | ||||
|  | ||||
|   constructor(privateKeyArg: string, publicKeyArg: string, csrArg: string) { | ||||
|     super(); | ||||
|   | ||||
| @@ -1,5 +1,8 @@ | ||||
| import * as plugins from './smartacme.plugins'; | ||||
| import { Cert } from './smartacme.classes.cert'; | ||||
| import { SmartAcme } from './smartacme.classes.smartacme'; | ||||
|  | ||||
| import * as interfaces from './interfaces'; | ||||
|  | ||||
|  | ||||
| export class CertManager { | ||||
| @@ -15,16 +18,22 @@ export class CertManager { | ||||
|   private mongoDescriptor: plugins.smartdata.IMongoDescriptor; | ||||
|   public smartdataDb: plugins.smartdata.SmartdataDb; | ||||
|  | ||||
|   constructor(optionsArg: { | ||||
|   public pendingMap: plugins.lik.Stringmap; | ||||
|  | ||||
|   constructor(smartAcmeArg: SmartAcme,optionsArg: { | ||||
|     mongoDescriptor: plugins.smartdata.IMongoDescriptor; | ||||
|   }) { | ||||
|     this.mongoDescriptor = optionsArg.mongoDescriptor; | ||||
|   } | ||||
|  | ||||
|   public async init () { | ||||
|     // Smartdata DB | ||||
|     this.smartdataDb = new plugins.smartdata.SmartdataDb(this.mongoDescriptor); | ||||
|     await this.smartdataDb.init(); | ||||
|     CertManager.activeDB = this.smartdataDb; | ||||
|  | ||||
|     // Pending Map | ||||
|     this.pendingMap = new plugins.lik.Stringmap(); | ||||
|   }; | ||||
|  | ||||
|   /** | ||||
| @@ -33,6 +42,7 @@ export class CertManager { | ||||
|    * @param domainName the domain Name to retrieve the vcertificate for | ||||
|    */ | ||||
|   public async retrieveCertificate(domainName: string): Promise<Cert> { | ||||
|     await this.checkCerts(); | ||||
|     const existingCertificate: Cert = await Cert.getInstance({ | ||||
|       name: domainName | ||||
|     }); | ||||
| @@ -56,12 +66,27 @@ export class CertManager { | ||||
|     cert.save(); | ||||
|   }; | ||||
|  | ||||
|   public async deleteCertificate(domainName: string) { | ||||
|   public async deleteCertificate(domainNameArg: string) { | ||||
|  | ||||
|   }; | ||||
|   } | ||||
|  | ||||
|   public async getCertificateStatus(domainNameArg: string): Promise<interfaces.TCertStatus> { | ||||
|     const isPending = this.pendingMap.checkString('domainNameArg'); | ||||
|     if (isPending) { | ||||
|       return 'pending'; | ||||
|     } | ||||
|  | ||||
|     // otherwise lets continue | ||||
|     const existingCertificate = this.retrieveCertificate(domainNameArg); | ||||
|     if (existingCertificate) { | ||||
|       return 'existing'; | ||||
|     } | ||||
|  | ||||
|     return 'nonexisting'; | ||||
|   } | ||||
|  | ||||
|   /** | ||||
|    * checks all certs for expiration | ||||
|    */ | ||||
|   checkCerts() {} | ||||
|   private async checkCerts() {}; | ||||
| } | ||||
|   | ||||
| @@ -1,10 +1,47 @@ | ||||
| import * as plugins from './smartacme.plugins'; | ||||
| import * as interfaces from './interfaces'; | ||||
| import { ICertRemoteResponse } from './interfaces'; | ||||
|  | ||||
| // tslint:disable-next-line: max-classes-per-file | ||||
| export class CertRemoteClient { | ||||
|   private remoteUrl: string; | ||||
|   private secret: string; | ||||
|  | ||||
|   constructor(optionsArg: { | ||||
|     remoteUrl: string; | ||||
|     secret: string; | ||||
|   }) { | ||||
|     this.remoteUrl = optionsArg.remoteUrl; | ||||
|     this.secret = optionsArg.secret; | ||||
|   } | ||||
|  | ||||
|   /** | ||||
|    *  | ||||
|    * @param domainNameArg  | ||||
|    */ | ||||
|   async getCertificateForDomain(domainNameArg: string): Promise<interfaces.ICert> { | ||||
|     let certificate: interfaces.ICert; | ||||
|     const doRequestCycle = async (): Promise<interfaces.ICert> => { | ||||
|       const response: ICertRemoteResponse = (await plugins.smartrequest.postJson(this.remoteUrl, { | ||||
|         requestBody: <interfaces.ICertRemoteRequest>{ | ||||
|           domainName: domainNameArg, | ||||
|           secret: this.secret | ||||
|         } | ||||
|       })).body; | ||||
|       switch(response.status) { | ||||
|         case 'pending': | ||||
|           await plugins.smartdelay.delayFor(5000); | ||||
|           const finalResponse = await doRequestCycle(); | ||||
|           return finalResponse; | ||||
|         case 'existing': | ||||
|           return response.certificate; | ||||
|         case 'failed': | ||||
|         default: | ||||
|           console.log(`could not retrieve certificate for ${domainNameArg}`); | ||||
|           return null; | ||||
|       } | ||||
|     }; | ||||
|     certificate = await doRequestCycle(); | ||||
|     return certificate; | ||||
|   } | ||||
| } | ||||
|   | ||||
| @@ -1,3 +0,0 @@ | ||||
| import * as plugins from './smartacme.plugins'; | ||||
|  | ||||
| export class CertRemoteHandler {} | ||||
| @@ -1,6 +1,8 @@ | ||||
| import * as plugins from './smartacme.plugins'; | ||||
| import { CertManager } from './smartacme.classes.certmanager'; | ||||
| import { CertRemoteHandler } from './smartacme.classes.certremotehandler'; | ||||
|  | ||||
| import * as interfaces from './interfaces'; | ||||
| import { request } from 'http'; | ||||
|  | ||||
| /** | ||||
|  * | ||||
| @@ -8,9 +10,10 @@ import { CertRemoteHandler } from './smartacme.classes.certremotehandler'; | ||||
| export interface ISmartAcmeOptions { | ||||
|   accountPrivateKey?: string; | ||||
|   accountEmail: string; | ||||
|   mongoDescriptor: plugins.smartdata.IMongoDescriptor; | ||||
|   setChallenge: (domainName: string, keyAuthorization: string) => Promise<any>; | ||||
|   removeChallenge: (domainName: string) => Promise<any>; | ||||
|   mongoDescriptor: plugins.smartdata.IMongoDescriptor; | ||||
|   validateRemoteRequest: () => Promise<boolean>; | ||||
| } | ||||
|  | ||||
| export class SmartAcme { | ||||
| @@ -26,26 +29,64 @@ export class SmartAcme { | ||||
|   // challenge fullfillment | ||||
|   private setChallenge: (domainName: string, keyAuthorization: string) => Promise<any>; | ||||
|   private removeChallenge: (domainName: string) => Promise<any>; | ||||
|   private validateRemoteRequest: () => Promise<boolean>; | ||||
|  | ||||
|   // certmanager | ||||
|   private certmanager: CertManager; | ||||
|   private certremoteHandler: CertRemoteHandler; | ||||
|   private certremoteHandler: plugins.smartexpress.Handler; | ||||
|  | ||||
|   constructor(optionsArg: ISmartAcmeOptions) { | ||||
|     this.options = optionsArg; | ||||
|   } | ||||
|  | ||||
|   /** | ||||
|    * inits the instance | ||||
|    */ | ||||
|   public async init() { | ||||
|     this.privateKey = this.options.accountPrivateKey || (await plugins.acme.forge.createPrivateKey()); | ||||
|     this.privateKey = | ||||
|       this.options.accountPrivateKey || (await plugins.acme.forge.createPrivateKey()); | ||||
|     this.setChallenge = this.options.setChallenge; | ||||
|     this.removeChallenge = this.options.removeChallenge; | ||||
|  | ||||
|     this.certmanager = new CertManager({ | ||||
|     // CertMangaer | ||||
|     this.certmanager = new CertManager(this, { | ||||
|       mongoDescriptor: this.options.mongoDescriptor | ||||
|     }); | ||||
|     await this.certmanager.init(); | ||||
|     this.certremoteHandler = new CertRemoteHandler(); | ||||
|  | ||||
|     // CertRemoteHandler | ||||
|     this.certremoteHandler = new plugins.smartexpress.Handler('POST', async (req, res) => { | ||||
|       const requestBody: interfaces.ICertRemoteRequest = req.body; | ||||
|       const status: interfaces.TCertStatus = await this.certmanager.getCertificateStatus(requestBody.domainName); | ||||
|       const existingCertificate = await this.certmanager.retrieveCertificate( | ||||
|         requestBody.domainName | ||||
|       ); | ||||
|       let response: interfaces.ICertRemoteResponse; | ||||
|       switch (status) { | ||||
|          case 'existing': | ||||
|           response = { | ||||
|             status, | ||||
|             certificate: { | ||||
|               created: existingCertificate.created, | ||||
|               csr: existingCertificate.csr, | ||||
|               domainName: existingCertificate.domainName, | ||||
|               privateKey: existingCertificate.privateKey, | ||||
|               publicKey: existingCertificate.publicKey | ||||
|             } | ||||
|           }; | ||||
|           break; | ||||
|         default: | ||||
|           response = { | ||||
|             status | ||||
|           }; | ||||
|           break; | ||||
|       } | ||||
|       res.status(200); | ||||
|       res.send(response); | ||||
|       res.end(); | ||||
|     }); | ||||
|  | ||||
|     // ACME Client | ||||
|     this.client = new plugins.acme.Client({ | ||||
|       directoryUrl: plugins.acme.directory.letsencrypt.staging, | ||||
|       accountKey: this.privateKey | ||||
| @@ -63,7 +104,7 @@ export class SmartAcme { | ||||
|  | ||||
|     const retrievedCertificate = await this.certmanager.retrieveCertificate(domain); | ||||
|  | ||||
|     if(retrievedCertificate) { | ||||
|     if (retrievedCertificate) { | ||||
|       return retrievedCertificate; | ||||
|     } | ||||
|  | ||||
| @@ -123,6 +164,4 @@ export class SmartAcme { | ||||
|  | ||||
|     this.certmanager.storeCertificate(key.toString(), cert.toString(), csr.toString()); | ||||
|   } | ||||
|  | ||||
|   toStorageObject() {} | ||||
| } | ||||
|   | ||||
		Reference in New Issue
	
	Block a user