hackchat-engine 1.1.6 → 1.1.8
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/Client.js +106 -34
- package/events/EventsManager.js +8 -0
- package/events/HackAttempt.js +24 -0
- package/events/PublicChannels.js +24 -0
- package/events/SignMessage.js +23 -0
- package/events/SignTransaction.js +23 -0
- package/package.json +1 -1
- package/structures/HackAttemptStruct.js +76 -0
- package/structures/MessageStruct.js +1 -1
- package/structures/PubChannelsStruct.js +47 -0
- package/structures/UserStruct.js +7 -0
- package/util/Constants.js +11 -0
- package/websocket/SocketHandler.js +11 -6
- package/websocket/packets/PacketRouter.js +39 -1
- package/websocket/packets/handlers/EmoteHandler.js +1 -1
- package/websocket/packets/handlers/HackAttemptHandler.js +30 -0
- package/websocket/packets/handlers/InfoHandler.js +1 -1
- package/websocket/packets/handlers/InviteHandler.js +1 -1
- package/websocket/packets/handlers/PubChannelsHandler.js +30 -0
- package/websocket/packets/handlers/SignMessageHandler.js +34 -0
- package/websocket/packets/handlers/SignTransactionHandler.js +36 -0
- package/websocket/packets/handlers/WhisperHandler.js +1 -1
package/Client.js
CHANGED
|
@@ -10,10 +10,8 @@ import SocketController from './websocket/SocketController.js';
|
|
|
10
10
|
import EventsManager from './events/EventsManager.js';
|
|
11
11
|
import ExtMap from './util/ExtMap.js';
|
|
12
12
|
|
|
13
|
-
const util = new Util();
|
|
14
|
-
|
|
15
13
|
/**
|
|
16
|
-
* Main client interface
|
|
14
|
+
* Main client interface for the hack.chat protocol
|
|
17
15
|
* @extends {EventEmitter}
|
|
18
16
|
*/
|
|
19
17
|
class Client extends EventEmitter {
|
|
@@ -33,26 +31,26 @@ class Client extends EventEmitter {
|
|
|
33
31
|
};
|
|
34
32
|
|
|
35
33
|
/**
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
34
|
+
* Create the websocket manager for this client
|
|
35
|
+
* @type {SocketController}
|
|
36
|
+
*/
|
|
39
37
|
this.ws = new SocketController(this);
|
|
40
38
|
|
|
41
39
|
/**
|
|
42
|
-
* Create the event manager for this client
|
|
40
|
+
* Create the event manager for this client, responsible for data structure mapping
|
|
43
41
|
* @type {EventsManager}
|
|
44
42
|
*/
|
|
45
43
|
this.events = new EventsManager(this);
|
|
46
44
|
|
|
47
45
|
/**
|
|
48
46
|
* Stored time that the client was last ready
|
|
49
|
-
* @type {Date}
|
|
47
|
+
* @type {Date|null}
|
|
50
48
|
*/
|
|
51
49
|
this.readyAt = null;
|
|
52
50
|
|
|
53
51
|
/**
|
|
54
52
|
* User info for this client
|
|
55
|
-
* @type {ClientStruct}
|
|
53
|
+
* @type {ClientStruct|null}
|
|
56
54
|
*/
|
|
57
55
|
this.myUser = null;
|
|
58
56
|
|
|
@@ -69,23 +67,25 @@ class Client extends EventEmitter {
|
|
|
69
67
|
this.channels = new ExtMap();
|
|
70
68
|
|
|
71
69
|
/**
|
|
72
|
-
* Active timeouts set on this client
|
|
73
|
-
* @type {Set}
|
|
70
|
+
* Active timeouts set on this client, managed for destruction
|
|
71
|
+
* @type {Set<Timeout>}
|
|
74
72
|
*/
|
|
75
73
|
this.timeouts = new Set();
|
|
76
74
|
|
|
77
75
|
/**
|
|
78
|
-
* Active intervals set on this client
|
|
76
|
+
* Active intervals set on this client, managed for destruction
|
|
79
77
|
* @type {Set<Timeout>}
|
|
80
78
|
*/
|
|
81
79
|
this.intervals = new Set();
|
|
82
80
|
|
|
83
81
|
/**
|
|
84
82
|
* Internal check to see if this code is run in node or a browser
|
|
85
|
-
* @type {
|
|
83
|
+
* @type {boolean}
|
|
86
84
|
*/
|
|
87
85
|
this.isBrowser = typeof window !== 'undefined';
|
|
88
86
|
|
|
87
|
+
this.util = new Util();
|
|
88
|
+
|
|
89
89
|
/**
|
|
90
90
|
* Initiate websocket connection
|
|
91
91
|
*/
|
|
@@ -108,7 +108,7 @@ class Client extends EventEmitter {
|
|
|
108
108
|
|
|
109
109
|
/**
|
|
110
110
|
* How long this client has been connected, in milliseconds
|
|
111
|
-
* @type {number}
|
|
111
|
+
* @type {number|null}
|
|
112
112
|
* @readonly
|
|
113
113
|
*/
|
|
114
114
|
get uptime() {
|
|
@@ -117,7 +117,7 @@ class Client extends EventEmitter {
|
|
|
117
117
|
|
|
118
118
|
/**
|
|
119
119
|
* Timestamp of the time the client when it was last ready
|
|
120
|
-
* @type {number}
|
|
120
|
+
* @type {number|null}
|
|
121
121
|
* @readonly
|
|
122
122
|
*/
|
|
123
123
|
get readyTimestamp() {
|
|
@@ -137,7 +137,7 @@ class Client extends EventEmitter {
|
|
|
137
137
|
* Sends a join event to the hackchat server
|
|
138
138
|
* @param {string} name Name to join with
|
|
139
139
|
* @param {string} password Optional password to create trip code
|
|
140
|
-
* @param {string} channel Channel to
|
|
140
|
+
* @param {string} channel Channel to join
|
|
141
141
|
* @returns {void}
|
|
142
142
|
*/
|
|
143
143
|
join(name = false, password = '', channel = false) {
|
|
@@ -167,11 +167,11 @@ class Client extends EventEmitter {
|
|
|
167
167
|
|
|
168
168
|
/**
|
|
169
169
|
* Establishes communication with a hackchat server
|
|
170
|
+
* @returns {Promise<void>}
|
|
170
171
|
*/
|
|
171
172
|
async connectToWebSocket() {
|
|
172
173
|
try {
|
|
173
|
-
|
|
174
|
-
return new Promise(async (resolve, reject) => { // anti-pattern my ass
|
|
174
|
+
return new Promise((resolve, reject) => {
|
|
175
175
|
this.emit(Events.DEBUG, '[client] Initiating connection. . .');
|
|
176
176
|
|
|
177
177
|
const timeout = this.setTimeout(
|
|
@@ -179,23 +179,32 @@ class Client extends EventEmitter {
|
|
|
179
179
|
1000 * 300,
|
|
180
180
|
);
|
|
181
181
|
|
|
182
|
-
|
|
182
|
+
const { gateway } = this.options.ws;
|
|
183
183
|
|
|
184
|
-
|
|
185
|
-
this.emit(Events.DEBUG,
|
|
186
|
-
const conf = await util.fetchWebsocketConfig();
|
|
187
|
-
gateway = conf.gateway;
|
|
188
|
-
}
|
|
184
|
+
const initiateConnection = (gw) => {
|
|
185
|
+
this.emit(Events.DEBUG, `[client] Using gateway ${gw}`);
|
|
189
186
|
|
|
190
|
-
|
|
187
|
+
const success = this.ws.connect(gw);
|
|
188
|
+
if (!success) {
|
|
189
|
+
return reject(new Error('Connection failed to start (Socket likely not IDLE)'));
|
|
190
|
+
}
|
|
191
191
|
|
|
192
|
-
|
|
193
|
-
this.ws.connection.once('error', reject);
|
|
192
|
+
this.ws.connection.once('error', reject);
|
|
194
193
|
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
194
|
+
this.once(Events.READY, () => {
|
|
195
|
+
this.clearTimeout(timeout);
|
|
196
|
+
resolve();
|
|
197
|
+
});
|
|
198
|
+
};
|
|
199
|
+
|
|
200
|
+
if (this.browser) {
|
|
201
|
+
this.emit(Events.DEBUG, '[client] Fetching ws config');
|
|
202
|
+
this.util.fetchWebsocketConfig()
|
|
203
|
+
.then((conf) => initiateConnection(conf.gateway))
|
|
204
|
+
.catch(reject);
|
|
205
|
+
} else {
|
|
206
|
+
initiateConnection(gateway);
|
|
207
|
+
}
|
|
199
208
|
});
|
|
200
209
|
} catch (e) {
|
|
201
210
|
this.destroy();
|
|
@@ -205,20 +214,21 @@ class Client extends EventEmitter {
|
|
|
205
214
|
|
|
206
215
|
/**
|
|
207
216
|
* Terminates the websocket connection and destroys the client
|
|
208
|
-
* @returns {Promise}
|
|
217
|
+
* @returns {Promise<void>}
|
|
209
218
|
*/
|
|
210
219
|
destroy() {
|
|
211
220
|
for (const t of this.timeouts) clearTimeout(t); // eslint-disable-line no-restricted-syntax
|
|
212
221
|
for (const i of this.intervals) clearInterval(i); // eslint-disable-line no-restricted-syntax
|
|
213
222
|
this.timeouts.clear();
|
|
214
223
|
this.intervals.clear();
|
|
224
|
+
this.ws.destroy();
|
|
215
225
|
return Promise.resolve();
|
|
216
226
|
}
|
|
217
227
|
|
|
218
228
|
/**
|
|
219
229
|
* Create a managed timeout
|
|
220
230
|
* @param {Function} func Target function to call
|
|
221
|
-
* @param {number} delay Wait time before calling func
|
|
231
|
+
* @param {number} delay Wait time before calling func (in ms)
|
|
222
232
|
* @param {...*} args Optional arguments to pass to func
|
|
223
233
|
* @returns {Timeout}
|
|
224
234
|
*/
|
|
@@ -245,7 +255,7 @@ class Client extends EventEmitter {
|
|
|
245
255
|
/**
|
|
246
256
|
* Create a managed interval
|
|
247
257
|
* @param {Function} func Target function to call
|
|
248
|
-
* @param {number} delay Wait time before calling func
|
|
258
|
+
* @param {number} delay Wait time before calling func (in ms)
|
|
249
259
|
* @param {...*} args Optional arguments to pass to func
|
|
250
260
|
* @returns {Timeout}
|
|
251
261
|
*/
|
|
@@ -333,6 +343,68 @@ class Client extends EventEmitter {
|
|
|
333
343
|
channel,
|
|
334
344
|
});
|
|
335
345
|
}
|
|
346
|
+
|
|
347
|
+
/**
|
|
348
|
+
* Registers a handler for a specific, unmapped command (cmd)
|
|
349
|
+
* This allows the client to process custom packets without needing the 'raw' event
|
|
350
|
+
* @param {string} cmd The command string from the server (e.g., 'signMessage')
|
|
351
|
+
* @param {function(object): void} handler The function to execute when the command is received
|
|
352
|
+
*
|
|
353
|
+
* @example
|
|
354
|
+
* import { Client } from 'hackchat-engine';
|
|
355
|
+
* const hcClient = new Client({
|
|
356
|
+
* isBot: false,
|
|
357
|
+
* });
|
|
358
|
+
* hcClient.onCommand('example', (payload) => {
|
|
359
|
+
* // This function only fires when { cmd: 'example' } is received
|
|
360
|
+
* console.log(payload);
|
|
361
|
+
* });
|
|
362
|
+
*/
|
|
363
|
+
onCommand(cmd, handler) {
|
|
364
|
+
if (!this.ws.connection || !this.ws.connection.packetRouter) {
|
|
365
|
+
this.emit(Events.WARN, `Cannot register command '${cmd}': Router not initialized.`);
|
|
366
|
+
return;
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
this.ws.connection.packetRouter.registerCustomCommand(cmd, handler);
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
/**
|
|
373
|
+
* Sends a Solana signature and the signed message back to the server for verification
|
|
374
|
+
* @param {string} signature The base64 or hex encoded signature from the client's wallet
|
|
375
|
+
* @param {string} signedMessage The original human-readable message that was signed
|
|
376
|
+
*/
|
|
377
|
+
requestSiw(wallet, address) {
|
|
378
|
+
this.ws.send({
|
|
379
|
+
cmd: OPCodes.REQUEST_SIW,
|
|
380
|
+
wallet,
|
|
381
|
+
address,
|
|
382
|
+
});
|
|
383
|
+
}
|
|
384
|
+
|
|
385
|
+
/**
|
|
386
|
+
* Sends a Solana signature and the signed message back to the server for verification
|
|
387
|
+
* @param {string} signature The base64 or hex encoded signature from the client's wallet
|
|
388
|
+
* @param {string} signedMessage The original human-readable message that was signed
|
|
389
|
+
*/
|
|
390
|
+
sendSignature(signature, signedMessage) {
|
|
391
|
+
this.ws.send({
|
|
392
|
+
cmd: OPCodes.SIGN_SIW,
|
|
393
|
+
signature,
|
|
394
|
+
signedMessage,
|
|
395
|
+
});
|
|
396
|
+
}
|
|
397
|
+
|
|
398
|
+
/**
|
|
399
|
+
* Sends a signed transaction back to the server for broadcasting
|
|
400
|
+
* @param {string} signedTransaction The base64 encoded signed transaction object
|
|
401
|
+
*/
|
|
402
|
+
sendSignedTransaction(signedTransaction) {
|
|
403
|
+
this.ws.send({
|
|
404
|
+
cmd: OPCodes.CONFIRM_TX,
|
|
405
|
+
signedTransaction,
|
|
406
|
+
});
|
|
407
|
+
}
|
|
336
408
|
}
|
|
337
409
|
|
|
338
410
|
export default Client;
|
package/events/EventsManager.js
CHANGED
|
@@ -10,6 +10,10 @@ import UserLeave from './UserLeave.js';
|
|
|
10
10
|
import UpdateUser from './UpdateUser.js';
|
|
11
11
|
import Warning from './Warning.js';
|
|
12
12
|
import Whisper from './Whisper.js';
|
|
13
|
+
import PublicChannels from './PublicChannels.js';
|
|
14
|
+
import HackAttempt from './HackAttempt.js';
|
|
15
|
+
import SignMessage from './SignMessage.js';
|
|
16
|
+
import SignTransaction from './SignTransaction.js';
|
|
13
17
|
|
|
14
18
|
/**
|
|
15
19
|
* This class routes incoming event data to it's proper handler
|
|
@@ -34,6 +38,10 @@ class EventsManager {
|
|
|
34
38
|
this.UpdateUser = new UpdateUser(this.client);
|
|
35
39
|
this.Warning = new Warning(this.client);
|
|
36
40
|
this.Whisper = new Whisper(this.client);
|
|
41
|
+
this.PublicChannels = new PublicChannels(this.client);
|
|
42
|
+
this.HackAttempt = new HackAttempt(this.client);
|
|
43
|
+
this.SignMessage = new SignMessage(this.client);
|
|
44
|
+
this.SignTransaction = new SignTransaction(this.client);
|
|
37
45
|
}
|
|
38
46
|
}
|
|
39
47
|
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import AbstractEvent from './AbstractEvent.js';
|
|
2
|
+
import HackAttemptStruct from '../structures/HackAttemptStruct.js';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* This class handles an incoming `hackattempt` event from the server
|
|
6
|
+
* @private
|
|
7
|
+
*/
|
|
8
|
+
class PublicChannels extends AbstractEvent {
|
|
9
|
+
/**
|
|
10
|
+
* Event handler function
|
|
11
|
+
* @param {object} data Incoming event data
|
|
12
|
+
* @returns {object}
|
|
13
|
+
*/
|
|
14
|
+
handle(data) {
|
|
15
|
+
const { client } = this;
|
|
16
|
+
const message = new HackAttemptStruct(client, data);
|
|
17
|
+
|
|
18
|
+
return {
|
|
19
|
+
message,
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export default PublicChannels;
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import AbstractEvent from './AbstractEvent.js';
|
|
2
|
+
import PubChannelsStruct from '../structures/PubChannelsStruct.js';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* This class handles an incoming `publicchannels` event from the server
|
|
6
|
+
* @private
|
|
7
|
+
*/
|
|
8
|
+
class PublicChannels extends AbstractEvent {
|
|
9
|
+
/**
|
|
10
|
+
* Event handler function
|
|
11
|
+
* @param {object} data Incoming event data
|
|
12
|
+
* @returns {object}
|
|
13
|
+
*/
|
|
14
|
+
handle(data) {
|
|
15
|
+
const { client } = this;
|
|
16
|
+
const message = new PubChannelsStruct(client, data);
|
|
17
|
+
|
|
18
|
+
return {
|
|
19
|
+
message,
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export default PublicChannels;
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import AbstractEvent from './AbstractEvent.js';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* This class handles an incoming `signMessage` event from the server
|
|
5
|
+
* @private
|
|
6
|
+
*/
|
|
7
|
+
class SignMessage extends AbstractEvent {
|
|
8
|
+
/**
|
|
9
|
+
* Event handler function
|
|
10
|
+
* @param {object} data Incoming event data
|
|
11
|
+
* @returns {object}
|
|
12
|
+
*/
|
|
13
|
+
handle(data) {
|
|
14
|
+
const { client } = this;
|
|
15
|
+
client.lastMsg = data;
|
|
16
|
+
|
|
17
|
+
return {
|
|
18
|
+
data,
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export default SignMessage;
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import AbstractEvent from './AbstractEvent.js';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* This class handles an incoming `signTransaction` event from the server
|
|
5
|
+
* @private
|
|
6
|
+
*/
|
|
7
|
+
class SignTransaction extends AbstractEvent {
|
|
8
|
+
/**
|
|
9
|
+
* Event handler function
|
|
10
|
+
* @param {object} data Incoming event data
|
|
11
|
+
* @returns {object}
|
|
12
|
+
*/
|
|
13
|
+
handle(data) {
|
|
14
|
+
const { client } = this;
|
|
15
|
+
client.lastSign = data;
|
|
16
|
+
|
|
17
|
+
return {
|
|
18
|
+
data,
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export default SignTransaction;
|
package/package.json
CHANGED
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* This class handles parsing of the data of a `hackAttempt` event
|
|
3
|
+
*/
|
|
4
|
+
class HackAttemptStruct {
|
|
5
|
+
/**
|
|
6
|
+
* @param {Channel} channel Channel that the hackAttempt was sent through
|
|
7
|
+
* @param {Number} fromId User id of requester
|
|
8
|
+
* @param {User} from User whomst'd sent the hackAttempt
|
|
9
|
+
* @param {String} fromNick User name of whomst'd sent the hackAttempt
|
|
10
|
+
* @param {String} lib Target library
|
|
11
|
+
* @param {Client} client Main client reference
|
|
12
|
+
*/
|
|
13
|
+
constructor(client, data) {
|
|
14
|
+
/**
|
|
15
|
+
* Add client reference
|
|
16
|
+
* @type {Client}
|
|
17
|
+
* @readonly
|
|
18
|
+
*/
|
|
19
|
+
Object.defineProperty(this, 'client', { value: client });
|
|
20
|
+
|
|
21
|
+
if (data) this.setup(data);
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Fill in this structure with provided data
|
|
26
|
+
* @param {object} data Incoming event data
|
|
27
|
+
* @returns {void}
|
|
28
|
+
*/
|
|
29
|
+
setup(data) {
|
|
30
|
+
/**
|
|
31
|
+
* Origin channel of the request
|
|
32
|
+
* @type {string}
|
|
33
|
+
*/
|
|
34
|
+
this.channel = data.channel;
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Userid of request sender
|
|
38
|
+
* @type {number}
|
|
39
|
+
*/
|
|
40
|
+
this.fromId = data.from;
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* The user who sent the whisper
|
|
44
|
+
* @type {User}
|
|
45
|
+
*/
|
|
46
|
+
this.from = this.client.users.find((val) => val.userid === data.from);
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Name of request sender
|
|
50
|
+
* @type {string}
|
|
51
|
+
*/
|
|
52
|
+
this.fromNick = data.fromNick;
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* URL to requested library
|
|
56
|
+
* @type {string}
|
|
57
|
+
*/
|
|
58
|
+
this.lib = data.lib;
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* The timestamp the publicchannels was sent at
|
|
62
|
+
* @type {number}
|
|
63
|
+
*/
|
|
64
|
+
this.timestamp = new Date();
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* When referenced as a string, output the content instead of an object type
|
|
69
|
+
* @returns {string}
|
|
70
|
+
*/
|
|
71
|
+
toString() {
|
|
72
|
+
return `${this.fromNick} suggested ${this.lib}`;
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
export default HackAttemptStruct;
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* This class handles parsing of the data of a `publicchannels` event
|
|
3
|
+
*/
|
|
4
|
+
class PubChannelsStruct {
|
|
5
|
+
/**
|
|
6
|
+
* @param {Array} list Array of objects containing channel name and population
|
|
7
|
+
*/
|
|
8
|
+
constructor(client, data) {
|
|
9
|
+
/**
|
|
10
|
+
* Add client reference
|
|
11
|
+
* @type {Client}
|
|
12
|
+
* @readonly
|
|
13
|
+
*/
|
|
14
|
+
Object.defineProperty(this, 'client', { value: client });
|
|
15
|
+
|
|
16
|
+
if (data) this.setup(data);
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Fill in this structure with provided data
|
|
21
|
+
* @param {object} data Incoming event data
|
|
22
|
+
* @returns {void}
|
|
23
|
+
*/
|
|
24
|
+
setup(data) {
|
|
25
|
+
/**
|
|
26
|
+
* Array of objects containing channel name and population
|
|
27
|
+
* @type {array}
|
|
28
|
+
*/
|
|
29
|
+
this.list = data.list;
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* The timestamp the publicchannels was sent at
|
|
33
|
+
* @type {number}
|
|
34
|
+
*/
|
|
35
|
+
this.timestamp = new Date();
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* When referenced as a string, output the content instead of an object type
|
|
40
|
+
* @returns {string}
|
|
41
|
+
*/
|
|
42
|
+
toString() {
|
|
43
|
+
return this.list.join(', ');
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
export default PubChannelsStruct;
|
package/structures/UserStruct.js
CHANGED
|
@@ -106,6 +106,12 @@ class User {
|
|
|
106
106
|
*/
|
|
107
107
|
this.nickColor = data.color || false;
|
|
108
108
|
|
|
109
|
+
/**
|
|
110
|
+
* User's color
|
|
111
|
+
* @type {string}
|
|
112
|
+
*/
|
|
113
|
+
this.flair = data.flair || '';
|
|
114
|
+
|
|
109
115
|
/**
|
|
110
116
|
* Numeric permission level
|
|
111
117
|
* @type {number}
|
|
@@ -260,6 +266,7 @@ class User {
|
|
|
260
266
|
this.userlevel = data.uType;
|
|
261
267
|
this.bot = data.isBot;
|
|
262
268
|
this.nickColor = data.color;
|
|
269
|
+
this.flair = data.flair;
|
|
263
270
|
this.permissionLevel = data.level;
|
|
264
271
|
}
|
|
265
272
|
|
package/util/Constants.js
CHANGED
|
@@ -73,6 +73,9 @@ export const OPCodes = {
|
|
|
73
73
|
LOCK_ROOM: 'lockroom',
|
|
74
74
|
UNLOCK_ROOM: 'unlockroom',
|
|
75
75
|
WHISPER: 'whisper',
|
|
76
|
+
REQUEST_SIW: 'siw',
|
|
77
|
+
SIGN_SIW: 'signsiw',
|
|
78
|
+
CONFIRM_TX: 'confirmtx',
|
|
76
79
|
};
|
|
77
80
|
|
|
78
81
|
/**
|
|
@@ -100,6 +103,10 @@ export const Events = {
|
|
|
100
103
|
ERROR: 'error',
|
|
101
104
|
WARN: 'warn',
|
|
102
105
|
DEBUG: 'debug',
|
|
106
|
+
PUB_CHANS: 'publicchannels',
|
|
107
|
+
HACK_ATTEMPT: 'hackAttempt',
|
|
108
|
+
SIGN_MESSAGE: 'signMessage',
|
|
109
|
+
SIGN_TRANSACTION: 'signTransaction',
|
|
103
110
|
};
|
|
104
111
|
|
|
105
112
|
/**
|
|
@@ -108,6 +115,7 @@ export const Events = {
|
|
|
108
115
|
*/
|
|
109
116
|
export const WSEvents = {
|
|
110
117
|
SESSION: 'session',
|
|
118
|
+
PUB_CHANS: 'publicchannels',
|
|
111
119
|
NEW_MESSAGE: 'chat',
|
|
112
120
|
CHANNEL_INFO: 'info',
|
|
113
121
|
CHANNEL_EMOTE: 'emote',
|
|
@@ -119,4 +127,7 @@ export const WSEvents = {
|
|
|
119
127
|
CHANNEL_CAPTCHA: 'captcha',
|
|
120
128
|
CHANNEL_INVITE: 'invite',
|
|
121
129
|
CHANNEL_WHISPER: 'whisper',
|
|
130
|
+
HACK_ATTEMPT: 'hackAttempt',
|
|
131
|
+
SIGN_MESSAGE: 'signMessage',
|
|
132
|
+
SIGN_TRANSACTION: 'signTransaction',
|
|
122
133
|
};
|
|
@@ -168,6 +168,11 @@ class SocketHandler extends EventEmitter {
|
|
|
168
168
|
* @returns {void}
|
|
169
169
|
*/
|
|
170
170
|
send(data) {
|
|
171
|
+
if (this.packetQueue.queue.length > 500) {
|
|
172
|
+
this.debug('Packet queue full, dropping message');
|
|
173
|
+
return;
|
|
174
|
+
}
|
|
175
|
+
|
|
171
176
|
if (!this.ws || this.ws.readyState !== WebSocket.OPEN) {
|
|
172
177
|
this.debug(`[socket handler] No connection, failed to send: ${data}`);
|
|
173
178
|
return;
|
|
@@ -189,7 +194,7 @@ class SocketHandler extends EventEmitter {
|
|
|
189
194
|
this.client.setTimeout(() => {
|
|
190
195
|
this.connect(gateway, 0, force);
|
|
191
196
|
},
|
|
192
|
-
|
|
197
|
+
after);
|
|
193
198
|
|
|
194
199
|
return false;
|
|
195
200
|
}
|
|
@@ -221,7 +226,7 @@ class SocketHandler extends EventEmitter {
|
|
|
221
226
|
}
|
|
222
227
|
|
|
223
228
|
/**
|
|
224
|
-
* Destroys the connection
|
|
229
|
+
* Destroys the connection
|
|
225
230
|
* @returns {boolean}
|
|
226
231
|
*/
|
|
227
232
|
destroy() {
|
|
@@ -290,9 +295,9 @@ class SocketHandler extends EventEmitter {
|
|
|
290
295
|
this.debug(`[socket handler] Connected to gateway ${this.gateway}`);
|
|
291
296
|
|
|
292
297
|
/**
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
298
|
+
* Emitted when websocket has been connected
|
|
299
|
+
* @event Client#connected
|
|
300
|
+
*/
|
|
296
301
|
this.client.emit(Events.CONNECTED, this.client);
|
|
297
302
|
|
|
298
303
|
this.sessionStart();
|
|
@@ -337,7 +342,7 @@ class SocketHandler extends EventEmitter {
|
|
|
337
342
|
this.closeExpected = false;
|
|
338
343
|
|
|
339
344
|
/**
|
|
340
|
-
* Emitted when the client's WebSocket disconnects and will no longer attempt to reconnect
|
|
345
|
+
* Emitted when the client's WebSocket disconnects and will no longer attempt to reconnect
|
|
341
346
|
* @event Client#disconnect
|
|
342
347
|
* @param {CloseEvent} event Close event
|
|
343
348
|
*/
|
|
@@ -1,5 +1,9 @@
|
|
|
1
1
|
/* eslint global-require: 0 */
|
|
2
|
-
import {
|
|
2
|
+
import {
|
|
3
|
+
Status,
|
|
4
|
+
WSEvents,
|
|
5
|
+
Events,
|
|
6
|
+
} from '../../util/Constants.js';
|
|
3
7
|
|
|
4
8
|
import SessionHandler from './handlers/SessionHandler.js';
|
|
5
9
|
import ChatHandler from './handlers/ChatHandler.js';
|
|
@@ -13,9 +17,14 @@ import UserLeaveHandler from './handlers/UserLeaveHandler.js';
|
|
|
13
17
|
import UpdateUserHandler from './handlers/UpdateUserHandler.js';
|
|
14
18
|
import CaptchaHandler from './handlers/CaptchaHandler.js';
|
|
15
19
|
import WhisperHandler from './handlers/WhisperHandler.js';
|
|
20
|
+
import PubChannelsHandler from './handlers/PubChannelsHandler.js';
|
|
21
|
+
import HackAttemptHandler from './handlers/HackAttemptHandler.js';
|
|
22
|
+
import SignMessageHandler from './handlers/SignMessageHandler.js';
|
|
23
|
+
import SignTransactionHandler from './handlers/SignTransactionHandler.js';
|
|
16
24
|
|
|
17
25
|
const BeforeReadyWhitelist = [
|
|
18
26
|
WSEvents.SESSION,
|
|
27
|
+
WSEvents.PUB_CHANS,
|
|
19
28
|
];
|
|
20
29
|
|
|
21
30
|
/**
|
|
@@ -45,6 +54,12 @@ class PacketRouter {
|
|
|
45
54
|
*/
|
|
46
55
|
this.queue = [];
|
|
47
56
|
|
|
57
|
+
/**
|
|
58
|
+
* Custom handlers registered by the user for unmapped commands
|
|
59
|
+
* @type {Map<string, function(object): void>}
|
|
60
|
+
*/
|
|
61
|
+
this.customHandlers = new Map();
|
|
62
|
+
|
|
48
63
|
// Register all events
|
|
49
64
|
this.registerEvent(WSEvents.SESSION, SessionHandler);
|
|
50
65
|
this.registerEvent(WSEvents.NEW_MESSAGE, ChatHandler);
|
|
@@ -58,6 +73,10 @@ class PacketRouter {
|
|
|
58
73
|
this.registerEvent(WSEvents.USER_UPDATE, UpdateUserHandler);
|
|
59
74
|
this.registerEvent(WSEvents.CHANNEL_CAPTCHA, CaptchaHandler);
|
|
60
75
|
this.registerEvent(WSEvents.CHANNEL_WHISPER, WhisperHandler);
|
|
76
|
+
this.registerEvent(WSEvents.PUB_CHANS, PubChannelsHandler);
|
|
77
|
+
this.registerEvent(WSEvents.HACK_ATTEMPT, HackAttemptHandler);
|
|
78
|
+
this.registerEvent(WSEvents.SIGN_MESSAGE, SignMessageHandler);
|
|
79
|
+
this.registerEvent(WSEvents.SIGN_TRANSACTION, SignTransactionHandler);
|
|
61
80
|
}
|
|
62
81
|
|
|
63
82
|
/**
|
|
@@ -69,6 +88,15 @@ class PacketRouter {
|
|
|
69
88
|
return this.ws.client;
|
|
70
89
|
}
|
|
71
90
|
|
|
91
|
+
/**
|
|
92
|
+
* Registers a custom command handler
|
|
93
|
+
* @param {string} cmd The command string
|
|
94
|
+
* @param {function(object): void} handler The function to execute
|
|
95
|
+
*/
|
|
96
|
+
registerCustomCommand(cmd, handler) {
|
|
97
|
+
this.customHandlers.set(cmd, handler);
|
|
98
|
+
}
|
|
99
|
+
|
|
72
100
|
/**
|
|
73
101
|
* Register an event handler module
|
|
74
102
|
* @param {string} eventname Event name constant
|
|
@@ -107,7 +135,17 @@ class PacketRouter {
|
|
|
107
135
|
}
|
|
108
136
|
|
|
109
137
|
if (!queue && this.queue.length > 0) this.processQueue();
|
|
138
|
+
|
|
110
139
|
if (this.handlers[packet.cmd]) return this.handlers[packet.cmd].handle(packet);
|
|
140
|
+
|
|
141
|
+
const customHandler = this.customHandlers.get(packet.cmd);
|
|
142
|
+
if (customHandler) {
|
|
143
|
+
this.client.emit(Events.DEBUG, `[router] Executing custom handler for cmd: ${packet.cmd}`);
|
|
144
|
+
customHandler(packet);
|
|
145
|
+
|
|
146
|
+
return true;
|
|
147
|
+
}
|
|
148
|
+
|
|
111
149
|
return false;
|
|
112
150
|
}
|
|
113
151
|
}
|
|
@@ -16,7 +16,7 @@ class EmoteHandler extends AbstractHandler {
|
|
|
16
16
|
const response = client.events.Emote.handle(packet);
|
|
17
17
|
|
|
18
18
|
/**
|
|
19
|
-
* Emitted when the client
|
|
19
|
+
* Emitted when the client receives an emote packet
|
|
20
20
|
* @event Client#emote
|
|
21
21
|
* @param {Emote} message The created message
|
|
22
22
|
*/
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import AbstractHandler from './AbstractHandler.js';
|
|
2
|
+
import { Events } from '../../../util/Constants.js';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Handles an incoming hackAttempt
|
|
6
|
+
* @private
|
|
7
|
+
*/
|
|
8
|
+
class HackAttemptHandler extends AbstractHandler {
|
|
9
|
+
/**
|
|
10
|
+
* Parses incoming packet data and emits related events
|
|
11
|
+
* @param {object} packet Incoming packet data
|
|
12
|
+
* @returns {void}
|
|
13
|
+
*/
|
|
14
|
+
handle(packet) {
|
|
15
|
+
const { client } = this.packetRouter;
|
|
16
|
+
const response = client.events.HackAttempt.handle(packet);
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Emitted when the client receives a hackAttempt packet
|
|
20
|
+
* @event Client#hackAttempt
|
|
21
|
+
* @param {HackAttemptStruct} message The hack attempt event
|
|
22
|
+
*/
|
|
23
|
+
client.emit(Events.HACK_ATTEMPT, response.message);
|
|
24
|
+
|
|
25
|
+
// Emit debug info
|
|
26
|
+
client.emit(Events.DEBUG, `[${Events.HACK_ATTEMPT}]: ${packet}`);
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export default HackAttemptHandler;
|
|
@@ -16,7 +16,7 @@ class InfoHandler extends AbstractHandler {
|
|
|
16
16
|
const response = client.events.Info.handle(packet);
|
|
17
17
|
|
|
18
18
|
/**
|
|
19
|
-
* Emitted when the client
|
|
19
|
+
* Emitted when the client receives an info packet
|
|
20
20
|
* @event Client#information
|
|
21
21
|
* @param {Information} message The created message
|
|
22
22
|
*/
|
|
@@ -16,7 +16,7 @@ class InviteHandler extends AbstractHandler {
|
|
|
16
16
|
const response = client.events.Invite.handle(packet);
|
|
17
17
|
|
|
18
18
|
/**
|
|
19
|
-
* Emitted when the client
|
|
19
|
+
* Emitted when the client receives an invite packet
|
|
20
20
|
* @event Client#invite
|
|
21
21
|
* @param {Invite} message The created message
|
|
22
22
|
*/
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import AbstractHandler from './AbstractHandler.js';
|
|
2
|
+
import { Events } from '../../../util/Constants.js';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Handles an incoming public channels event
|
|
6
|
+
* @private
|
|
7
|
+
*/
|
|
8
|
+
class PubChannelsHandler extends AbstractHandler {
|
|
9
|
+
/**
|
|
10
|
+
* Parses incoming packet data and emits related events
|
|
11
|
+
* @param {object} packet Incoming packet data
|
|
12
|
+
* @returns {void}
|
|
13
|
+
*/
|
|
14
|
+
handle(packet) {
|
|
15
|
+
const { client } = this.packetRouter;
|
|
16
|
+
const response = client.events.PublicChannels.handle(packet);
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Emitted when the client receives a publicchannels packet
|
|
20
|
+
* @event Client#publicchannels
|
|
21
|
+
* @param {PubChannelsStruct} message The publicchannels event
|
|
22
|
+
*/
|
|
23
|
+
client.emit(Events.PUB_CHANS, response.message);
|
|
24
|
+
|
|
25
|
+
// Emit debug info
|
|
26
|
+
client.emit(Events.DEBUG, `[${Events.PUB_CHANS}]: ${packet}`);
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export default PubChannelsHandler;
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import AbstractHandler from './AbstractHandler.js';
|
|
2
|
+
import { Events } from '../../../util/Constants.js';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Handles an incoming custom `signMessage` event from the server
|
|
6
|
+
* @private
|
|
7
|
+
*/
|
|
8
|
+
class SignMessageHandler extends AbstractHandler {
|
|
9
|
+
/**
|
|
10
|
+
* Parses incoming packet data and emits related events
|
|
11
|
+
* @param {object} packet Incoming packet data
|
|
12
|
+
* @returns {void}
|
|
13
|
+
*/
|
|
14
|
+
handle(packet) {
|
|
15
|
+
const { client } = this.packetRouter;
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Emitted when the server requests the client to sign a message
|
|
19
|
+
* This is used for Sign-In with Solana (SIWS) authentication
|
|
20
|
+
* @event Client#signMessage
|
|
21
|
+
* @param {object} payload The payload containing the wallet and message
|
|
22
|
+
* @param {string} payload.wallet The public key of the wallet to sign with
|
|
23
|
+
* @param {string} payload.message The human-readable message to be signed
|
|
24
|
+
*/
|
|
25
|
+
client.emit(Events.SIGN_MESSAGE, {
|
|
26
|
+
wallet: packet.wallet,
|
|
27
|
+
message: packet.message,
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
client.emit(Events.DEBUG, `[${Events.SIGN_MESSAGE}]: Request received for wallet ${packet.wallet}`);
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export default SignMessageHandler;
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import AbstractHandler from './AbstractHandler.js';
|
|
2
|
+
import { Events } from '../../../util/Constants.js';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Handles an incoming custom `signTransaction` event from the server
|
|
6
|
+
* @private
|
|
7
|
+
*/
|
|
8
|
+
class SignTransactionHandler extends AbstractHandler {
|
|
9
|
+
/**
|
|
10
|
+
* Parses incoming packet data and emits related events
|
|
11
|
+
* @param {object} packet Incoming packet data
|
|
12
|
+
* @returns {void}
|
|
13
|
+
*/
|
|
14
|
+
handle(packet) {
|
|
15
|
+
const { client } = this.packetRouter;
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Emitted when the server requests the client to sign a transaction
|
|
19
|
+
* @event Client#signTransaction
|
|
20
|
+
* @param {object} payload The payload containing the tx and type
|
|
21
|
+
* @param {string} payload.tx The base64 encoded transaction payload
|
|
22
|
+
* @param {string} payload.type The transaction type
|
|
23
|
+
* @param {string} payload.channel The channel which invoked the event
|
|
24
|
+
*/
|
|
25
|
+
client.emit(Events.SIGN_TRANSACTION, {
|
|
26
|
+
tx: packet.tx,
|
|
27
|
+
type: packet.type,
|
|
28
|
+
channel: packet.channel,
|
|
29
|
+
from: packet.from,
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
client.emit(Events.DEBUG, `[${Events.SIGN_TRANSACTION}]: signTransaction requested`);
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
export default SignTransactionHandler;
|
|
@@ -16,7 +16,7 @@ class WhisperHandler extends AbstractHandler {
|
|
|
16
16
|
const response = client.events.Whisper.handle(packet);
|
|
17
17
|
|
|
18
18
|
/**
|
|
19
|
-
* Emitted when the client
|
|
19
|
+
* Emitted when the client receives a whisper packet
|
|
20
20
|
* @event Client#whisper
|
|
21
21
|
* @param {WhisperStruct} message The whisper event
|
|
22
22
|
*/
|