UNPKG

@cto.af/ca

Version:

Testing-only Certificate Authority (CA) for your local development environment ONLY. This is in no way suitable for production of any kind.

5 lines (4 loc) 4.03 kB
import{createLog as R}from"@cto.af/log";import w from"fs/promises";function S(i,e,t){return i.log?.warn('Reading key from untrusted store: "%s"',t),w.readFile(t,"utf8")}async function A(i,e,t,r){i.log?.warn('Writing key to untrusted store: "%s"',t),await w.writeFile(t,r,"utf8")}async function O(i,e,t){i.log?.warn('Deleting key in untrusted store: "%s"',t),await w.rm(t)}function m(i,e=new Date){return new Date(e.getTime()+i*864e5)}import k from"filenamify";import p from"fs/promises";import b from"path";import y from"jsrsasign";var h="com.github.cto-af.ca",f=class i{name;key=void 0;cert;notAfter;notBefore;subject;issuer;serial;ca;constructor(e,t,r,o){this.name=e,t&&(this.key=typeof t=="string"?t:y.KEYUTIL.getPEM(t,"PKCS8PRV")),this.cert=typeof r=="string"?r:r.getPEM();let n=new y.X509;n.readCertPEM(this.cert),this.notAfter=y.zulutodate(n.getNotAfter()),this.notBefore=y.zulutodate(n.getNotBefore()),this.subject=n.getSubjectString(),this.issuer=n.getIssuerString(),this.ca=o,this.serial=n.getSerialNumberHex()}static async read(e,t,r){try{let o=this.#e(e,t),n=e.noKey?void 0:await S(e,h,o.keyName),u=await p.readFile(o.certName,"utf8"),s=new i(t,n,u,r);return s.notAfter<m(e.minRunDays)?null:s}catch(o){if(o.code==="ENOENT")return null;throw o}}static#e(e,t){let r=k(t),o=b.resolve(process.cwd(),e.certDir),n=b.join(o,`${r}.key.pem`),u=b.join(o,`${r}.cert.pem`);return{certDir:o,keyName:n,certName:u}}async delete(e){let t=i.#e(e,this.name);await O(e,h,t.keyName),await p.rm(t.certName)}async write(e){let t=i.#e(e,this.name);await p.mkdir(t.certDir,{recursive:!0}),this.key&&await A(e,h,t.keyName,this.key),await p.writeFile(t.certName,this.cert,"utf8")}};import N from"env-paths";import j from"filenamify";import x from"path";import c from"jsrsasign";var v="/C=US/ST=Colorado/L=Denver/O=@cto.af/CN=cto-af-Root-CA",E="@cto.af/ca",{config:P}=N(E);var K={caSubject:v,minRunDays:1,notAfterDays:7,caDir:P,certDir:".cert",forceCA:!1,forceCert:!1,host:"localhost",logLevel:0,logFile:null,log:null,noKey:!1};function D(i){return i.log??=R({logLevel:i.logLevel,logFile:i.logFile}),i.log}async function T(i){let e={...K,...i},t=D(e);e.certDir=e.caDir;let r=j(e.caSubject);if(!e.forceCA){let a=await f.read(e,r);if(a)return a}t.info("Creating new CA certificate");let o=c.KEYUTIL.generateKeypair("EC","secp256r1"),n=o.prvKeyObj,u=o.pubKeyObj,s=new Date,g=new Date(s.getTime()-1e4),d=m(365,s),C=new c.KJUR.asn1.x509.Certificate({version:3,serial:{int:s.getTime()},issuer:{str:e.caSubject},notbefore:c.datetozulu(g,!1,!1),notafter:c.datetozulu(d,!1,!1),subject:{str:e.caSubject},sbjpubkey:u,ext:[{extname:"basicConstraints",cA:!0}],sigalg:"SHA256withECDSA",cakey:n}),l=new f(e.caSubject,n,C);return await l.write(e),process.platform==="darwin"&&t.info(` To trust the new CA for OSX apps like Safari, try: sudo security add-trusted-cert -d -r trustRoot -k /Library/Keychains/System.keychain %s.cert.pem `,x.resolve(e.caDir,r)),l}async function Q(i){let e={...K,...i},t=D(e),r=await T(e);if(!e.forceCert){let a=await f.read(e,e.host,r);if(a){if(a.issuer!==r.subject)t.warn('Invalid CA subject "%s" != "%s".',a.issuer,r.subject);else if(a.notBefore.getTime()>=r.notBefore.getTime())return a;t.warn("CA no longer valid: %s < %s",a.notBefore.toISOString(),r.notBefore.toISOString())}}t.info('Creating cert for "%s".',e.host);let o=new Date,n=new Date(o.getTime()-1e4),u=m(e.notAfterDays,o),s=c.KEYUTIL.generateKeypair("EC","secp256r1"),g=s.prvKeyObj,d=s.pubKeyObj;if(!r.key)throw new Error("Key required");let C=new c.KJUR.asn1.x509.Certificate({version:3,serial:{int:o.getTime()},issuer:{str:r.subject},notbefore:c.datetozulu(n,!0,!1),notafter:c.datetozulu(u,!0,!1),subject:{str:`/CN=${e.host}`},sbjpubkey:d,ext:[{extname:"basicConstraints",cA:!1},{extname:"keyUsage",critical:!0,names:["digitalSignature"]},{extname:"subjectAltName",array:[{dns:e.host}]}],sigalg:"SHA256withECDSA",cakey:r.key}),l=new f(e.host,g,C.getPEM(),r);return await l.write(e),l}export{K as DEFAULT_CERT_OPTIONS,f as KeyCert,T as createCA,Q as createCert};