Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

@liveblocks/node

Package Overview
Dependencies
Maintainers
6
Versions
337
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@liveblocks/node - npm Package Compare versions

Comparing version 0.19.9-beta3 to 0.19.9-beta4

102

dist/index.d.ts

@@ -0,1 +1,101 @@

import { IncomingHttpHeaders } from 'http';
declare class WebhookHandler {
private secretBuffer;
private static secretPrefix;
constructor(
/**
* The signing secret provided on the dashboard's webhooks page
* @example "whsec_wPbvQ+u3VtN2e2tRPDKchQ1tBZ3svaHLm"
*/
secret: string);
/**
* Verifies a webhook request and returns the event
*/
verifyRequest(request: WebhookRequest): WebhookEvent;
/**
* Verifies the headers and returns the webhookId, timestamp and rawSignatures
*/
private verifyHeaders;
/**
* Signs the content with the secret
* @param content
* @returns `string`
*/
private sign;
/**
* Verifies that the timestamp is not too old or in the future
*/
private verifyTimestamp;
/**
* Ensures that the event is a known event type
* or throws and prompts the user to upgrade to a higher version of @liveblocks/node
*/
private verifyWebhookEventType;
}
declare type WebhookRequest = {
/**
* Headers of the request
* @example
* {
* "webhook-id": "123",
* "webhook-timestamp": "1614588800000",
* "webhook-signature": "v1,bm9ldHUjKzFob2VudXRob2VodWUzMjRvdWVvdW9ldQo= v2,MzJsNDk4MzI0K2VvdSMjMTEjQEBAQDEyMzMzMzEyMwo="
* }
*/
headers: IncomingHttpHeaders;
/**
* Raw body of the request, do not parse it
* @example '{"type":"storageUpdated","data":{"roomId":"my-room-id","appId":"my-app-id","updatedAt":"2021-03-01T12:00:00.000Z"}}'
*/
rawBody: string;
};
declare type WebhookEvent = StorageUpdatedEvent | UserEnteredEvent | UserLeftEvent;
declare type StorageUpdatedEvent = {
type: "storageUpdated";
data: {
roomId: string;
appId: string;
/**
* ISO 8601 datestring
* @example "2021-03-01T12:00:00.000Z"
*/
updatedAt: string;
};
};
declare type UserEnteredEvent = {
type: "userEntered";
data: {
appId: string;
roomId: string;
connectionId: number;
userId: string | null;
userInfo: Record<string, unknown> | null;
/**
* ISO 8601 datestring
* @example "2021-03-01T12:00:00.000Z"
* @description The time when the user entered the room.
*/
enteredAt: string;
numActiveUsers: number;
};
};
declare type UserLeftEvent = {
type: "userLeft";
data: {
appId: string;
roomId: string;
connectionId: number;
userId: string | null;
userInfo: Record<string, unknown> | null;
/**
* ISO 8601 datestring
* @example "2021-03-01T12:00:00.000Z"
* @description The time when the user left the room.
*/
leftAt: string;
numActiveUsers: number;
};
};
declare type AuthorizeOptions = {

@@ -50,2 +150,2 @@ /**

export { authorize };
export { StorageUpdatedEvent, UserEnteredEvent, UserLeftEvent, WebhookEvent, WebhookHandler, WebhookRequest, authorize };

@@ -24,2 +24,80 @@ "use strict";Object.defineProperty(exports, "__esModule", {value: true}); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }var __async = (__this, __arguments, generator) => {

var _nodefetch = require('node-fetch'); var _nodefetch2 = _interopRequireDefault(_nodefetch);
// src/webhooks.ts
var _crypto = require('crypto'); var _crypto2 = _interopRequireDefault(_crypto);
var _WebhookHandler = class {
constructor(secret) {
if (!secret)
throw new Error("Secret is required");
if (typeof secret !== "string")
throw new Error("Secret must be a string");
if (secret.startsWith(_WebhookHandler.secretPrefix) === false)
throw new Error("Invalid secret, must start with whsec_");
const secretKey = secret.slice(_WebhookHandler.secretPrefix.length);
this.secretBuffer = Buffer.from(secretKey, "base64");
}
verifyRequest(request) {
const { webhookId, timestamp, rawSignatures } = this.verifyHeaders(
request.headers
);
this.verifyTimestamp(timestamp);
const signature = this.sign(`${webhookId}.${timestamp}.${request.rawBody}`);
const expectedSignatures = rawSignatures.split(" ").map((rawSignature) => {
const [, parsedSignature] = rawSignature.split(",");
return parsedSignature;
}).filter(isNotUndefined);
if (expectedSignatures.includes(signature) === false)
throw new Error(
`Invalid signature, expected one of ${expectedSignatures}, got ${signature}`
);
const event = JSON.parse(request.rawBody);
this.verifyWebhookEventType(event);
return event;
}
verifyHeaders(headers) {
const sanitizedHeaders = {};
Object.keys(headers).forEach((key) => {
sanitizedHeaders[key.toLowerCase()] = headers[key];
});
const webhookId = sanitizedHeaders["webhook-id"];
if (typeof webhookId !== "string")
throw new Error("Invalid webhook-id header");
const timestamp = sanitizedHeaders["webhook-timestamp"];
if (typeof timestamp !== "string")
throw new Error("Invalid webhook-timestamp header");
const rawSignatures = sanitizedHeaders["webhook-signature"];
if (typeof rawSignatures !== "string")
throw new Error("Invalid webhook-signature header");
return { webhookId, timestamp, rawSignatures };
}
sign(content) {
return _crypto2.default.createHmac("sha256", this.secretBuffer).update(content).digest("base64");
}
verifyTimestamp(timestampHeader) {
const now = Math.floor(Date.now() / 1e3);
const timestamp = parseInt(timestampHeader, 10);
if (isNaN(timestamp)) {
throw new Error("Invalid timestamp");
}
if (timestamp < now - WEBHOOK_TOLERANCE_IN_SECONDS) {
throw new Error("Timestamp too old");
}
if (timestamp > now + WEBHOOK_TOLERANCE_IN_SECONDS) {
throw new Error("Timestamp in the future");
}
}
verifyWebhookEventType(event) {
if (event && event.type && (event.type === "storageUpdated" || event.type === "userEntered" || event.type === "userLeft"))
return;
throw new Error(
"Unknown event type, please upgrade to a higher version of @liveblocks/node"
);
}
};
var WebhookHandler = _WebhookHandler;
WebhookHandler.secretPrefix = "whsec_";
var WEBHOOK_TOLERANCE_IN_SECONDS = 5 * 60;
var isNotUndefined = (value) => value !== void 0;
// src/index.ts
function authorize(options) {

@@ -78,2 +156,3 @@ return __async(this, null, function* () {

exports.authorize = authorize;
exports.WebhookHandler = WebhookHandler; exports.authorize = authorize;

5

package.json
{
"name": "@liveblocks/node",
"version": "0.19.9-beta3",
"version": "0.19.9-beta4",
"description": "A server-side utility that lets you set up a Liveblocks authentication endpoint. Liveblocks is the all-in-one toolkit to build collaborative products like Figma, Notion, and more.",

@@ -23,3 +23,4 @@ "license": "Apache-2.0",

"@liveblocks/jest-config": "*",
"@types/node-fetch": "^2.5.8"
"@types/node-fetch": "^2.5.8",
"svix": "^0.75.0"
},

@@ -26,0 +27,0 @@ "dependencies": {

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc