Skip to content

Commit

Permalink
(feature) Return CA Certificate path/data (#41)
Browse files Browse the repository at this point in the history
* Fixes typescript runtime errors

* Encryption/chmod not required for certificate, only key

* Add run options & branch that returns caPath/caCert Buffer

* Reverse formatting changes

* separate API concerns

Separates `returnCa` into `getCaPath` and `getCaBuffer`

Co-Authored-By: James Zetlen <[email protected]>

* Add support for both `getCaPath` and `getCaBuffer` API interfaces

Co-Authored-By: James Zetlen <[email protected]>

* TSDoc update

* Update conditions / return type

* Add additional flags to main function TSDoc
  • Loading branch information
Js-Brecht authored and zetlen committed Nov 21, 2019
1 parent 014ca91 commit 0d3ce16
Show file tree
Hide file tree
Showing 4 changed files with 57 additions and 29 deletions.
6 changes: 3 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@
"homepage": "https://github.com/davewasmer/devcert#readme",
"devDependencies": {
"standard-version": "^4.3.0",
"typescript": "^2.7.0"
"typescript": "^2.9.2"
},
"dependencies": {
"@types/configstore": "^2.1.1",
Expand All @@ -52,7 +52,7 @@
"rimraf": "^2.6.2",
"sudo-prompt": "^8.2.0",
"tmp": "^0.0.33",
"tslib": "^1.8.1"
"tslib": "^1.10.0"
},
"optionalDependencies": {}
}
}
17 changes: 5 additions & 12 deletions src/certificate-authority.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,6 @@ export default async function installCertificateAuthority(options: Options = {})

debug(`Generating a root certificate authority`);
let rootKeyPath = mktmp();
let rootCertPath = mktmp();

debug(`Generating the OpenSSL configuration needed to setup the certificate authority`);
seedConfigFiles();
Expand All @@ -44,13 +43,13 @@ export default async function installCertificateAuthority(options: Options = {})
generateKey(rootKeyPath);

debug(`Generating a CA certificate`);
openssl(`req -new -x509 -config "${ caSelfSignConfig }" -key "${ rootKeyPath }" -out "${ rootCertPath }" -days 825`);
openssl(`req -new -x509 -config "${ caSelfSignConfig }" -key "${ rootKeyPath }" -out "${ rootCACertPath }" -days 825`);

debug('Saving certificate authority credentials');
await saveCertificateAuthorityCredentials(rootKeyPath, rootCertPath);
await saveCertificateAuthorityCredentials(rootKeyPath);

debug(`Adding the root certificate authority to trust stores`);
await currentPlatform.addToTrustStores(rootCertPath, options);
await currentPlatform.addToTrustStores(rootCACertPath, options);
}

/**
Expand Down Expand Up @@ -101,20 +100,14 @@ function seedConfigFiles() {
export async function withCertificateAuthorityCredentials(cb: ({ caKeyPath, caCertPath }: { caKeyPath: string, caCertPath: string }) => Promise<void> | void) {
debug(`Retrieving devcert's certificate authority credentials`);
let tmpCAKeyPath = mktmp();
let tmpCACertPath = mktmp();
let caKey = await currentPlatform.readProtectedFile(rootCAKeyPath);
let caCert = await currentPlatform.readProtectedFile(rootCACertPath);
writeFile(tmpCAKeyPath, caKey);
writeFile(tmpCACertPath, caCert);
await cb({ caKeyPath: tmpCAKeyPath, caCertPath: tmpCACertPath });
await cb({ caKeyPath: tmpCAKeyPath, caCertPath: rootCACertPath });
rm(tmpCAKeyPath);
rm(tmpCACertPath);
}

async function saveCertificateAuthorityCredentials(keypath: string, certpath: string) {
async function saveCertificateAuthorityCredentials(keypath: string) {
debug(`Saving devcert's certificate authority credentials`);
let key = readFile(keypath, 'utf-8');
let cert = readFile(certpath, 'utf-8');
await currentPlatform.writeProtectedFile(rootCAKeyPath, key);
await currentPlatform.writeProtectedFile(rootCACertPath, cert);
}
49 changes: 41 additions & 8 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,8 @@ import {
isWindows,
pathForDomain,
domainsDir,
rootCAKeyPath
rootCAKeyPath,
rootCACertPath
} from './constants';
import currentPlatform from './platforms';
import installCertificateAuthority from './certificate-authority';
Expand All @@ -17,12 +18,33 @@ import UI, { UserInterface } from './user-interface';

const debug = createDebug('devcert');

export interface Options {
skipCertutilInstall?: true,
skipHostsFile?: true,
export interface Options /* extends Partial<ICaBufferOpts & ICaPathOpts> */{
/** Return the CA certificate data? */
getCaBuffer?: boolean;
/** Return the path to the CA certificate? */
getCaPath?: boolean;
/** If `certutil` is not installed already (for updating nss databases; e.g. firefox), do not attempt to install it */
skipCertutilInstall?: boolean,
/** Do not update your systems host file with the domain name of the certificate */
skipHostsFile?: boolean,
/** User interface hooks */
ui?: UserInterface
}

interface ICaBuffer {
ca: Buffer;
}
interface ICaPath {
caPath: string;
}
interface IDomainData {
key: Buffer;
cert: Buffer;
}
type IReturnCa<O extends Options> = O['getCaBuffer'] extends true ? ICaBuffer : false;
type IReturnCaPath<O extends Options> = O['getCaPath'] extends true ? ICaPath : false;
type IReturnData<O extends Options = {}> = (IDomainData) & (IReturnCa<O>) & (IReturnCaPath<O>);

/**
* Request an SSL certificate for the given app name signed by the devcert root
* certificate authority. If devcert has previously generated a certificate for
Expand All @@ -34,8 +56,14 @@ export interface Options {
* Returns a promise that resolves with { key, cert }, where `key` and `cert`
* are Buffers with the contents of the certificate private key and certificate
* file, respectively
*
* If `options.getCaBuffer` is true, return value will include the ca certificate data
* as { ca: Buffer }
*
* If `options.getCaPath` is true, return value will include the ca certificate path
* as { caPath: string }
*/
export async function certificateFor(domain: string, options: Options = {}) {
export async function certificateFor<O extends Options>(domain: string, options: O = {} as O): Promise<IReturnData<O>> {
debug(`Certificate requested for ${ domain }. Skipping certutil install: ${ Boolean(options.skipCertutilInstall) }. Skipping hosts file: ${ Boolean(options.skipHostsFile) }`);

if (options.ui) {
Expand Down Expand Up @@ -68,10 +96,15 @@ export async function certificateFor(domain: string, options: Options = {}) {
}

debug(`Returning domain certificate`);
return {

const ret = {
key: readFile(domainKeyPath),
cert: readFile(domainCertPath)
};
} as IReturnData<O>;
if (options.getCaBuffer) (ret as ICaBuffer).ca = readFile(rootCACertPath);
if (options.getCaPath) (ret as ICaPath).caPath = rootCACertPath;

return ret;
}

export function hasCertificateFor(domain: string) {
Expand All @@ -84,4 +117,4 @@ export function configuredDomains() {

export function removeDomain(domain: string) {
return rimraf.sync(pathForDomain(domain));
}
}
14 changes: 8 additions & 6 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -1184,17 +1184,19 @@ trim-off-newlines@^1.0.0:
version "1.0.1"
resolved "https://registry.yarnpkg.com/trim-off-newlines/-/trim-off-newlines-1.0.1.tgz#9f9ba9d9efa8764c387698bcbfeb2c848f11adb3"

tslib@^1.8.1:
version "1.8.1"
resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.8.1.tgz#6946af2d1d651a7b1863b531d6e5afa41aa44eac"
tslib@^1.10.0:
version "1.10.0"
resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.10.0.tgz#c3c19f95973fb0a62973fb09d90d961ee43e5c8a"
integrity sha512-qOebF53frne81cf0S9B41ByenJ3/IuH8yJKngAX35CmiZySA0khhkovshKK+jGCaMnVomla7gVlIcc3EvKPbTQ==

typedarray@^0.0.6:
version "0.0.6"
resolved "https://registry.yarnpkg.com/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777"

typescript@^2.7.0:
version "2.7.2"
resolved "https://registry.yarnpkg.com/typescript/-/typescript-2.7.2.tgz#2d615a1ef4aee4f574425cdff7026edf81919836"
typescript@^2.9.2:
version "2.9.2"
resolved "https://registry.yarnpkg.com/typescript/-/typescript-2.9.2.tgz#1cbf61d05d6b96269244eb6a3bce4bd914e0f00c"
integrity sha512-Gr4p6nFNaoufRIY4NMdpQRNmgxVIGMs4Fcu/ujdYk3nAZqk7supzBE9idmvfZIlH/Cuj//dvi+019qEue9lV0w==

uglify-js@^3.1.4:
version "3.6.9"
Expand Down

0 comments on commit 0d3ce16

Please sign in to comment.