Skip to content
Open
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
3 changes: 3 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ COPY --from=builder /tmp/bitgo/modules/statics /var/modules/statics/
COPY --from=builder /tmp/bitgo/modules/utxo-lib /var/modules/utxo-lib/
COPY --from=builder /tmp/bitgo/modules/blake2b /var/modules/blake2b/
COPY --from=builder /tmp/bitgo/modules/blake2b-wasm /var/modules/blake2b-wasm/
COPY --from=builder /tmp/bitgo/modules/logger /var/modules/logger/
COPY --from=builder /tmp/bitgo/modules/bitgo /var/modules/bitgo/
COPY --from=builder /tmp/bitgo/modules/abstract-utxo /var/modules/abstract-utxo/
COPY --from=builder /tmp/bitgo/modules/blockapis /var/modules/blockapis/
Expand Down Expand Up @@ -147,6 +148,7 @@ cd /var/modules/statics && yarn link && \
cd /var/modules/utxo-lib && yarn link && \
cd /var/modules/blake2b && yarn link && \
cd /var/modules/blake2b-wasm && yarn link && \
cd /var/modules/logger && yarn link && \
cd /var/modules/bitgo && yarn link && \
cd /var/modules/abstract-utxo && yarn link && \
cd /var/modules/blockapis && yarn link && \
Expand Down Expand Up @@ -249,6 +251,7 @@ RUN cd /var/bitgo-express && \
yarn link @bitgo/utxo-lib && \
yarn link @bitgo/blake2b && \
yarn link @bitgo/blake2b-wasm && \
yarn link @bitgo/logger && \
yarn link bitgo && \
yarn link @bitgo/abstract-utxo && \
yarn link @bitgo/blockapis && \
Expand Down
1 change: 1 addition & 0 deletions modules/blockapis/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
"directory": "modules/blockapis"
},
"dependencies": {
"@bitgo/logger": "^1.0.0",
"@bitgo/utxo-lib": "^11.20.0",
"@types/superagent": "4.1.16",
"superagent": "^9.0.1"
Expand Down
3 changes: 2 additions & 1 deletion modules/blockapis/src/BaseHttpClient.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import * as superagent from 'superagent';
import { logger } from '@bitgo/logger';

export class ApiRequestError extends Error {
constructor(public url: string, public reason: Error | string) {
Expand Down Expand Up @@ -64,7 +65,7 @@ export class BaseHttpClient implements HttpClient {
try {
response = await superagent(method, url).send(requestBody as Record<string, unknown>);
} catch (e) {
console.error(e);
logger.error(e);
throw new ApiRequestError(url, e as Error);
}
if (!response.ok) {
Expand Down
1 change: 1 addition & 0 deletions modules/express/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@
"@api-ts/io-ts-http": "^3.2.1",
"@api-ts/typed-express-router": "2.0.0",
"@bitgo/abstract-lightning": "^7.7.0",
"@bitgo/logger": "^1.0.0",
"@bitgo/sdk-core": "^36.30.0",
"@bitgo/utxo-lib": "^11.20.0",
"@types/proxyquire": "^1.3.31",
Expand Down
13 changes: 7 additions & 6 deletions modules/express/src/clientRoutes.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
/**
* @prettier
*/
import { logger } from '@bitgo/logger';
import {
CommitmentShareRecord,
CreateNetworkConnectionParams,
Expand Down Expand Up @@ -491,7 +492,7 @@ export async function handleV2GenerateShareTSS(
throw new Error(`MPC Algorithm ${coin.getMPCAlgorithm()} is not supported.`);
}
} catch (error) {
console.error('error while signing wallet transaction ', error);
logger.error('error while signing wallet transaction', error);
throw error;
}
}
Expand All @@ -504,7 +505,7 @@ export async function handleV2SignTSSWalletTx(req: ExpressApiRouteRequest<'expre
try {
return await wallet.ensureCleanSigSharesAndSignTransaction(createTSSSendParams(req, wallet));
} catch (error) {
console.error('error while signing wallet transaction ', error);
logger.error('error while signing wallet transaction', error);
throw error;
}
}
Expand Down Expand Up @@ -536,7 +537,7 @@ export async function handleV2Sign(req: ExpressApiRouteRequest<'express.v2.coin.
try {
return await coin.signTransaction({ ...req.body, prv: privKey });
} catch (error) {
console.log('error while signing wallet transaction ', error);
logger.error('error while signing wallet transaction', error);
throw error;
}
}
Expand Down Expand Up @@ -586,7 +587,7 @@ export async function handleV2OFCSignPayloadInExtSigningMode(
signature,
};
} catch (error) {
console.log('Error while signing message.', error);
logger.error('Error while signing message', error);
throw error;
}
}
Expand Down Expand Up @@ -730,7 +731,7 @@ async function handleV2SignTxWallet(req: ExpressApiRouteRequest<'express.v2.wall
try {
return await wallet.signTransaction(createSendParams(req));
} catch (error) {
console.log('error while signing wallet transaction ', error);
logger.error('error while signing wallet transaction', error);
throw error;
}
}
Expand All @@ -745,7 +746,7 @@ async function handleV2SignTx(req: ExpressApiRouteRequest<'express.v2.coin.signt
try {
return await coin.signTransaction(req.decoded);
} catch (error) {
console.log('error while signing the transaction ', error);
logger.error('error while signing the transaction', error);
throw error;
}
}
Expand Down
3 changes: 2 additions & 1 deletion modules/express/src/fetchEncryptedPrivKeys.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
* Copyright 2022, BitGo, Inc. All Rights Reserved.
*/
import { writeFile } from 'fs';
import { logger } from '@bitgo/logger';
import { BitGo, EnvironmentName } from 'bitgo';
import 'dotenv/config';

Expand Down Expand Up @@ -112,4 +113,4 @@ export async function fetchKeys(ids: WalletIds, token: string, accessToken?: str
return Promise.resolve(output);
}

fetchKeys(walletIds, accessToken).catch((e) => console.error(e));
fetchKeys(walletIds, accessToken).catch((e) => logger.error(e));
2 changes: 2 additions & 0 deletions modules/logger/.eslintignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
dist
node_modules
4 changes: 4 additions & 0 deletions modules/logger/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
dist
node_modules
.nyc_output
*.log
9 changes: 9 additions & 0 deletions modules/logger/.npmignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
src
test
.eslintignore
.gitignore
.prettierignore
.prettierrc.yml
.mocharc.js
tsconfig.json
.nyc_output
2 changes: 2 additions & 0 deletions modules/logger/.prettierignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
dist
node_modules
3 changes: 3 additions & 0 deletions modules/logger/.prettierrc.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
printWidth: 120
trailingComma: es5
singleQuote: true
5 changes: 5 additions & 0 deletions modules/logger/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# @bitgo/logger

## 1.0.0

- Initial release with sensitive data sanitization
35 changes: 35 additions & 0 deletions modules/logger/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
{
"name": "@bitgo/logger",
"version": "1.0.0",
"description": "BitGo logger with sensitive data sanitization",
"main": "./dist/src/index.js",
"types": "./dist/src/index.d.ts",
"files": [
"dist"
],
"scripts": {
"build": "yarn tsc --build --incremental --verbose .",
"fmt": "prettier --write .",
"check-fmt": "prettier --check '**/*.{ts,js,json}'",
"clean": "rm -r ./dist",
"lint": "eslint --quiet .",
"prepare": "npm run build"
},
"author": "BitGo SDK Team <sdkteam@bitgo.com>",
"license": "MIT",
"repository": {
"type": "git",
"url": "https://github.com/BitGo/BitGoJS.git",
"directory": "modules/logger"
},
"lint-staged": {
"*.{js,ts}": [
"yarn prettier --write",
"yarn eslint --fix"
]
},
"publishConfig": {
"access": "public"
},
"dependencies": {}
}
1 change: 1 addition & 0 deletions modules/logger/src/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { logger } from './logger';
71 changes: 71 additions & 0 deletions modules/logger/src/logger.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
import { sanitize } from './sanitizeLog';

/**
* BitGo Logger with automatic sanitization in test/staging environments
*/
class BitGoLogger {
/**
* Determines if sanitization should be applied based on NODE_ENV
*/
private shouldSanitize(): boolean {
const env = process.env.NODE_ENV;
return env === 'test' || env === 'staging';
}

/**
* Sanitizes arguments if in test/staging environment
*/
private sanitizeArgs(args: unknown[]): unknown[] {
if (!this.shouldSanitize()) {
return args;
}

return args.map((arg) => {
if (typeof arg === 'object' && arg !== null) {
return sanitize(arg);
}
return arg;
});
}

/**
* Logs a message with automatic sanitization
*/
log(...args: unknown[]): void {
const sanitized = this.sanitizeArgs(args);
// eslint-disable-next-line no-console
console.log(...sanitized);
}

/**
* Logs an error message with automatic sanitization
*/
error(...args: unknown[]): void {
const sanitized = this.sanitizeArgs(args);
// eslint-disable-next-line no-console
console.error(...sanitized);
}

/**
* Logs a warning message with automatic sanitization
*/
warn(...args: unknown[]): void {
const sanitized = this.sanitizeArgs(args);
// eslint-disable-next-line no-console
console.warn(...sanitized);
}

/**
* Logs an info message with automatic sanitization
*/
info(...args: unknown[]): void {
const sanitized = this.sanitizeArgs(args);
// eslint-disable-next-line no-console
console.info(...sanitized);
}
}

/**
* Singleton logger instance
*/
export const logger = new BitGoLogger();
78 changes: 78 additions & 0 deletions modules/logger/src/sanitizeLog.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
/**
* Sanitizes sensitive data from logs to prevent token exposure in test/staging environments
*/

const SENSITIVE_KEYS = new Set([
'token',
'bearer',
'prv',
'xprv',
'privatekey',
'password',
'otp',
'passphrase',
'walletPassphrase',
]);

const BEARER_V2_PATTERN = /^v2x[a-f0-9]{32,}$/i;

/**
* Checks if a key is sensitive (case-insensitive)
*/
function isSensitiveKey(key: string): boolean {
return SENSITIVE_KEYS.has(key.toLowerCase());
}

/**
* Checks if a value matches the bearer v2 token pattern
*/
function isBearerV2Token(value: unknown): boolean {
return typeof value === 'string' && BEARER_V2_PATTERN.test(value);
}

/**
* Recursively sanitizes an object, replacing sensitive values with '<REMOVED>'
* Handles circular references and nested structures
*/
export function sanitize(obj: unknown, seen = new WeakSet<Record<string, unknown>>(), depth = 0): unknown {
// Prevent infinite recursion
if (depth > 50) {
return '[Max Depth Exceeded]';
}

// Handle primitives
if (obj === null || obj === undefined) {
return obj;
}

if (typeof obj !== 'object') {
return obj;
}

// Handle circular references
if (seen.has(obj as Record<string, unknown>)) {
return '[Circular]';
}

seen.add(obj as Record<string, unknown>);

// Handle arrays
if (Array.isArray(obj)) {
return obj.map((item) => sanitize(item, seen, depth + 1));
}

// Handle objects
const sanitized: Record<string, unknown> = {};

for (const [key, value] of Object.entries(obj)) {
if (isSensitiveKey(key) || isBearerV2Token(value)) {
sanitized[key] = '<REMOVED>';
} else if (typeof value === 'object' && value !== null) {
sanitized[key] = sanitize(value, seen, depth + 1);
} else {
sanitized[key] = value;
}
}

return sanitized;
}
12 changes: 12 additions & 0 deletions modules/logger/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
{
"extends": "../../tsconfig.json",
"compilerOptions": {
"outDir": "./dist",
"rootDir": "./",
"strictPropertyInitialization": false,
"esModuleInterop": true,
"typeRoots": ["../../types", "./node_modules/@types", "../../node_modules/@types"]
},
"include": ["src/**/*", "test/**/*"],
"exclude": ["node_modules"]
}
1 change: 1 addition & 0 deletions modules/sdk-coin-apt/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@
},
"dependencies": {
"@aptos-labs/ts-sdk": "1.33.1",
"@bitgo/logger": "^1.0.0",
"@bitgo/sdk-core": "^36.30.0",
"@bitgo/statics": "^58.24.0",
"bignumber.js": "^9.1.2",
Expand Down
3 changes: 2 additions & 1 deletion modules/sdk-coin-apt/src/lib/transaction/transaction.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import {
TransactionRecipient,
TransactionType,
} from '@bitgo/sdk-core';
import { logger } from '@bitgo/logger';
import { BaseCoin as CoinConfig, NetworkType } from '@bitgo/statics';
import {
AccountAddress,
Expand Down Expand Up @@ -222,7 +223,7 @@ export abstract class Transaction extends BaseTransaction {
feePayerSignature
);
} catch (e) {
console.error('invalid signed transaction', e);
logger.error('invalid signed transaction', e);
throw new Error('invalid signed transaction');
}
}
Expand Down
Loading
Loading