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
6 changes: 3 additions & 3 deletions .github/workflows/codeql-analysis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ jobs:

# Initializes the CodeQL tools for scanning.
- name: Initialize CodeQL
uses: github/codeql-action/init@v2
uses: github/codeql-action/init@v3
with:
languages: ${{ matrix.language }}
# If you wish to specify custom queries, you can do so here or in a config file.
Expand All @@ -52,7 +52,7 @@ jobs:
# Autobuild attempts to build any compiled languages (C/C++, C#, or Java).
# If this step fails, then you should remove it and run the build manually (see below)
- name: Autobuild
uses: github/codeql-action/autobuild@v2
uses: github/codeql-action/autobuild@v3

# ℹ️ Command-line programs to run using the OS shell.
# 📚 See https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstepsrun
Expand All @@ -65,4 +65,4 @@ jobs:
# ./location_of_script_within_repo/buildscript.sh

- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@v2
uses: github/codeql-action/analyze@v3
37 changes: 19 additions & 18 deletions src/core.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import { debug as Debug } from 'debug';
import { createServer } from 'http';
import { promisify } from 'util';
import { logger as log } from './logger';
import { MESSAGES } from './messages';


let _config: any = {};
Expand All @@ -26,25 +27,25 @@ let jsonParser = promisify(bodyParser.json({ limit: '1mb' }));
*/
const requestHandler = (request, response) => {

log.info(`Request recived, '${request.method} : ${request.url}'`);
log.info(MESSAGES.REQUEST_RECEIVED);
debug('_config', _config);
// Explicitly remove or override the X-Powered-By header
response.setHeader('X-Powered-By', '');
return Promise.resolve().then(() => {
// Should be a POST call.
if (request.method && request.method !== 'POST') {
debug('Only POST call is supported.');
debug(MESSAGES.ONLY_POST_SUPPORTED);
return Promise.reject({
body: `Only POST call is supported.`,
body: `Only POST requests are supported.`,
statusCode: 400,
statusMessage: 'Not allowed',
});
}
}).then(() => {
// validate endpoint
debug(`${request.url} invoked`);
debug(MESSAGES.REQUEST_INVOKED(request.url));
if (_config && _config.listener && request.url !== _config.listener.endpoint) {
debug('url authentication failed');
debug(MESSAGES.URL_AUTH_FAILED);
return Promise.reject({
body: `${request.url} not found.`,
statusCode: 404,
Expand All @@ -53,12 +54,12 @@ const requestHandler = (request, response) => {
}
}).then(() => {
// verify authorization
debug('validating basic auth', _config.listener);
debug(MESSAGES.VALIDATING_BASIC_AUTH, _config.listener);
if (_config && _config.listener && _config.listener.basic_auth) {
debug('validating basic auth');
debug(MESSAGES.VALIDATING_BASIC_AUTH);
const creds = BasicAuth(request);
if (!creds || (creds.name !== _config.listener.basic_auth.user || creds.pass !== _config.listener.basic_auth.pass)) {
debug('basic auth failed');
debug(MESSAGES.BASIC_AUTH_FAILED);
debug(
'expected %O but received %O',
_config.listener.basic_auth,
Expand All @@ -73,12 +74,12 @@ const requestHandler = (request, response) => {
}
}).then(() => {
// validate custom headers
debug('validate custom headers');
debug(MESSAGES.VALIDATING_CUSTOM_HEADERS);
if (_config && _config.listener) {
for (const headerKey in _config.listener.headers) {
debug('validating headers');
debug(MESSAGES.VALIDATING_HEADERS);
if (request.headers[headerKey] !== _config.listener.headers[headerKey]) {
debug(`${headerKey} was not found in req headers`);
debug(MESSAGES.HEADER_NOT_FOUND(headerKey));
return Promise.reject({
body: 'Header key mismatch.',
statusCode: 417,
Expand All @@ -88,7 +89,7 @@ const requestHandler = (request, response) => {
}
}
}).then(async () => {
debug('parsing json');
debug(MESSAGES.PARSING_JSON);
try {
if (_config.reqBodyLimit) {
jsonParser = promisify(bodyParser.json({ limit: _config.reqBodyLimit }));
Expand All @@ -103,13 +104,13 @@ const requestHandler = (request, response) => {
locale = body.data.locale;
}
debug('_config.listener.actions[type]', _config.listener.actions[type]);
debug('event', event);
debug(MESSAGES.EVENT, event);
// validate event:type
if (
!_config.listener.actions[type] ||
_config.listener.actions[type].indexOf(event) === -1
) {
debug(`${event}:${type} not defined for processing`);
debug(MESSAGES.EVENT_NOT_DEFINED(event, type));
return Promise.reject({
body: `${event}:${type} not defined for processing`,
statusCode: 403,
Expand Down Expand Up @@ -137,9 +138,9 @@ const requestHandler = (request, response) => {
}
data.event = event;
_notify(data).then((data) => {
debug('Data [_notify]', data);
debug(MESSAGES.DATA_RECEIVED_NOTIFY, data);
}).catch((error) => {
debug('Error [_notify]', error);
debug(MESSAGES.ERROR_OCCURRED_NOTIFY, error);
});
return Promise.resolve({ statusCode: 200, statusMessage: 'OK', body: data });
} catch (err) {
Expand All @@ -150,7 +151,7 @@ const requestHandler = (request, response) => {
});
}
}).then((value) => {
debug('Value', value);
debug(MESSAGES.VALUE, value);
response.setHeader('Content-Type', 'application/json');
response.statusCode = value.statusCode;
response.statusMessage = value.statusMessage;
Expand All @@ -162,7 +163,7 @@ const requestHandler = (request, response) => {
response.end(JSON.stringify(safeBody));
return;
}).catch((error) => {
debug('Error', error);
debug(MESSAGES.ERROR, error);
const safeError = {
statusCode: error.statusCode || 500,
statusMessage: error.statusMessage || 'Internal Server Error',
Expand Down
13 changes: 7 additions & 6 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import { merge } from 'lodash';
import { createListener } from './core';
import { defaultConfig } from './defaults';
import { logger as log, setLogger } from './logger';
import { MESSAGES } from './messages';

const debug = Debug('webhook:listener');
let notify;
Expand All @@ -26,7 +27,7 @@ export function register(consumer: any) {
if (typeof consumer !== 'function') {
throw new Error('Provide function to notify consumer.');
}
debug('register called with %O', notify);
debug(MESSAGES.REGISTER_CALLED, notify);
notify = consumer;
return true;
}
Expand All @@ -44,7 +45,7 @@ export function start(userConfig: any, customLogger?: any) {
if (customLogger) {
setLogger(customLogger);
}
debug('start called with %O', userConfig);
debug(MESSAGES.START_CALLED, userConfig);
appConfig = merge(appConfig, userConfig)
validateConfig(appConfig);

Expand All @@ -59,10 +60,10 @@ export function start(userConfig: any, customLogger?: any) {
);
}

debug('starting with config: ' + JSON.stringify(appConfig));
debug(MESSAGES.STARTING_WITH_CONFIG(JSON.stringify(appConfig)));
const port = process.env.PORT || appConfig.listener.port;
const server = createListener(appConfig, notify).listen(port, () => {
log.info(`Server running at port ${port}`);
log.info(MESSAGES.SERVER_RUNNING(port));
});
return resolve(server);
} catch (error) {
Expand Down Expand Up @@ -102,14 +103,14 @@ function validateConfig(customConfig) {
customConfig.listener.endpoint = '/' + customConfig.listener.endpoint;
}
} else {
throw new TypeError('Please provide valide listener.endpoint');
throw new TypeError(MESSAGES.INVALID_LISTENER_ENDPOINT);
}
}
if (
customConfig.listener.port &&
typeof customConfig.listener.port !== 'number'
) {
throw new TypeError('Please provide valide listener.port');
throw new TypeError(MESSAGES.INVALID_LISTENER_PORT);
}
}
}
Expand Down
7 changes: 4 additions & 3 deletions src/logger.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { Console } from 'console';
import { MESSAGES } from './messages';

let logger;
logger = new Console(process.stdout, process.stderr);
Expand All @@ -11,10 +12,10 @@ logger = new Console(process.stdout, process.stderr);
function setLogger(customLogger) {
const validator = validateLogger(customLogger);
if (!validator) {
console.warn('Failed to register logger, using console for logging.');
console.warn(MESSAGES.LOGGER_REGISTRATION_FAILED);
} else {
logger = customLogger;
logger.info('Logger registered successfully.');
logger.info(MESSAGES.LOGGER_REGISTERED_SUCCESS);
}
}

Expand All @@ -26,7 +27,7 @@ const validateLogger = (instance) => {
const requiredFn = ['info', 'warn', 'log', 'error', 'debug'];
requiredFn.forEach((name) => {
if (typeof instance[name] !== 'function') {
console.warn(`Unable to register custom logger since '${name}()' does not exist on ${instance}!`);
console.warn(MESSAGES.UNABLE_TO_REGISTER_LOGGER(name, instance));
flag = true;
}
});
Expand Down
54 changes: 54 additions & 0 deletions src/messages.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
/*!
* contentstack-webhook-listener
* copyright (c) Contentstack LLC
* MIT Licensed
*/

'use strict';

/**
* Centralized messages for the webhook listener.
* This file contains all log messages, debug messages, and error messages
* used throughout the application.
*/

export const MESSAGES = {
// Debug messages for index.ts
REGISTER_CALLED: 'Register called with object: %O',
START_CALLED: 'Start called with object: %O',
STARTING_WITH_CONFIG: (config: string) => `Starting with config: ${config}`,

// Log messages for index.ts
SERVER_RUNNING: (port: string | number) => `Server is running on port ${port}.`,

// Error messages for index.ts
INVALID_LISTENER_ENDPOINT: 'Please provide a valid listener endpoint.',
INVALID_LISTENER_PORT: 'Please provide a valid listener port.',

// Log messages for core.ts
REQUEST_RECEIVED: 'Request received.',

// Debug messages for core.ts
ONLY_POST_SUPPORTED: 'Only POST requests are supported.',
REQUEST_INVOKED: (url: string) => `Request invoked: ${url}`,
URL_AUTH_FAILED: 'URL authentication failed.',
VALIDATING_BASIC_AUTH: 'Validating basic authentication...',
BASIC_AUTH_FAILED: 'Basic authentication failed.',
VALIDATING_CUSTOM_HEADERS: 'Validating custom headers...',
VALIDATING_HEADERS: 'Validating headers...',
HEADER_NOT_FOUND: (headerKey: string) => `Header '${headerKey}' was not found in the request.`,
PARSING_JSON: 'Parsing JSON...',
EVENT: 'Event',
EVENT_NOT_DEFINED: (event: string, type: string) => `Event '${event}:${type}' not defined for processing.`,
DATA_RECEIVED_NOTIFY: 'Data received for [_notify].',
ERROR_OCCURRED_NOTIFY: 'Error occurred in [_notify].',
VALUE: 'Value',
ERROR: 'Error',

// Logger messages
LOGGER_REGISTRATION_FAILED: 'Failed to register logger.',
LOGGER_REGISTERED_SUCCESS: 'Logger registered successfully.',
UNABLE_TO_REGISTER_LOGGER: (name: string, instance: any) =>
`Unable to register custom logger: '${name}()' does not exist on ${instance}.`,
};

10 changes: 5 additions & 5 deletions test/unit/index.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,7 @@ describe("Test start method without user config.", () => {
.then(response => {
expect(response.statusCode).toBe(400);
expect(response.body.error.message).toBe(
"Only POST call is supported.",
"Only POST requests are supported.",
);
});
});
Expand Down Expand Up @@ -147,7 +147,7 @@ describe("Test start method with custom logger", () => {
});
});

describe("Test start method with invalid user config", async () => {
describe("Test start method with invalid user config", () => {
test("It should throw error when endpoint in config set to number", () => {
let config;
register(notify);
Expand All @@ -160,7 +160,7 @@ describe("Test start method with invalid user config", async () => {
start(config)
.then(svr => {})
.catch(error => {
expect(error.message).toBe("Please provide valide listener.endpoint");
expect(error.message).toBe("Please provide a valid listener endpoint.");
});
});

Expand All @@ -176,7 +176,7 @@ describe("Test start method with invalid user config", async () => {
start(config)
.then(svr => {})
.catch(error => {
expect(error.message).toBe("Please provide valide listener.port");
expect(error.message).toBe("Please provide a valid listener port.");
});
});
});
Expand Down Expand Up @@ -223,7 +223,7 @@ describe("Test start method with user config", () => {
.then(response => {
expect(response.statusCode).toBe(400);
expect(response.body.error.message).toBe(
"Only POST call is supported.",
"Only POST requests are supported.",
);
});
});
Expand Down
Loading