Skip to content

Commit

Permalink
feat: auto generate ssl certificates
Browse files Browse the repository at this point in the history
  • Loading branch information
Raymond Ottun committed Nov 11, 2021
1 parent fa21879 commit fe9afe3
Show file tree
Hide file tree
Showing 8 changed files with 74 additions and 34 deletions.
3 changes: 3 additions & 0 deletions docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,11 @@ services:
dockerfile: Dockerfile
context: .
environment:
DEPUTY_TSL_ENABLED: true
DEPUTY_TSL_DOMAINS: 'localhost,test.duputy.com'
DEPUTY_PORT: 8080
volumes:
- ./ssl:/app/ssl
ports:
- 8080:8080

28 changes: 28 additions & 0 deletions mocks/mocks.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
[
{
"name": "Successful todo",
"id": "first_behavior",
"request": {
"path": "/todo/[0-9]+",
"method": "(GET|POST|DELETE|PUT)"
},
"response": {
"body": {
"id": 2,
"text": "The todo body"
}
}
},
{
"name": "Failed todo",
"id": "last_behavior",
"request": {
"path": "/customer",
"method": "(GET|POST|DELETE|PUT)"
},
"response": {
"statusCode": 500,
"body": "Server blew up"
}
}
]
18 changes: 0 additions & 18 deletions mocks/mocks.yml

This file was deleted.

3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@
"clean": "rm -rf lib",
"build": "tsc",
"watch": "nodemon",
"dev": "ts-node src/deputy.ts --from-file=mocks/mocks.yml",
"dev": "ts-node src/deputy.ts --mocks-directory=mocks",
"dev:ui": "yarn --cwd ui dev",
"build:ui": "yarn --cwd ui build",
"dev:docs": "vuepress dev docs",
Expand Down Expand Up @@ -72,6 +72,7 @@
"axios": "^0.21.4",
"cli-table": "^0.3.6",
"cors": "^2.8.5",
"devcert": "^1.2.0",
"express": "^4.17.1",
"express-ws": "^5.0.2",
"morgan": "^1.10.0",
Expand Down
15 changes: 13 additions & 2 deletions src/deputy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ import os from 'os';
import path from 'path';
import yargs from 'yargs';
import { hideBin } from 'yargs/helpers';
import { isTLSEnabled } from './server/ssl';
import logger from './server/logger';
import { createServer } from './server';

Expand All @@ -30,7 +29,7 @@ const logInfo = (config) => {

eth0.forEach((it) => {
if (it.family === 'IPv4') {
const protocol = isTLSEnabled() ? 'https' : 'http';
const protocol = config.tlsEnabled ? 'https' : 'http';
const table = new Table({ head: ['Description', 'Url'] });
routes.forEach(([desc, url]) => {
table.push([desc, `http://${it.address}:${config.apiPort}${url}`]);
Expand Down Expand Up @@ -66,6 +65,18 @@ const args = yargs(hideBin(process.argv))
alias: 'd',
describe: 'A directory containing .yml files definitions',
default: process.env.DEPUTY_MOCKS_DIRECTORY || 'mocks',
})
.option('tls-enabled', {
type: 'boolean',
alias: 'tls',
describe: 'Enable HTTPS, Auto generate ssl certificates',
default: process.env.DEPUTY_TSL_ENABLED || false,
})
.option('tls-domains', {
type: 'array',
alias: 'domain',
describe: 'Specify domain to auto-generate certification for. localhost is auto included',
default: process.env.DEPUTY_TSL_DOMAINS ? process.env.DEPUTY_TSL_DOMAINS.split(',') : [],
}).argv;

const startServer = async () => {
Expand Down
12 changes: 7 additions & 5 deletions src/server/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import { WebSocketServer } from 'ws';
import https from 'https';
import http from 'http';
import { loadMocks } from './utils';
import { isTLSEnabled, loadSSLCerts } from './ssl';
import { loadSSLCerts } from './ssl';
import { createAPIRouter } from './routes/api';
import { createMocksRouter } from './routes/mocks';
import { errorHandler, responseHandler, parseBodyHandler } from './routes/middleware';
Expand All @@ -20,6 +20,8 @@ const defaultConfig: DeputyConfig = {
apiPort: 8081,
proxy: true,
mocksDirectory: 'mocks',
tlsEnabled: false,
tslDomains: [],
};

const createExpress = (): Express => {
Expand Down Expand Up @@ -62,7 +64,7 @@ export const createAPIServer = ({ engine }) => {
return http.createServer(server);
};

export const createMockServer = ({ engine }) => {
export const createMockServer = async ({ engine, config }) => {
const server = createExpress();
server.use(createMocksRouter({ engine }));
server.use(responseHandler);
Expand All @@ -71,8 +73,8 @@ export const createMockServer = ({ engine }) => {
const SERVER_TIMEOUT = 4000;
const onTimeOut = () => logger.error('Request Timeout');

if (isTLSEnabled()) {
const { cert, key } = loadSSLCerts();
if (config.tlsEnabled) {
const { cert, key } = await loadSSLCerts({ domains: config.tlsDomains });
return https.createServer({ key, cert }, server).setTimeout(SERVER_TIMEOUT, onTimeOut);
} else {
return http.createServer(server).setTimeout(SERVER_TIMEOUT, onTimeOut);
Expand All @@ -83,7 +85,7 @@ export const createServer = async (argConfig: DeputyConfig): Promise<App> => {
const config = Object.assign({}, defaultConfig, argConfig);
const engine = createEngine(config);

const mockServer = createMockServer({ engine });
const mockServer = await createMockServer({ engine, config });
const apiServer = createAPIServer({ engine });

return {
Expand Down
28 changes: 20 additions & 8 deletions src/server/ssl.ts
Original file line number Diff line number Diff line change
@@ -1,21 +1,33 @@
import path from 'path';
import fs from 'fs';
import * as devcert from 'devcert';

const TLS_CERT_NAME = 'cert.pem';
const TLS_KEY_NAME = 'key.pem';
const keyFile = path.join(process.cwd(), 'ssl', TLS_KEY_NAME);
const certFile = path.join(process.cwd(), 'ssl', TLS_CERT_NAME);

export const loadSSLCerts = () => {
return {
cert: fs.readFileSync(certFile),
key: fs.readFileSync(keyFile),
};
};

export const isTLSEnabled = () => {
const isSSLExisting = () => {
if (process.env.NODE_ENV === 'test') {
return false;
}
return fs.existsSync(keyFile) && fs.existsSync(certFile);
};

const generateSSL = async ({ domains }) => {
const { key, cert } = await devcert.certificateFor(['localhost', ...domains]);

fs.mkdirSync(path.join(process.cwd(), 'ssl'));
fs.writeFileSync(keyFile, key);
fs.writeFileSync(certFile, cert);
};

export const loadSSLCerts = async ({ domains }) => {
if (!isSSLExisting()) {
await generateSSL({ domains });
}
return Promise.resolve({
cert: fs.readFileSync(certFile),
key: fs.readFileSync(keyFile),
});
};
1 change: 1 addition & 0 deletions src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -139,4 +139,5 @@ export interface DeputyConfig {
mocksDirectory?: string;
tlsEnabled?: boolean;
proxy?: boolean;
tslDomains?: Array<string>;
}

0 comments on commit fe9afe3

Please sign in to comment.