Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
42 commits
Select commit Hold shift + click to select a range
9a9b756
Added logs for debugging
kreloaded Feb 13, 2024
b375848
Bug fix
kreloaded Feb 13, 2024
6d2a2f0
Json stringified
kreloaded Feb 13, 2024
33cf001
Added logs for debugging
kreloaded Feb 13, 2024
fddbafb
Fixed common middlewares signature validation
kreloaded Feb 13, 2024
2bd909d
FIxed req param
kreloaded Feb 13, 2024
42b4e2f
Param fixes
kreloaded Feb 13, 2024
dccbac7
Param fixes
kreloaded Feb 13, 2024
9a185bd
Added logs for debugging
kreloaded Feb 13, 2024
70ac774
Added logs for debugging
kreloaded Feb 13, 2024
1e8fa3c
Added encoding to sig validation
kreloaded Feb 13, 2024
b4c7433
Added logs for debugging
kreloaded Feb 13, 2024
f0fb4fe
Api app id fix
kreloaded Feb 13, 2024
4960426
Added logs for debugging
kreloaded Feb 13, 2024
9eef333
Added logs for debugging
kreloaded Feb 14, 2024
898b828
Fix
kreloaded Feb 14, 2024
d249c3d
Fix
kreloaded Feb 14, 2024
c4d9520
Added logs for debugging
kreloaded Feb 14, 2024
00a5d91
Added logs for debugging
kreloaded Feb 14, 2024
458de71
Added logs for debugging
kreloaded Feb 14, 2024
5c2b4de
Parsed payload
kreloaded Feb 14, 2024
59f75cd
Parsed payload
kreloaded Feb 14, 2024
9362203
Added logs for debugging
kreloaded Feb 14, 2024
7fd82a9
Removed logs added for debugging
kreloaded Feb 14, 2024
a54c8d1
Added date picker and static select to modal
kreloaded Feb 15, 2024
496ad4d
Fix
kreloaded Feb 15, 2024
eaebd31
Fix
kreloaded Feb 15, 2024
f681dc0
Added default value
kreloaded Feb 15, 2024
edc09bc
Stringified payload
kreloaded Feb 16, 2024
84fdb46
Date picker type changed to input from section
kreloaded Feb 16, 2024
dbb223b
Updated datepicker modal
kreloaded Feb 16, 2024
698a9bc
Removed block id from datepicker
kreloaded Feb 16, 2024
149abd3
Added datepicker value
kreloaded Feb 16, 2024
07b3fcd
Static select to use input
kreloaded Feb 16, 2024
f6b593e
Added static select to parse view params
kreloaded Feb 16, 2024
3b58a5e
Added logs for debugging
kreloaded Feb 16, 2024
090d487
Switch case fix
kreloaded Feb 16, 2024
3d52d60
Switch case fix
kreloaded Feb 16, 2024
6084777
Removed logs added for debugging
kreloaded Feb 16, 2024
f213ac8
Do not replace original message
kreloaded Feb 16, 2024
d166e98
Replace original moved to param
kreloaded Feb 16, 2024
eccc4f3
Removed logs added for debugging
kreloaded Feb 16, 2024
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
11 changes: 9 additions & 2 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -51,15 +51,21 @@ class SlackAdmin {

return async function(req, res, next) {
try {
const response = await oThis.validators.common(req.body, req.query, req.headers, req.method);
const response = await oThis.validators.common(
req.body,
req.rawBody,
req.query,
req.headers,
req.method
);

req.body = response.requestBody;
req.query = response.requestQuery;
req.internalDecodedParams = response.internalDecodedParams;
req.decodedParams = response.decodedParams;
next();
} catch (errorMessage) {
console.error('Common middleaware error:', errorMessage);
console.error('Common middleware error:', errorMessage);
return res.status(200).json('Something went wrong.');
}
};
Expand Down Expand Up @@ -89,6 +95,7 @@ class SlackAdmin {

next();
} catch (err) {
console.log('Error in interactive endpoint middleware:', err);
console.error('Interactive endpoint middleware error:', JSON.stringify(err));
return res.status(200).json('something_went_wrong');
}
Expand Down
5 changes: 4 additions & 1 deletion lib/helpers/messageHelper.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ class SlackHelper {
* @param {string} params.text
* @param {array} [params.blocks]
* @param {string} params.responseUrl
* @param {boolean} [params.replaceOriginal]
*
* @returns {Promise<never>}
*/
Expand All @@ -28,6 +29,7 @@ class SlackHelper {
const text = params.text;
const responseUrl = params.responseUrl;
const blocks = params.blocks || [];
const replaceOriginal = params.replaceOriginal || false;

if (!responseUrl) {
return Promise.reject(
Expand All @@ -44,7 +46,8 @@ class SlackHelper {
const messageObject = {
response_type: responseType,
text: text || '',
blocks: blocks
blocks: blocks,
replace_original: replaceOriginal
};

const httpLibObj = new HttpLibrary({ resource: responseUrl, noFormattingRequired: true });
Expand Down
31 changes: 24 additions & 7 deletions lib/middlewareMethods/Common.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,30 +16,47 @@ class CommonMiddlewares {
* @param requestMethod
* @returns {{requestQuery: *, internalDecodedParams: {}, decodedParams: (*|{}), requestBody: *}}
*/
async CommonMiddleWareMethod(requestBody, requestQuery, requestHeaders, requestMethod) {
async CommonMiddleWareMethod(
requestBody,
requestRawBody,
requestQuery,
requestHeaders,
requestMethod
) {
let internalDecodedParams = {},
decodedParams = {};

const requestRawBody = AssignRawBodyMiddleware.assignRawBody(requestBody);
// 1. Validate slack signature
await authenticator.validateSlackSignature(requestBody, requestRawBody, requestHeaders);

// 2. Payload formatting
const formattedPayload = PayloadFormatterMiddleware.formatPayload(requestBody);
requestBody.payload = formattedPayload;

const sanitisedResponse = sanitizer.sanitizeBodyAndQuery(requestBody, requestQuery);
requestBody = sanitisedResponse.requestBody;
requestQuery = sanitisedResponse.requestQuery;
// 3. Sanitize body and query
const sanitizedResponse = sanitizer.sanitizeBodyAndQuery(requestBody, requestQuery);
requestBody = sanitizedResponse.requestBody;
requestQuery = sanitizedResponse.requestQuery;

// 4. Assign request params
decodedParams = AssignParamsMiddleware.assignParams(requestMethod, requestBody, requestQuery);

// 5. Extract slack params
const slackParamsResponse = ExtractSlackParamsMiddleware.extractSlackParams(requestBody, internalDecodedParams);
requestBody = slackParamsResponse.requestBody;
internalDecodedParams = slackParamsResponse.internalDecodedParams;

// 6. Validate raw body params
await authenticator.validateRawBodyParams(requestRawBody);

// 7. Validate request headers
await authenticator.validateRequestHeaders(requestHeaders);

// 8. Validate request domain
await authenticator.validateRequestDomain(requestBody);
await authenticator.validateSlackSignature(requestRawBody, requestHeaders, requestBody);
await authenticator.validateSlackUser(requestRawBody, requestHeaders, requestBody);

// 9. Validate slack user
await authenticator.validateSlackUser(requestBody);

return { decodedParams, internalDecodedParams, requestBody, requestQuery };
}
Expand Down
90 changes: 90 additions & 0 deletions lib/slack/Modal.js
Original file line number Diff line number Diff line change
Expand Up @@ -158,6 +158,96 @@ class Modal {
oThis.viewJSON.blocks.push(textboxJSON);
}

/**
* Add date picker element to modal.
*
* @param {string} labelText
* @param {string} [initialDate]
* @param {string} [placeHolderText]
*/
addDatePicker(labelText, initialDate = '1990-04-28', placeHolderText = 'Select a date') {
const oThis = this;

const datePickerJson = {
type: 'input',
element: {
type: 'datepicker',
initial_date: initialDate,
placeholder: {
type: 'plain_text',
text: placeHolderText,
emoji: true
}
},
label: {
type: 'plain_text',
text: labelText,
emoji: true
}
};

oThis.viewJSON.blocks.push(datePickerJson);
}

/**
* Add static select to modal.
*
* @param {string} labelText
* @param {string} optionsArray
* @param {string} defaultOption
* @param {string} placeholderText
*/
addStaticSelect(labelText, optionsArray = [], defaultOption = {}, placeholderText = 'Select an item') {
const oThis = this;

const staticSelectJson = {
type: 'input',
element: {
type: 'static_select',
placeholder: {
type: 'plain_text',
text: placeholderText,
emoji: true
},
options: []
},
label: {
type: 'plain_text',
text: labelText,
emoji: true
}
};

for (let index = 0; index < optionsArray.length; index++) {
const currOption = optionsArray[index];

staticSelectJson.element.options.push({
text: {
type: 'plain_text',
text: currOption.text,
emoji: true
},
value: currOption.value
});
}

if (optionsArray.length === 0) {
if (!CommonValidators.validateNonEmptyObject(defaultOption)) {
defaultOption = {
text: {
type: 'plain_text',
text: 'this is plain_text text',
emoji: true
},
value: 'default-value'
}
}
staticSelectJson.element.options.push(defaultOption);
}

oThis.viewJSON.blocks.push(staticSelectJson);
}

/**
* Add check boxes to modal.
*
Expand Down
8 changes: 8 additions & 0 deletions lib/slack/ParseViewActionsApiParams.js
Original file line number Diff line number Diff line change
Expand Up @@ -175,6 +175,14 @@ class ParseBlockActionsApiParams {
oThis.finalResponse.apiParams[relevantParameter] = stateObject.selected_option.value;
break;
}
case 'datepicker': {
oThis.finalResponse.apiParams[relevantParameter] = stateObject.selected_date;
break;
}
case 'static_select': {
oThis.finalResponse.apiParams[relevantParameter] = stateObject.selected_option.value;
break;
}
default:
// Do nothing;
}
Expand Down
2 changes: 2 additions & 0 deletions middlewares/assignRawBody.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,9 @@ class AssignRawBody {
*/
assignRawBody(requestBody) {
const oThis = this;

const requestRawBody = qs.stringify(requestBody).replace(/%20/g, '+');

return requestRawBody;
}
}
Expand Down
20 changes: 8 additions & 12 deletions middlewares/authentication/Authenticator.js
Original file line number Diff line number Diff line change
Expand Up @@ -55,17 +55,15 @@ class Authenticator {
/**
* Function to validate slack signature.
*
* @param {object} requestRawBody
* @param {object} requestHeaders
* @param {object} requestBody
* @param {object} req
* @returns {Promise<void>}
*/
async validateSlackSignature(requestRawBody, requestHeaders, requestBody) {
const authResponse = await new ValidateSlackSignature({
rawBody: requestRawBody,
requestHeaders: requestHeaders,
slackRequestParams: requestBody
}).perform();
async validateSlackSignature(requestBody, requestRawBody, requestHeaders) {
const authResponse = await new ValidateSlackSignature({
requestBody: requestBody,
requestRawBody: requestRawBody,
requestHeaders: requestHeaders
}).perform();

if (authResponse.isFailure()) {
throw new Error('Invalid Slack Signature');
Expand All @@ -80,10 +78,8 @@ class Authenticator {
* @param {object} requestBody
* @returns {Promise<void>}
*/
async validateSlackUser(requestRawBody, requestHeaders, requestBody) {
async validateSlackUser(requestBody) {
const authResponse = await new ValidateSlackUser({
rawBody: requestRawBody,
requestHeaders: requestHeaders,
slackRequestParams: requestBody
}).perform();

Expand Down
2 changes: 1 addition & 1 deletion middlewares/authentication/RawBodyParams.js
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ class ValidateRawBodyParams {
const oThis = this;

if (!CommonValidators.validateString(oThis.rawBody)) {
console.error(`Slack authentication failed. Invalid raw Body Input ${oThis.rawBody}`);
console.error(`Slack authentication failed. Invalid raw Body Input ${JSON.stringify(oThis.rawBody)}`);
return responseHelper.error({
internal_error_identifier: 'm_a_rbp_p',
api_error_identifier: 'unauthorized_api_request',
Expand Down
25 changes: 14 additions & 11 deletions middlewares/authentication/Signature.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,16 @@ class ValidateSlackSignature {
constructor(params) {
const oThis = this;

oThis.rawBody = params.rawBody;
const requestBody = params.requestBody;
oThis.requestRawBody = params.requestRawBody;
oThis.requestHeaders = params.requestHeaders;
oThis.slackRequestParams = params.slackRequestParams;

oThis.requestPayload = oThis.slackRequestParams.payload || null;
if (requestBody.payload) {
const parsedPayload = JSON.parse(requestBody.payload);
oThis.apiAppId = parsedPayload.api_app_id;
} else {
oThis.apiAppId = requestBody.api_app_id;
}
}

/**
Expand Down Expand Up @@ -61,9 +66,8 @@ class ValidateSlackSignature {
internal_error_identifier: 'm_a_s_p',
api_error_identifier: 'unauthorized_api_request',
debug_options: {
body: oThis.rawBody,
rawBody: oThis.requestRawBody,
headers: oThis.requestHeaders,
slackRequestParams: oThis.slackRequestParams
}
});
}
Expand All @@ -88,14 +92,13 @@ class ValidateSlackSignature {
async _validateSignature(requestTimestamp, version, signature) {
const oThis = this;

const appId = oThis.slackRequestParams.api_app_id;
const signingSecret = slackAppConstants.getSigningSecretForAppId(appId);
const signingSecret = slackAppConstants.getSigningSecretForAppId(oThis.apiAppId);

const signatureString = `${version}:${requestTimestamp}:${oThis.rawBody}`;
const signatureString = `${version}:${requestTimestamp}:${oThis.requestRawBody}`;
const computedSignature = crypto
.createHmac('sha256', signingSecret)
.update(signatureString)
.digest('hex');
.createHmac('sha256', signingSecret)
.update(signatureString, 'utf8')
.digest('hex');

if (!crypto.timingSafeEqual(Buffer.from(signature, 'utf-8'), Buffer.from(computedSignature, 'utf-8'))) {
console.error(`Invalid signature :: ${signature}`);
Expand Down