Skip to content

Commit 0b00769

Browse files
sonologicoMeenaAlfonsagatav
authored
Add support for initial user features (#162)
* Add authenticateUser function and deprecate authenticate in favor of authorizeChannel * Send To User * feat: add terminate user connections function Co-authored-by: Meena Alfons <[email protected]> Co-authored-by: Agata Walukiewicz <[email protected]>
1 parent e74721a commit 0b00769

File tree

6 files changed

+369
-41
lines changed

6 files changed

+369
-41
lines changed

README.md

Lines changed: 33 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -241,7 +241,7 @@ pusher
241241
242242
This library supports end-to-end encryption of your private channels. This means that only you and your connected clients will be able to read your messages. Pusher cannot decrypt them. You can enable this feature by following these steps:
243243
244-
1. You should first set up Private channels. This involves [creating an authentication endpoint on your server](https://pusher.com/docs/authenticating_users).
244+
1. You should first set up Private channels. This involves [creating an authorization endpoint on your server](https://pusher.com/docs/authenticating_users).
245245
246246
2. Next, generate your 32 byte master encryption key, encode it as base64 and pass it to the Pusher constructor.
247247
@@ -278,17 +278,44 @@ pusher.trigger(["channel-1", "private-encrypted-channel-2"], "test_event", {
278278
279279
Rationale: the methods in this library map directly to individual Channels HTTP API requests. If we allowed triggering a single event on multiple channels (some encrypted, some unencrypted), then it would require two API requests: one where the event is encrypted to the encrypted channels, and one where the event is unencrypted for unencrypted channels.
280280
281-
### Authenticating private channels
281+
### Authenticating users
282282
283-
To authorise your users to access private channels on Pusher Channels, you can use the `authenticate` function:
283+
To authenticate users during sign in, you can use the `authenticateUser` function:
284284
285285
```javascript
286-
const auth = pusher.authenticate(socketId, channel)
286+
const userData = {
287+
id: "unique_user_id",
288+
name: "John Doe",
289+
image: "https://...",
290+
}
291+
const auth = pusher.authenticateUser(socketId, userData)
292+
```
293+
294+
The `userData` parameter must contain an `id` property with a non empty string. For more information see: <http://pusher.com/docs/authenticating_users>
295+
296+
### Terminating user connections
297+
298+
In order to terminate a user's connections, the user must have been authenticated. Check the [Server user authentication docs](http://pusher.com/docs/authenticating_users) for the information on how to create a user authentication endpoint.
299+
300+
To terminate all connections established by a given user, you can use the `terminateUserConnections` function:
301+
302+
```javascript
303+
pusher.terminateUserConnections(userId)
304+
```
305+
306+
Please note, that it only terminates the user's active connections. This means, if nothing else is done, the user will be able to reconnect. For more information see: [Terminating user connections docs](https://pusher.com/docs/channels/server_api/terminating-user-connections/).
307+
308+
### Private channel authorisation
309+
310+
To authorise your users to access private channels on Pusher Channels, you can use the `authorizeChannel` function:
311+
312+
```javascript
313+
const auth = pusher.authorizeChannel(socketId, channel)
287314
```
288315
289316
For more information see: <http://pusher.com/docs/authenticating_users>
290317
291-
### Authenticating presence channels
318+
### Presence channel authorisation
292319
293320
Using presence channels is similar to private channels, but you can specify extra data to identify that particular user:
294321
@@ -300,7 +327,7 @@ const channelData = {
300327
twitter_id: '@leggetter'
301328
}
302329
};
303-
const auth = pusher.authenticate(socketId, channel, channelData);
330+
const auth = pusher.authorizeChannel(socketId, channel, channelData);
304331
```
305332
306333
The `auth` is then returned to the caller as JSON.

lib/auth.js

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,14 @@
11
const util = require("./util")
22

3+
function getSocketSignatureForUser(token, socketId, userData) {
4+
const serializedUserData = JSON.stringify(userData)
5+
const signature = token.sign(`${socketId}::user::${serializedUserData}`)
6+
return {
7+
auth: `${token.key}:${signature}`,
8+
user_data: serializedUserData,
9+
}
10+
}
11+
312
function getSocketSignature(pusher, token, channel, socketID, data) {
413
const result = {}
514

@@ -26,4 +35,5 @@ function getSocketSignature(pusher, token, channel, socketID, data) {
2635
return result
2736
}
2837

38+
exports.getSocketSignatureForUser = getSocketSignatureForUser
2939
exports.getSocketSignature = getSocketSignature

lib/pusher.js

Lines changed: 69 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,19 @@ const validateSocketId = function (socketId) {
3434
}
3535
}
3636

37+
const validateUserId = function (userId) {
38+
if (typeof userId !== "string" || userId === "") {
39+
throw new Error("Invalid user id: '" + userId + "'")
40+
}
41+
}
42+
43+
const validateUserData = function (userData) {
44+
if (userData == null || typeof userData !== "object") {
45+
throw new Error("Invalid user data: '" + userData + "'")
46+
}
47+
validateUserId(userData.id)
48+
}
49+
3750
/** Provides access to Pusher's REST API, WebHooks and authentication.
3851
*
3952
* @constructor
@@ -103,9 +116,9 @@ Pusher.forCluster = function (cluster, options) {
103116
* @param {String} socketId socket id
104117
* @param {String} channel channel name
105118
* @param {Object} [data] additional socket data
106-
* @returns {String} authentication signature
119+
* @returns {String} authorization signature
107120
*/
108-
Pusher.prototype.authenticate = function (socketId, channel, data) {
121+
Pusher.prototype.authorizeChannel = function (socketId, channel, data) {
109122
validateSocketId(socketId)
110123
validateChannel(channel)
111124

@@ -118,6 +131,60 @@ Pusher.prototype.authenticate = function (socketId, channel, data) {
118131
)
119132
}
120133

134+
/** Returns a signature for given socket id, channel and socket data.
135+
*
136+
* DEPRECATED. Use authorizeChannel.
137+
*
138+
* @param {String} socketId socket id
139+
* @param {String} channel channel name
140+
* @param {Object} [data] additional socket data
141+
* @returns {String} authorization signature
142+
*/
143+
Pusher.prototype.authenticate = Pusher.prototype.authorizeChannel
144+
145+
/** Returns a signature for given socket id and user data.
146+
*
147+
* @param {String} socketId socket id
148+
* @param {Object} userData user data
149+
* @returns {String} authentication signature
150+
*/
151+
Pusher.prototype.authenticateUser = function (socketId, userData) {
152+
validateSocketId(socketId)
153+
validateUserData(userData)
154+
155+
return auth.getSocketSignatureForUser(this.config.token, socketId, userData)
156+
}
157+
158+
/** Sends an event to a user.
159+
*
160+
* Event name can be at most 200 characters long.
161+
*
162+
* @param {String} userId user id
163+
* @param {String} event event name
164+
* @param data event data, objects are JSON-encoded
165+
* @returns {Promise} a promise resolving to a response, or rejecting to a RequestError.
166+
* @see RequestError
167+
*/
168+
Pusher.prototype.sendToUser = function (userId, event, data) {
169+
if (event.length > 200) {
170+
throw new Error("Too long event name: '" + event + "'")
171+
}
172+
validateUserId(userId)
173+
return events.trigger(this, [`#server-to-user-${userId}`], event, data)
174+
}
175+
176+
/** Terminate users's connections.
177+
*
178+
*
179+
* @param {String} userId user id
180+
* @returns {Promise} a promise resolving to a response, or rejecting to a RequestError.
181+
* @see RequestError
182+
*/
183+
Pusher.prototype.terminateUserConnections = function (userId) {
184+
validateUserId(userId)
185+
return this.post({ path: `/users/${userId}/terminate_connections`, body: {} })
186+
}
187+
121188
/** Triggers an event.
122189
*
123190
* Channel names can contain only characters which are alphanumeric, '_' or '-'

0 commit comments

Comments
 (0)