@cord-sdk/server
Advanced tools
Comparing version 1.38.0 to 1.38.1-canary.0
@@ -85,22 +85,31 @@ 'use strict'; | ||
* Will validate the signature of the webhook request to ensure the source of | ||
* the request is Cord, and can be trusted. Will throw an exception if there | ||
* are any problems with the request validation. | ||
* @param requestPayload The raw request payload. The object must have a header | ||
* function that will fetch header properties for the request, and a body | ||
* property that is the raw payload from the webhook request. See the node express | ||
* request format for a compatible implementation. Note the body must be | ||
* the data from the raw request request payload, without performing JSON deserialization. | ||
* the request is Cord and can be trusted. Will throw an exception if there are | ||
* any problems with the request validation. | ||
* @param body The raw request body. This must be exactly the bytes sent in the | ||
* body of the request, without JSON deserialization or any other modification. | ||
* For example, use the `raw` middleware from the `body-parser` library for | ||
* Express or the `request.text()` function in NextJS. | ||
* @param cordTimestamp The contents of the `X-Cord-Timestamp` header from the | ||
* request. | ||
* @param cordSignature The contents of the `X-Cord-Signature` header from the | ||
* request. | ||
* @param projectSecret The project secret. This is used to validate the | ||
* request body using the cord signature proof. Details can be found here: | ||
* request body using the Cord signature proof. Details can be found here: | ||
* https://docs.cord.com/reference/events-webhook | ||
* @param options Options to customize how the validity checking is done. By | ||
* default, the maximum accepted age is 5 minutes. | ||
*/ | ||
function validateWebhookSignature(requestPayload, projectSecret) { | ||
const cordTimestamp = Number(requestPayload.header('X-Cord-Timestamp')); | ||
const cordSignature = requestPayload.header('X-Cord-Signature'); | ||
if (Number.isNaN(cordTimestamp) || | ||
Math.abs(Date.now() - cordTimestamp) > 1000 * 60 * 5) { | ||
throw new Error('Notification timestamp invalid or too old.'); | ||
function validateWebhookSignature(body, cordTimestamp, cordSignature, projectSecret, options = {}) { | ||
if (!cordSignature) { | ||
throw new Error('Webhook signature is missing'); | ||
} | ||
const bodyString = JSON.stringify(requestPayload.body); | ||
const verifyStr = cordTimestamp + ':' + bodyString; | ||
if (!cordTimestamp) { | ||
throw new Error('Webhook signature timestamp is missing'); | ||
} | ||
const acceptAgeSeconds = options.acceptAgeSeconds ?? 60 * 5; | ||
if (Number.isNaN(Number(cordTimestamp)) || | ||
Math.abs(Date.now() - Number(cordTimestamp)) > 1000 * acceptAgeSeconds) { | ||
throw new Error('Webhook signature timestamp invalid or too old.'); | ||
} | ||
const verifyStr = cordTimestamp + ':' + body; | ||
const hmac = crypto.createHmac('sha256', projectSecret); | ||
@@ -110,3 +119,3 @@ hmac.update(verifyStr); | ||
if (cordSignature !== incomingSignature) { | ||
throw new Error('Unable to verify signature'); | ||
throw new Error('Unable to verify webhook signature'); | ||
} | ||
@@ -116,9 +125,12 @@ } | ||
* Will validate the signature of the webhook request to ensure the source of | ||
* the request is Cord, and can be trusted. Will return false if there | ||
* are any problems with the request validation. | ||
* @param requestPayload The raw request payload. The object must have a header | ||
* function that will fetch header properties for the request, and a body | ||
* property that is the raw payload from the webhook request. See the node express | ||
* request format for a compatible implementation. Note the body must be | ||
* the data from the raw request request payload, without performing JSON deserialization. | ||
* the request is Cord, and can be trusted. Will return false if there are any | ||
* problems with the request validation. | ||
* @param body The raw request body. This must be exactly the bytes sent in the | ||
* body of the request, without JSON deserialization or any other modification. | ||
* For example, use the `raw` middleware from the `body-parser` library for | ||
* Express or the `request.text()` function in NextJS. | ||
* @param cordTimestamp The contents of the `X-Cord-Timestamp` header from the | ||
* request. | ||
* @param cordSignature The contents of the `X-Cord-Signature` header from the | ||
* request. | ||
* @param projectSecret The project secret. This is used to validate the | ||
@@ -128,5 +140,5 @@ * request body using the cord signature proof. Details can be found here: | ||
*/ | ||
function tryValidateWebhookSignature(requestPayload, clientSecret) { | ||
function tryValidateWebhookSignature(body, timestamp, signature, clientSecret) { | ||
try { | ||
validateWebhookSignature(requestPayload, clientSecret); | ||
validateWebhookSignature(body, timestamp, signature, clientSecret); | ||
} | ||
@@ -139,19 +151,22 @@ catch (e) { | ||
/** | ||
* Takes a request payload, and returns a typed object for handling | ||
* Cord webhook notifications. | ||
* @param requestPayload Request payload from a webhook request. Should have | ||
* a similar structure to express style request object. | ||
* @returns A typed object to support handling webhook events. See: | ||
* Takes a raw request body, and returns a typed object for handling | ||
* Cord webhook events. | ||
* @param body The raw request body. This must be exactly the bytes sent in the | ||
* body of the request, without JSON deserialization or any other modification. | ||
* For example, use the `raw` middleware from the `body-parser` library for | ||
* Express or the `request.text()` function in NextJS. | ||
* @returns A typed object to support handling webhook events. See: | ||
* https://docs.cord.com/reference/events-webhook | ||
*/ | ||
function parseEventPayload(requestPayload) { | ||
switch (requestPayload.body.type) { | ||
function parseWebhookBody(body) { | ||
const payload = JSON.parse(body); | ||
switch (payload.type) { | ||
case 'thread-message-added': | ||
return requestPayload.body; | ||
return payload; | ||
case 'notification-created': | ||
return requestPayload.body; | ||
return payload; | ||
case 'url-verification': | ||
return requestPayload.body; | ||
return payload; | ||
default: | ||
throw 'unknown webhook request type.'; | ||
throw new Error('Unknown webhook request type.'); | ||
} | ||
@@ -165,4 +180,4 @@ } | ||
exports.getServerAuthToken = getServerAuthToken; | ||
exports.parseEventPayload = parseEventPayload; | ||
exports.parseWebhookBody = parseWebhookBody; | ||
exports.tryValidateWebhookSignature = tryValidateWebhookSignature; | ||
exports.validateWebhookSignature = validateWebhookSignature; |
@@ -61,22 +61,31 @@ import * as jwt from 'jsonwebtoken'; | ||
* Will validate the signature of the webhook request to ensure the source of | ||
* the request is Cord, and can be trusted. Will throw an exception if there | ||
* are any problems with the request validation. | ||
* @param requestPayload The raw request payload. The object must have a header | ||
* function that will fetch header properties for the request, and a body | ||
* property that is the raw payload from the webhook request. See the node express | ||
* request format for a compatible implementation. Note the body must be | ||
* the data from the raw request request payload, without performing JSON deserialization. | ||
* the request is Cord and can be trusted. Will throw an exception if there are | ||
* any problems with the request validation. | ||
* @param body The raw request body. This must be exactly the bytes sent in the | ||
* body of the request, without JSON deserialization or any other modification. | ||
* For example, use the `raw` middleware from the `body-parser` library for | ||
* Express or the `request.text()` function in NextJS. | ||
* @param cordTimestamp The contents of the `X-Cord-Timestamp` header from the | ||
* request. | ||
* @param cordSignature The contents of the `X-Cord-Signature` header from the | ||
* request. | ||
* @param projectSecret The project secret. This is used to validate the | ||
* request body using the cord signature proof. Details can be found here: | ||
* request body using the Cord signature proof. Details can be found here: | ||
* https://docs.cord.com/reference/events-webhook | ||
* @param options Options to customize how the validity checking is done. By | ||
* default, the maximum accepted age is 5 minutes. | ||
*/ | ||
function validateWebhookSignature(requestPayload, projectSecret) { | ||
const cordTimestamp = Number(requestPayload.header('X-Cord-Timestamp')); | ||
const cordSignature = requestPayload.header('X-Cord-Signature'); | ||
if (Number.isNaN(cordTimestamp) || | ||
Math.abs(Date.now() - cordTimestamp) > 1000 * 60 * 5) { | ||
throw new Error('Notification timestamp invalid or too old.'); | ||
function validateWebhookSignature(body, cordTimestamp, cordSignature, projectSecret, options = {}) { | ||
if (!cordSignature) { | ||
throw new Error('Webhook signature is missing'); | ||
} | ||
const bodyString = JSON.stringify(requestPayload.body); | ||
const verifyStr = cordTimestamp + ':' + bodyString; | ||
if (!cordTimestamp) { | ||
throw new Error('Webhook signature timestamp is missing'); | ||
} | ||
const acceptAgeSeconds = options.acceptAgeSeconds ?? 60 * 5; | ||
if (Number.isNaN(Number(cordTimestamp)) || | ||
Math.abs(Date.now() - Number(cordTimestamp)) > 1000 * acceptAgeSeconds) { | ||
throw new Error('Webhook signature timestamp invalid or too old.'); | ||
} | ||
const verifyStr = cordTimestamp + ':' + body; | ||
const hmac = createHmac('sha256', projectSecret); | ||
@@ -86,3 +95,3 @@ hmac.update(verifyStr); | ||
if (cordSignature !== incomingSignature) { | ||
throw new Error('Unable to verify signature'); | ||
throw new Error('Unable to verify webhook signature'); | ||
} | ||
@@ -92,9 +101,12 @@ } | ||
* Will validate the signature of the webhook request to ensure the source of | ||
* the request is Cord, and can be trusted. Will return false if there | ||
* are any problems with the request validation. | ||
* @param requestPayload The raw request payload. The object must have a header | ||
* function that will fetch header properties for the request, and a body | ||
* property that is the raw payload from the webhook request. See the node express | ||
* request format for a compatible implementation. Note the body must be | ||
* the data from the raw request request payload, without performing JSON deserialization. | ||
* the request is Cord, and can be trusted. Will return false if there are any | ||
* problems with the request validation. | ||
* @param body The raw request body. This must be exactly the bytes sent in the | ||
* body of the request, without JSON deserialization or any other modification. | ||
* For example, use the `raw` middleware from the `body-parser` library for | ||
* Express or the `request.text()` function in NextJS. | ||
* @param cordTimestamp The contents of the `X-Cord-Timestamp` header from the | ||
* request. | ||
* @param cordSignature The contents of the `X-Cord-Signature` header from the | ||
* request. | ||
* @param projectSecret The project secret. This is used to validate the | ||
@@ -104,5 +116,5 @@ * request body using the cord signature proof. Details can be found here: | ||
*/ | ||
function tryValidateWebhookSignature(requestPayload, clientSecret) { | ||
function tryValidateWebhookSignature(body, timestamp, signature, clientSecret) { | ||
try { | ||
validateWebhookSignature(requestPayload, clientSecret); | ||
validateWebhookSignature(body, timestamp, signature, clientSecret); | ||
} | ||
@@ -115,22 +127,25 @@ catch (e) { | ||
/** | ||
* Takes a request payload, and returns a typed object for handling | ||
* Cord webhook notifications. | ||
* @param requestPayload Request payload from a webhook request. Should have | ||
* a similar structure to express style request object. | ||
* @returns A typed object to support handling webhook events. See: | ||
* Takes a raw request body, and returns a typed object for handling | ||
* Cord webhook events. | ||
* @param body The raw request body. This must be exactly the bytes sent in the | ||
* body of the request, without JSON deserialization or any other modification. | ||
* For example, use the `raw` middleware from the `body-parser` library for | ||
* Express or the `request.text()` function in NextJS. | ||
* @returns A typed object to support handling webhook events. See: | ||
* https://docs.cord.com/reference/events-webhook | ||
*/ | ||
function parseEventPayload(requestPayload) { | ||
switch (requestPayload.body.type) { | ||
function parseWebhookBody(body) { | ||
const payload = JSON.parse(body); | ||
switch (payload.type) { | ||
case 'thread-message-added': | ||
return requestPayload.body; | ||
return payload; | ||
case 'notification-created': | ||
return requestPayload.body; | ||
return payload; | ||
case 'url-verification': | ||
return requestPayload.body; | ||
return payload; | ||
default: | ||
throw 'unknown webhook request type.'; | ||
throw new Error('Unknown webhook request type.'); | ||
} | ||
} | ||
export { fetchCordRESTApi, getApplicationManagementAuthToken, getClientAuthToken, getProjectManagementAuthToken, getServerAuthToken, parseEventPayload, tryValidateWebhookSignature, validateWebhookSignature }; | ||
export { fetchCordRESTApi, getApplicationManagementAuthToken, getClientAuthToken, getProjectManagementAuthToken, getServerAuthToken, parseWebhookBody, tryValidateWebhookSignature, validateWebhookSignature }; |
@@ -1,32 +0,40 @@ | ||
import type { ThreadMessageAddedWebhookPayload, NotificationCreatedWebhookPayload, URLVerificationWebhookPayload } from '@cord-sdk/types'; | ||
export type WebhookPayload = ThreadMessageAddedWebhookPayload | NotificationCreatedWebhookPayload | URLVerificationWebhookPayload; | ||
export type WebhookRequest = { | ||
header(name: string): string; | ||
body: { | ||
type: string; | ||
}; | ||
import type { WebhookWrapperProperties, WebhookTypes } from '@cord-sdk/types'; | ||
type ValidateWebhookOptions = { | ||
/** | ||
* The maximum age of a webhook request (as determined by the timestamp | ||
* encoded in it) to accept. By default, this is set to 5 minutes. | ||
*/ | ||
acceptAgeSeconds?: number; | ||
}; | ||
/** | ||
* Will validate the signature of the webhook request to ensure the source of | ||
* the request is Cord, and can be trusted. Will throw an exception if there | ||
* are any problems with the request validation. | ||
* @param requestPayload The raw request payload. The object must have a header | ||
* function that will fetch header properties for the request, and a body | ||
* property that is the raw payload from the webhook request. See the node express | ||
* request format for a compatible implementation. Note the body must be | ||
* the data from the raw request request payload, without performing JSON deserialization. | ||
* the request is Cord and can be trusted. Will throw an exception if there are | ||
* any problems with the request validation. | ||
* @param body The raw request body. This must be exactly the bytes sent in the | ||
* body of the request, without JSON deserialization or any other modification. | ||
* For example, use the `raw` middleware from the `body-parser` library for | ||
* Express or the `request.text()` function in NextJS. | ||
* @param cordTimestamp The contents of the `X-Cord-Timestamp` header from the | ||
* request. | ||
* @param cordSignature The contents of the `X-Cord-Signature` header from the | ||
* request. | ||
* @param projectSecret The project secret. This is used to validate the | ||
* request body using the cord signature proof. Details can be found here: | ||
* request body using the Cord signature proof. Details can be found here: | ||
* https://docs.cord.com/reference/events-webhook | ||
* @param options Options to customize how the validity checking is done. By | ||
* default, the maximum accepted age is 5 minutes. | ||
*/ | ||
export declare function validateWebhookSignature(requestPayload: WebhookRequest, projectSecret: string): void; | ||
export declare function validateWebhookSignature(body: string, cordTimestamp: string | null | undefined, cordSignature: string | null | undefined, projectSecret: string, options?: ValidateWebhookOptions): void; | ||
/** | ||
* Will validate the signature of the webhook request to ensure the source of | ||
* the request is Cord, and can be trusted. Will return false if there | ||
* are any problems with the request validation. | ||
* @param requestPayload The raw request payload. The object must have a header | ||
* function that will fetch header properties for the request, and a body | ||
* property that is the raw payload from the webhook request. See the node express | ||
* request format for a compatible implementation. Note the body must be | ||
* the data from the raw request request payload, without performing JSON deserialization. | ||
* the request is Cord, and can be trusted. Will return false if there are any | ||
* problems with the request validation. | ||
* @param body The raw request body. This must be exactly the bytes sent in the | ||
* body of the request, without JSON deserialization or any other modification. | ||
* For example, use the `raw` middleware from the `body-parser` library for | ||
* Express or the `request.text()` function in NextJS. | ||
* @param cordTimestamp The contents of the `X-Cord-Timestamp` header from the | ||
* request. | ||
* @param cordSignature The contents of the `X-Cord-Signature` header from the | ||
* request. | ||
* @param projectSecret The project secret. This is used to validate the | ||
@@ -36,11 +44,14 @@ * request body using the cord signature proof. Details can be found here: | ||
*/ | ||
export declare function tryValidateWebhookSignature(requestPayload: WebhookRequest, clientSecret: string): boolean; | ||
export declare function tryValidateWebhookSignature(body: string, timestamp: string | null | undefined, signature: string | null | undefined, clientSecret: string): boolean; | ||
/** | ||
* Takes a request payload, and returns a typed object for handling | ||
* Cord webhook notifications. | ||
* @param requestPayload Request payload from a webhook request. Should have | ||
* a similar structure to express style request object. | ||
* @returns A typed object to support handling webhook events. See: | ||
* Takes a raw request body, and returns a typed object for handling | ||
* Cord webhook events. | ||
* @param body The raw request body. This must be exactly the bytes sent in the | ||
* body of the request, without JSON deserialization or any other modification. | ||
* For example, use the `raw` middleware from the `body-parser` library for | ||
* Express or the `request.text()` function in NextJS. | ||
* @returns A typed object to support handling webhook events. See: | ||
* https://docs.cord.com/reference/events-webhook | ||
*/ | ||
export declare function parseEventPayload(requestPayload: WebhookRequest): WebhookPayload; | ||
export declare function parseWebhookBody<T extends WebhookTypes>(body: string): WebhookWrapperProperties<T>; | ||
export {}; |
{ | ||
"name": "@cord-sdk/server", | ||
"description": "Server-side portion of the Cord SDK", | ||
"version": "1.38.0", | ||
"version": "1.38.1-canary.0", | ||
"homepage": "https://docs.cord.com/", | ||
@@ -25,3 +25,3 @@ "license": "MIT", | ||
"devDependencies": { | ||
"@cord-sdk/types": "1.38.0", | ||
"@cord-sdk/types": "1.38.1-canary.0", | ||
"@types/jsonwebtoken": "^8.5.9", | ||
@@ -28,0 +28,0 @@ "typescript": "~5.1.6" |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
No v1
QualityPackage is not semver >=1. This means it is not stable and does not support ^ ranges.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
20967
394
2