@liveblocks/node 1.0.2-test5 → 1.0.6-test1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +3 -2
- package/dist/index.d.ts +50 -50
- package/dist/index.js +75 -59
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -32,8 +32,9 @@ npm install @liveblocks/node
|
|
|
32
32
|
|
|
33
33
|
## Documentation
|
|
34
34
|
|
|
35
|
-
Read the
|
|
36
|
-
|
|
35
|
+
Read the
|
|
36
|
+
[documentation](https://liveblocks.io/docs/api-reference/liveblocks-node) for
|
|
37
|
+
guides and API references.
|
|
37
38
|
|
|
38
39
|
## Examples
|
|
39
40
|
|
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,55 @@
|
|
|
1
1
|
import { IncomingHttpHeaders } from 'http';
|
|
2
2
|
|
|
3
|
+
declare type AuthorizeOptions = {
|
|
4
|
+
/**
|
|
5
|
+
* The secret api provided at https://liveblocks.io/dashboard/apikeys
|
|
6
|
+
*/
|
|
7
|
+
secret: string;
|
|
8
|
+
/**
|
|
9
|
+
* The room provided in the authorization request body
|
|
10
|
+
*/
|
|
11
|
+
room: string;
|
|
12
|
+
/**
|
|
13
|
+
* The id of the user that try to connect. It can be used to get information about the connected users in the room (name, avatar, etc).
|
|
14
|
+
* It can also be used to generate a token that gives access to a private room where the userId is configured in the room accesses.
|
|
15
|
+
* Liveblocks uses the userId to calculate your account's Monthly Active Users.
|
|
16
|
+
*/
|
|
17
|
+
userId: string;
|
|
18
|
+
/**
|
|
19
|
+
* The info associated to the user. Can be used to store the name or the profile picture to implement avatar for example. Can't exceed 1KB when serialized as JSON
|
|
20
|
+
*/
|
|
21
|
+
userInfo?: unknown;
|
|
22
|
+
/**
|
|
23
|
+
* The ids of the groups to which the user belongs. It should be used to generate a token that gives access to a private room and at least one of the group is configured in the room accesses.
|
|
24
|
+
*/
|
|
25
|
+
groupIds?: string[];
|
|
26
|
+
};
|
|
27
|
+
declare type AuthorizeResponse = {
|
|
28
|
+
status: number;
|
|
29
|
+
body: string;
|
|
30
|
+
error?: Error;
|
|
31
|
+
};
|
|
32
|
+
/**
|
|
33
|
+
* @example
|
|
34
|
+
* export default async function auth(req, res) {
|
|
35
|
+
*
|
|
36
|
+
* // Implement your own security here.
|
|
37
|
+
*
|
|
38
|
+
* const room = req.body.room;
|
|
39
|
+
* const response = await authorize({
|
|
40
|
+
* room,
|
|
41
|
+
* secret,
|
|
42
|
+
* userId: "123",
|
|
43
|
+
* userInfo: { // Optional
|
|
44
|
+
* name: "Ada Lovelace"
|
|
45
|
+
* },
|
|
46
|
+
* groupIds: ["group1"] // Optional
|
|
47
|
+
* });
|
|
48
|
+
* return res.status(response.status).end(response.body);
|
|
49
|
+
* }
|
|
50
|
+
*/
|
|
51
|
+
declare function authorize(options: AuthorizeOptions): Promise<AuthorizeResponse>;
|
|
52
|
+
|
|
3
53
|
declare class WebhookHandler {
|
|
4
54
|
private secretBuffer;
|
|
5
55
|
private static secretPrefix;
|
|
@@ -122,54 +172,4 @@ declare type RoomDeletedEvent = {
|
|
|
122
172
|
};
|
|
123
173
|
};
|
|
124
174
|
|
|
125
|
-
declare type AuthorizeOptions = {
|
|
126
|
-
/**
|
|
127
|
-
* The secret api provided at https://liveblocks.io/dashboard/apikeys
|
|
128
|
-
*/
|
|
129
|
-
secret: string;
|
|
130
|
-
/**
|
|
131
|
-
* The room provided in the authorization request body
|
|
132
|
-
*/
|
|
133
|
-
room: string;
|
|
134
|
-
/**
|
|
135
|
-
* The id of the user that try to connect. It can be used to get information about the connected users in the room (name, avatar, etc).
|
|
136
|
-
* It can also be used to generate a token that gives access to a private room where the userId is configured in the room accesses.
|
|
137
|
-
* Liveblocks uses the userId to calculate your account's Monthly Active Users.
|
|
138
|
-
*/
|
|
139
|
-
userId: string;
|
|
140
|
-
/**
|
|
141
|
-
* The info associated to the user. Can be used to store the name or the profile picture to implement avatar for example. Can't exceed 1KB when serialized as JSON
|
|
142
|
-
*/
|
|
143
|
-
userInfo?: unknown;
|
|
144
|
-
/**
|
|
145
|
-
* The ids of the groups to which the user belongs. It should be used to generate a token that gives access to a private room and at least one of the group is configured in the room accesses.
|
|
146
|
-
*/
|
|
147
|
-
groupIds?: string[];
|
|
148
|
-
};
|
|
149
|
-
declare type AuthorizeResponse = {
|
|
150
|
-
status: number;
|
|
151
|
-
body: string;
|
|
152
|
-
error?: Error;
|
|
153
|
-
};
|
|
154
|
-
/**
|
|
155
|
-
* @example
|
|
156
|
-
* export default async function auth(req, res) {
|
|
157
|
-
*
|
|
158
|
-
* // Implement your own security here.
|
|
159
|
-
*
|
|
160
|
-
* const room = req.body.room;
|
|
161
|
-
* const response = await authorize({
|
|
162
|
-
* room,
|
|
163
|
-
* secret,
|
|
164
|
-
* userId: "123",
|
|
165
|
-
* userInfo: { // Optional
|
|
166
|
-
* name: "Ada Lovelace"
|
|
167
|
-
* },
|
|
168
|
-
* groupIds: ["group1"] // Optional
|
|
169
|
-
* });
|
|
170
|
-
* return res.status(response.status).end(response.body);
|
|
171
|
-
* }
|
|
172
|
-
*/
|
|
173
|
-
declare function authorize(options: AuthorizeOptions): Promise<AuthorizeResponse>;
|
|
174
|
-
|
|
175
175
|
export { StorageUpdatedEvent, UserEnteredEvent, UserLeftEvent, WebhookEvent, WebhookHandler, WebhookRequest, authorize };
|
package/dist/index.js
CHANGED
|
@@ -19,8 +19,64 @@
|
|
|
19
19
|
});
|
|
20
20
|
};
|
|
21
21
|
|
|
22
|
-
// src/
|
|
22
|
+
// src/authorize.ts
|
|
23
23
|
var _nodefetch = require('node-fetch'); var _nodefetch2 = _interopRequireDefault(_nodefetch);
|
|
24
|
+
function authorize(options) {
|
|
25
|
+
return __async(this, null, function* () {
|
|
26
|
+
try {
|
|
27
|
+
const { room, secret, userId, userInfo, groupIds } = options;
|
|
28
|
+
if (!(typeof room === "string" && room.length > 0)) {
|
|
29
|
+
throw new Error(
|
|
30
|
+
"Invalid room. Please provide a non-empty string as the room. For more information: https://liveblocks.io/docs/api-reference/liveblocks-node#authorize"
|
|
31
|
+
);
|
|
32
|
+
}
|
|
33
|
+
if (!(typeof userId === "string" && userId.length > 0)) {
|
|
34
|
+
throw new Error(
|
|
35
|
+
"Invalid userId. Please provide a non-empty string as the userId. For more information: https://liveblocks.io/docs/api-reference/liveblocks-node#authorize"
|
|
36
|
+
);
|
|
37
|
+
}
|
|
38
|
+
const result = yield _nodefetch2.default.call(void 0,
|
|
39
|
+
buildLiveblocksAuthorizeEndpoint(options, room),
|
|
40
|
+
{
|
|
41
|
+
method: "POST",
|
|
42
|
+
headers: {
|
|
43
|
+
Authorization: `Bearer ${secret}`,
|
|
44
|
+
"Content-Type": "application/json"
|
|
45
|
+
},
|
|
46
|
+
body: JSON.stringify({
|
|
47
|
+
userId,
|
|
48
|
+
userInfo,
|
|
49
|
+
groupIds
|
|
50
|
+
})
|
|
51
|
+
}
|
|
52
|
+
);
|
|
53
|
+
if (!result.ok) {
|
|
54
|
+
return {
|
|
55
|
+
status: 403,
|
|
56
|
+
body: yield result.text()
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
return {
|
|
60
|
+
status: 200,
|
|
61
|
+
body: yield result.text()
|
|
62
|
+
};
|
|
63
|
+
} catch (er) {
|
|
64
|
+
return {
|
|
65
|
+
status: 403,
|
|
66
|
+
body: 'Call to "https://api.liveblocks.io/v2/rooms/:roomId/authorize" failed. See "error" for more information.',
|
|
67
|
+
error: er
|
|
68
|
+
};
|
|
69
|
+
}
|
|
70
|
+
});
|
|
71
|
+
}
|
|
72
|
+
function buildLiveblocksAuthorizeEndpoint(options, roomId) {
|
|
73
|
+
if (options.liveblocksAuthorizeEndpoint) {
|
|
74
|
+
return options.liveblocksAuthorizeEndpoint.replace("{roomId}", roomId);
|
|
75
|
+
}
|
|
76
|
+
return `https://api.liveblocks.io/v2/rooms/${encodeURIComponent(
|
|
77
|
+
roomId
|
|
78
|
+
)}/authorize`;
|
|
79
|
+
}
|
|
24
80
|
|
|
25
81
|
// src/webhooks.ts
|
|
26
82
|
var _crypto = require('crypto'); var _crypto2 = _interopRequireDefault(_crypto);
|
|
@@ -35,6 +91,9 @@ var _WebhookHandler = class {
|
|
|
35
91
|
const secretKey = secret.slice(_WebhookHandler.secretPrefix.length);
|
|
36
92
|
this.secretBuffer = Buffer.from(secretKey, "base64");
|
|
37
93
|
}
|
|
94
|
+
/**
|
|
95
|
+
* Verifies a webhook request and returns the event
|
|
96
|
+
*/
|
|
38
97
|
verifyRequest(request) {
|
|
39
98
|
const { webhookId, timestamp, rawSignatures } = this.verifyHeaders(
|
|
40
99
|
request.headers
|
|
@@ -53,6 +112,9 @@ var _WebhookHandler = class {
|
|
|
53
112
|
this.verifyWebhookEventType(event);
|
|
54
113
|
return event;
|
|
55
114
|
}
|
|
115
|
+
/**
|
|
116
|
+
* Verifies the headers and returns the webhookId, timestamp and rawSignatures
|
|
117
|
+
*/
|
|
56
118
|
verifyHeaders(headers) {
|
|
57
119
|
const sanitizedHeaders = {};
|
|
58
120
|
Object.keys(headers).forEach((key) => {
|
|
@@ -69,9 +131,17 @@ var _WebhookHandler = class {
|
|
|
69
131
|
throw new Error("Invalid webhook-signature header");
|
|
70
132
|
return { webhookId, timestamp, rawSignatures };
|
|
71
133
|
}
|
|
134
|
+
/**
|
|
135
|
+
* Signs the content with the secret
|
|
136
|
+
* @param content
|
|
137
|
+
* @returns `string`
|
|
138
|
+
*/
|
|
72
139
|
sign(content) {
|
|
73
140
|
return _crypto2.default.createHmac("sha256", this.secretBuffer).update(content).digest("base64");
|
|
74
141
|
}
|
|
142
|
+
/**
|
|
143
|
+
* Verifies that the timestamp is not too old or in the future
|
|
144
|
+
*/
|
|
75
145
|
verifyTimestamp(timestampHeader) {
|
|
76
146
|
const now = Math.floor(Date.now() / 1e3);
|
|
77
147
|
const timestamp = parseInt(timestampHeader, 10);
|
|
@@ -85,6 +155,10 @@ var _WebhookHandler = class {
|
|
|
85
155
|
throw new Error("Timestamp in the future");
|
|
86
156
|
}
|
|
87
157
|
}
|
|
158
|
+
/**
|
|
159
|
+
* Ensures that the event is a known event type
|
|
160
|
+
* or throws and prompts the user to upgrade to a higher version of @liveblocks/node
|
|
161
|
+
*/
|
|
88
162
|
verifyWebhookEventType(event) {
|
|
89
163
|
if (event && event.type && [
|
|
90
164
|
"storageUpdated",
|
|
@@ -104,64 +178,6 @@ WebhookHandler.secretPrefix = "whsec_";
|
|
|
104
178
|
var WEBHOOK_TOLERANCE_IN_SECONDS = 5 * 60;
|
|
105
179
|
var isNotUndefined = (value) => value !== void 0;
|
|
106
180
|
|
|
107
|
-
// src/index.ts
|
|
108
|
-
function authorize(options) {
|
|
109
|
-
return __async(this, null, function* () {
|
|
110
|
-
try {
|
|
111
|
-
const { room, secret, userId, userInfo, groupIds } = options;
|
|
112
|
-
if (!(typeof room === "string" && room.length > 0)) {
|
|
113
|
-
throw new Error(
|
|
114
|
-
"Invalid room. Please provide a non-empty string as the room. For more information: https://liveblocks.io/docs/api-reference/liveblocks-node#authorize"
|
|
115
|
-
);
|
|
116
|
-
}
|
|
117
|
-
if (!(typeof userId === "string" && userId.length > 0)) {
|
|
118
|
-
throw new Error(
|
|
119
|
-
"Invalid userId. Please provide a non-empty string as the userId. For more information: https://liveblocks.io/docs/api-reference/liveblocks-node#authorize"
|
|
120
|
-
);
|
|
121
|
-
}
|
|
122
|
-
const result = yield _nodefetch2.default.call(void 0,
|
|
123
|
-
buildLiveblocksAuthorizeEndpoint(options, room),
|
|
124
|
-
{
|
|
125
|
-
method: "POST",
|
|
126
|
-
headers: {
|
|
127
|
-
Authorization: `Bearer ${secret}`,
|
|
128
|
-
"Content-Type": "application/json"
|
|
129
|
-
},
|
|
130
|
-
body: JSON.stringify({
|
|
131
|
-
userId,
|
|
132
|
-
userInfo,
|
|
133
|
-
groupIds
|
|
134
|
-
})
|
|
135
|
-
}
|
|
136
|
-
);
|
|
137
|
-
if (!result.ok) {
|
|
138
|
-
return {
|
|
139
|
-
status: 403,
|
|
140
|
-
body: yield result.text()
|
|
141
|
-
};
|
|
142
|
-
}
|
|
143
|
-
return {
|
|
144
|
-
status: 200,
|
|
145
|
-
body: yield result.text()
|
|
146
|
-
};
|
|
147
|
-
} catch (er) {
|
|
148
|
-
return {
|
|
149
|
-
status: 403,
|
|
150
|
-
body: 'Call to "https://api.liveblocks.io/v2/rooms/:roomId/authorize" failed. See "error" for more information.',
|
|
151
|
-
error: er
|
|
152
|
-
};
|
|
153
|
-
}
|
|
154
|
-
});
|
|
155
|
-
}
|
|
156
|
-
function buildLiveblocksAuthorizeEndpoint(options, roomId) {
|
|
157
|
-
if (options.liveblocksAuthorizeEndpoint) {
|
|
158
|
-
return options.liveblocksAuthorizeEndpoint.replace("{roomId}", roomId);
|
|
159
|
-
}
|
|
160
|
-
return `https://api.liveblocks.io/v2/rooms/${encodeURIComponent(
|
|
161
|
-
roomId
|
|
162
|
-
)}/authorize`;
|
|
163
|
-
}
|
|
164
|
-
|
|
165
181
|
|
|
166
182
|
|
|
167
183
|
exports.WebhookHandler = WebhookHandler; exports.authorize = authorize;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@liveblocks/node",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.6-test1",
|
|
4
4
|
"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.",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"main": "./dist/index.js",
|