Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
"body-parser": "^1.20.3",
"connect-timeout": "^1.9.0",
"debug": "^3.1.0",
"winston": "^3.11.0",
"express": "4.17.3",
"lodash": "^4.17.20",
"morgan": "^1.9.1",
Expand All @@ -41,6 +42,7 @@
"@types/node": "^16.18.46",
"@types/sinon": "^10.0.11",
"@types/supertest": "^2.0.11",
"@types/winston": "^2.4.4",
"@typescript-eslint/eslint-plugin": "^5.0.0",
"@typescript-eslint/parser": "^5.0.0",
"eslint": "^8.0.0",
Expand Down
30 changes: 13 additions & 17 deletions src/enclavedApp.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
* @prettier
*/
import express from 'express';
import debug from 'debug';
import https from 'https';
import http from 'http';
import morgan from 'morgan';
Expand All @@ -20,28 +19,25 @@ import {
prepareIpc,
readCertificates,
} from './shared/appUtils';

const debugLogger = debug('enclaved:express');
import logger from './logger';

/**
* Create a startup function which will be run upon server initialization
*/
export function startup(config: EnclavedConfig, baseUri: string): () => void {
return function () {
/* eslint-disable no-console */
console.log('BitGo Enclaved Express running');
console.log(`Base URI: ${baseUri}`);
console.log(`TLS Mode: ${config.tlsMode}`);
console.log(`mTLS Enabled: ${config.tlsMode === TlsMode.MTLS}`);
console.log(`Request Client Cert: ${config.mtlsRequestCert}`);
console.log(`Reject Unauthorized: ${config.mtlsRejectUnauthorized}`);
/* eslint-enable no-console */
logger.info('BitGo Enclaved Express running');
logger.info(`Base URI: ${baseUri}`);
logger.info(`TLS Mode: ${config.tlsMode}`);
logger.info(`mTLS Enabled: ${config.tlsMode === TlsMode.MTLS}`);
logger.info(`Request Client Cert: ${config.mtlsRequestCert}`);
logger.info(`Reject Unauthorized: ${config.mtlsRejectUnauthorized}`);
};
}

function isTLS(config: EnclavedConfig): boolean {
const { keyPath, crtPath, tlsKey, tlsCert, tlsMode } = config;
console.log('TLS Configuration:', {
logger.debug('TLS Configuration:', {
tlsMode,
hasKeyPath: Boolean(keyPath),
hasCrtPath: Boolean(crtPath),
Expand All @@ -64,12 +60,12 @@ async function createHttpsServer(
if (tlsKey && tlsCert) {
key = tlsKey;
cert = tlsCert;
console.log('Using TLS key and cert from environment variables');
logger.info('Using TLS key and cert from environment variables');
} else if (keyPath && crtPath) {
const certificates = await readCertificates(keyPath, crtPath);
key = certificates.key;
cert = certificates.cert;
console.log(`Using TLS key and cert from files: ${keyPath}, ${crtPath}`);
logger.info(`Using TLS key and cert from files: ${keyPath}, ${crtPath}`);
} else {
throw new Error('Failed to get TLS key and certificate');
}
Expand Down Expand Up @@ -127,12 +123,12 @@ export function createBaseUri(config: EnclavedConfig): string {
* Create and configure the express application
*/
export function app(cfg: EnclavedConfig): express.Application {
debugLogger('app is initializing');
logger.debug('app is initializing');

const app = express();

setupLogging(app, cfg);
debugLogger('logging setup');
logger.debug('logging setup');

// Add custom morgan token for mTLS client certificate
morgan.token('remote-user', function (req: express.Request) {
Expand All @@ -146,7 +142,7 @@ export function app(cfg: EnclavedConfig): express.Application {
routes.setupRoutes(app);

// Add error handler
app.use(createErrorHandler(debugLogger));
app.use(createErrorHandler());

return app;
}
Expand Down
61 changes: 61 additions & 0 deletions src/logger.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
import winston from 'winston';

// Define log levels
const levels = {
error: 0,
warn: 1,
info: 2,
http: 3,
debug: 4,
};

// Define level based on environment
const level = () => {
const env = process.env.NODE_ENV || 'development';
const isDevelopment = env === 'development';
return isDevelopment ? 'debug' : 'warn';
};

// Define colors for each level
const colors = {
error: 'red',
warn: 'yellow',
info: 'green',
http: 'magenta',
debug: 'white',
};

// Add colors to winston
winston.addColors(colors);

// Define the format for the logs
const format = winston.format.combine(
winston.format.timestamp({ format: 'YYYY-MM-DD HH:mm:ss:ms' }),
winston.format.colorize({ all: true }),
winston.format.printf(
(info: winston.Logform.TransformableInfo) => `${info.timestamp} ${info.level}: ${info.message}`,
),
);

// Define which transports the logger must use
const transports = [
// Console transport
new winston.transports.Console(),
// Error log file transport
new winston.transports.File({
filename: 'logs/error.log',
level: 'error',
}),
// All logs file transport
new winston.transports.File({ filename: 'logs/all.log' }),
];

// Create the logger instance
const logger = winston.createLogger({
level: level(),
levels,
format,
transports,
});

export default logger;
42 changes: 20 additions & 22 deletions src/masterExpressApp.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
* @prettier
*/
import express from 'express';
import debug from 'debug';
import https from 'https';
import http from 'http';
import superagent from 'superagent';
Expand All @@ -28,22 +27,20 @@ import { ProxyAgent } from 'proxy-agent';
import { promiseWrapper } from './routes';
import pjson from '../package.json';
import { handleGenerateWalletOnPrem } from './masterBitgoExpress/generateWallet';
import logger from './logger';

const debugLogger = debug('master-express:express');
const BITGOEXPRESS_USER_AGENT = `BitGoExpress/${pjson.version} BitGoJS/${version}`;

/**
* Create a startup function which will be run upon server initialization
*/
export function startup(config: MasterExpressConfig, baseUri: string): () => void {
return function () {
/* eslint-disable no-console */
console.log('BitGo Master Express running');
console.log(`Base URI: ${baseUri}`);
console.log(`Environment: ${config.env}`);
console.log(`SSL Enabled: ${config.enableSSL}`);
console.log(`Proxy Enabled: ${config.enableProxy}`);
/* eslint-enable no-console */
logger.info('BitGo Master Express running');
logger.info(`Base URI: ${baseUri}`);
logger.info(`Environment: ${config.env}`);
logger.info(`SSL Enabled: ${config.enableSSL}`);
logger.info(`Proxy Enabled: ${config.enableProxy}`);
};
}

Expand Down Expand Up @@ -123,12 +120,12 @@ async function createHttpsServer(
if (sslKey && sslCert) {
key = sslKey;
cert = sslCert;
console.log('Using SSL key and cert from environment variables');
logger.info('Using SSL key and cert from environment variables');
} else if (keyPath && crtPath) {
const certificates = await readCertificates(keyPath, crtPath);
key = certificates.key;
cert = certificates.cert;
console.log(`Using SSL key and cert from files: ${keyPath}, ${crtPath}`);
logger.info(`Using SSL key and cert from files: ${keyPath}, ${crtPath}`);
} else {
throw new Error('Failed to get SSL key and certificate');
}
Expand Down Expand Up @@ -165,16 +162,17 @@ function setupMasterExpressRoutes(app: express.Application): void {
setupHealthCheckRoutes(app, 'master express');

const cfg = config() as MasterExpressConfig;
console.log('SSL Enabled:', cfg.enableSSL);
console.log('Enclaved Express URL:', cfg.enclavedExpressUrl);
console.log('Certificate exists:', Boolean(cfg.enclavedExpressSSLCert));
console.log('Certificate length:', cfg.enclavedExpressSSLCert.length);
console.log('Certificate content:', cfg.enclavedExpressSSLCert);
logger.debug('SSL Configuration:', {
sslEnabled: cfg.enableSSL,
enclavedExpressUrl: cfg.enclavedExpressUrl,
hasCertificate: Boolean(cfg.enclavedExpressSSLCert),
certificateLength: cfg.enclavedExpressSSLCert.length,
});

// Add enclaved express ping route
app.post('/ping/enclavedExpress', async (req, res) => {
try {
console.log('Pinging enclaved express');
logger.debug('Pinging enclaved express');

const response = await superagent
.get(`${cfg.enclavedExpressUrl}/ping`)
Expand All @@ -192,7 +190,7 @@ function setupMasterExpressRoutes(app: express.Application): void {
enclavedResponse: response.body,
});
} catch (error) {
debugLogger('Failed to ping enclaved express:', error);
logger.error('Failed to ping enclaved express:', { error });
res.status(500).json({
error: 'Failed to ping enclaved express',
details: error instanceof Error ? error.message : String(error),
Expand All @@ -215,19 +213,19 @@ function setupMasterExpressRoutes(app: express.Application): void {
});
});

debugLogger('Master express routes configured');
logger.debug('Master express routes configured');
}

/**
* Create and configure the express application for master express mode
*/
export function app(cfg: MasterExpressConfig): express.Application {
debugLogger('master express app is initializing');
logger.debug('master express app is initializing');

const app = express();

setupLogging(app, cfg);
debugLogger('logging setup');
logger.debug('logging setup');

setupDebugNamespaces(cfg.debugNamespace);
setupCommonMiddleware(app, cfg);
Expand All @@ -236,7 +234,7 @@ export function app(cfg: MasterExpressConfig): express.Application {
setupMasterExpressRoutes(app);

// Add error handler
app.use(createErrorHandler(debugLogger));
app.use(createErrorHandler());

return app;
}
Expand Down
13 changes: 6 additions & 7 deletions src/shared/appUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
*/
import express from 'express';
import path from 'path';
import debug from 'debug';
import https from 'https';
import http from 'http';
import morgan from 'morgan';
Expand All @@ -12,6 +11,7 @@ import timeout from 'connect-timeout';
import bodyParser from 'body-parser';
import _ from 'lodash';
import pjson from '../../package.json';
import logger from '../logger';

import { Config } from '../config';

Expand All @@ -25,8 +25,7 @@ export function setupLogging(app: express.Application, config: Config): void {
// create a write stream (in append mode)
const accessLogPath = path.resolve(config.logFile);
const accessLogStream = fs.createWriteStream(accessLogPath, { flags: 'a' });
/* eslint-disable-next-line no-console */
console.log('Log location: ' + accessLogPath);
logger.info(`Log location: ${accessLogPath}`);
// setup the logger
middleware = morgan('combined', { stream: accessLogStream });
} else {
Expand All @@ -42,8 +41,8 @@ export function setupLogging(app: express.Application, config: Config): void {
export function setupDebugNamespaces(debugNamespace?: string[]): void {
if (_.isArray(debugNamespace)) {
for (const ns of debugNamespace) {
if (ns && !debug.enabled(ns)) {
debug.enable(ns);
if (ns) {
logger.debug(`Enabling debug namespace: ${ns}`);
}
}
}
Expand Down Expand Up @@ -73,14 +72,14 @@ export function setupCommonMiddleware(app: express.Application, config: Config):
/**
* Create error handling middleware
*/
export function createErrorHandler(debugLogger: debug.Debugger) {
export function createErrorHandler() {
return function (
err: any,
req: express.Request,
res: express.Response,
_next: express.NextFunction,
) {
debugLogger('Error: ' + (err && err.message ? err.message : String(err)));
logger.error('Error:', { error: err && err.message ? err.message : String(err) });
const statusCode = err && err.status ? err.status : 500;
const result = {
error: err && err.message ? err.message : String(err),
Expand Down
Loading