crisp-api 9.13.0 → 10.0.2
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/CHANGELOG.md +8 -0
- package/README.md +2 -2
- package/dist/crisp.d.ts +167 -0
- package/dist/crisp.js +764 -0
- package/dist/resources/BaseResource.d.ts +15 -0
- package/dist/resources/BaseResource.js +20 -0
- package/dist/resources/BucketURL.d.ts +28 -0
- package/dist/resources/BucketURL.js +29 -0
- package/dist/resources/MediaAnimation.d.ts +14 -0
- package/dist/resources/MediaAnimation.js +32 -0
- package/dist/resources/PluginConnect.d.ts +50 -0
- package/dist/resources/PluginConnect.js +73 -0
- package/dist/resources/PluginSubscription.d.ts +103 -0
- package/dist/resources/PluginSubscription.js +122 -0
- package/dist/resources/WebsiteAnalytics.d.ts +14 -0
- package/dist/resources/WebsiteAnalytics.js +29 -0
- package/dist/resources/WebsiteAvailability.d.ts +31 -0
- package/dist/resources/WebsiteAvailability.js +36 -0
- package/dist/resources/WebsiteBase.d.ts +60 -0
- package/dist/resources/WebsiteBase.js +71 -0
- package/dist/resources/WebsiteBatch.d.ts +52 -0
- package/dist/resources/WebsiteBatch.js +70 -0
- package/dist/resources/WebsiteCampaign.d.ts +199 -0
- package/dist/resources/WebsiteCampaign.js +194 -0
- package/dist/resources/WebsiteConversation.d.ts +701 -0
- package/dist/resources/WebsiteConversation.js +595 -0
- package/dist/resources/WebsiteHelpdesk.d.ts +347 -0
- package/dist/resources/WebsiteHelpdesk.js +587 -0
- package/dist/resources/WebsiteOperator.d.ts +79 -0
- package/dist/resources/WebsiteOperator.js +93 -0
- package/dist/resources/WebsitePeople.d.ts +248 -0
- package/dist/resources/WebsitePeople.js +276 -0
- package/dist/resources/WebsiteSettings.d.ts +159 -0
- package/dist/resources/WebsiteSettings.js +36 -0
- package/dist/resources/WebsiteVerify.d.ts +38 -0
- package/dist/resources/WebsiteVerify.js +50 -0
- package/dist/resources/WebsiteVisitors.d.ts +113 -0
- package/dist/resources/WebsiteVisitors.js +88 -0
- package/dist/resources/index.d.ts +17 -0
- package/dist/resources/index.js +40 -0
- package/dist/services/bucket.d.ts +13 -0
- package/dist/services/bucket.js +28 -0
- package/dist/services/media.d.ts +13 -0
- package/dist/services/media.js +28 -0
- package/dist/services/plugin.d.ts +14 -0
- package/dist/services/plugin.js +30 -0
- package/dist/services/website.d.ts +24 -0
- package/dist/services/website.js +50 -0
- package/eslint.config.mjs +208 -0
- package/lib/crisp.ts +957 -0
- package/lib/resources/BaseResource.ts +29 -0
- package/lib/resources/BucketURL.ts +49 -0
- package/lib/resources/MediaAnimation.ts +34 -0
- package/lib/resources/PluginConnect.ts +128 -0
- package/lib/resources/PluginSubscription.ts +208 -0
- package/lib/resources/WebsiteAnalytics.ts +31 -0
- package/lib/resources/WebsiteAvailability.ts +54 -0
- package/lib/resources/WebsiteBase.ts +108 -0
- package/lib/resources/WebsiteBatch.ts +96 -0
- package/lib/resources/WebsiteCampaign.ts +399 -0
- package/lib/resources/WebsiteConversation.ts +1416 -0
- package/lib/resources/WebsiteHelpdesk.ts +982 -0
- package/lib/resources/WebsiteOperator.ts +161 -0
- package/lib/resources/WebsitePeople.ts +527 -0
- package/lib/resources/WebsiteSettings.ts +192 -0
- package/lib/resources/WebsiteVerify.ts +76 -0
- package/lib/resources/WebsiteVisitors.ts +196 -0
- package/lib/resources/index.ts +25 -0
- package/lib/services/bucket.ts +28 -0
- package/lib/services/media.ts +28 -0
- package/lib/services/plugin.ts +32 -0
- package/lib/services/website.ts +62 -0
- package/package.json +16 -11
- package/tsconfig.json +12 -5
- package/lib/crisp.js +0 -1171
- package/lib/resources/BucketURL.js +0 -34
- package/lib/resources/MediaAnimation.js +0 -41
- package/lib/resources/PluginConnect.js +0 -119
- package/lib/resources/PluginSubscription.js +0 -234
- package/lib/resources/WebsiteAnalytics.js +0 -37
- package/lib/resources/WebsiteAvailability.js +0 -48
- package/lib/resources/WebsiteBase.js +0 -100
- package/lib/resources/WebsiteBatch.js +0 -92
- package/lib/resources/WebsiteCampaign.js +0 -396
- package/lib/resources/WebsiteConversation.js +0 -1261
- package/lib/resources/WebsiteHelpdesk.js +0 -1198
- package/lib/resources/WebsiteOperator.js +0 -167
- package/lib/resources/WebsitePeople.js +0 -516
- package/lib/resources/WebsiteSettings.js +0 -50
- package/lib/resources/WebsiteVerify.js +0 -79
- package/lib/resources/WebsiteVisitors.js +0 -148
- package/lib/services/Bucket.js +0 -28
- package/lib/services/Media.js +0 -28
- package/lib/services/Plugin.js +0 -29
- package/lib/services/Website.js +0 -39
- package/types/crisp.d.ts +0 -151
- package/types/resources/BucketURL.d.ts +0 -15
- package/types/resources/MediaAnimation.d.ts +0 -15
- package/types/resources/PluginConnect.d.ts +0 -15
- package/types/resources/PluginSubscription.d.ts +0 -15
- package/types/resources/WebsiteAnalytics.d.ts +0 -15
- package/types/resources/WebsiteAvailability.d.ts +0 -15
- package/types/resources/WebsiteBase.d.ts +0 -15
- package/types/resources/WebsiteBatch.d.ts +0 -15
- package/types/resources/WebsiteCampaign.d.ts +0 -15
- package/types/resources/WebsiteConversation.d.ts +0 -15
- package/types/resources/WebsiteHelpdesk.d.ts +0 -15
- package/types/resources/WebsiteOperator.d.ts +0 -15
- package/types/resources/WebsitePeople.d.ts +0 -15
- package/types/resources/WebsiteSettings.d.ts +0 -15
- package/types/resources/WebsiteVerify.d.ts +0 -15
- package/types/resources/WebsiteVisitors.d.ts +0 -15
- package/types/services/Bucket.d.ts +0 -14
- package/types/services/Media.d.ts +0 -14
- package/types/services/Plugin.d.ts +0 -14
- package/types/services/Website.d.ts +0 -14
package/lib/crisp.js
DELETED
|
@@ -1,1171 +0,0 @@
|
|
|
1
|
-
/*
|
|
2
|
-
* node-crisp-api
|
|
3
|
-
*
|
|
4
|
-
* Copyright 2022, Crisp IM SAS
|
|
5
|
-
* Author: Baptiste Jamin <baptiste@crisp.chat>
|
|
6
|
-
*/
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
"use strict";
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
// Imports
|
|
13
|
-
var pkg = require("../package.json");
|
|
14
|
-
var got = require("got");
|
|
15
|
-
|
|
16
|
-
var URL = require("url").URL;
|
|
17
|
-
var Crypto = require("crypto");
|
|
18
|
-
var EventEmitter = require("fbemitter").EventEmitter;
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
// RTM modes available
|
|
22
|
-
Crisp.RTM_MODES = {
|
|
23
|
-
WebSockets : "websockets",
|
|
24
|
-
WebHooks : "webhooks"
|
|
25
|
-
};
|
|
26
|
-
|
|
27
|
-
Crisp.AVAILABLE_RTM_MODES = [
|
|
28
|
-
Crisp.RTM_MODES.WebSockets,
|
|
29
|
-
Crisp.RTM_MODES.WebHooks
|
|
30
|
-
];
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
// Base configuration
|
|
34
|
-
Crisp.DEFAULT_REQUEST_TIMEOUT = 10000;
|
|
35
|
-
Crisp.DEFAULT_SOCKET_TIMEOUT = 10000;
|
|
36
|
-
Crisp.DEFAULT_SOCKET_RECONNECT_DELAY = 5000;
|
|
37
|
-
Crisp.DEFAULT_SOCKET_RECONNECT_DELAY_MAX = 10000;
|
|
38
|
-
Crisp.DEFAULT_SOCKET_RECONNECT_FACTOR = 0.75;
|
|
39
|
-
Crisp.DEFAULT_BROKER_SCHEDULE = 500;
|
|
40
|
-
Crisp.DEFAULT_EVENT_REBIND_INTERVAL_MIN = 2500;
|
|
41
|
-
Crisp.DEFAULT_USERAGENT_PREFIX = "node-crisp-api/";
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
// REST API defaults
|
|
45
|
-
Crisp.DEFAULT_REST_HOST = "https://api.crisp.chat";
|
|
46
|
-
Crisp.DEFAULT_REST_BASE_PATH = "/v1/";
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
// RTM API defaults
|
|
50
|
-
Crisp.DEFAULT_RTM_MODE = Crisp.RTM_MODES.WebSockets;
|
|
51
|
-
|
|
52
|
-
Crisp.DEFAULT_RTM_EVENTS = [
|
|
53
|
-
// Session Events
|
|
54
|
-
"session:update_availability",
|
|
55
|
-
"session:update_verify",
|
|
56
|
-
"session:request:initiated",
|
|
57
|
-
"session:set_email",
|
|
58
|
-
"session:set_phone",
|
|
59
|
-
"session:set_address",
|
|
60
|
-
"session:set_subject",
|
|
61
|
-
"session:set_avatar",
|
|
62
|
-
"session:set_nickname",
|
|
63
|
-
"session:set_origin",
|
|
64
|
-
"session:set_data",
|
|
65
|
-
"session:sync:pages",
|
|
66
|
-
"session:sync:events",
|
|
67
|
-
"session:sync:capabilities",
|
|
68
|
-
"session:sync:geolocation",
|
|
69
|
-
"session:sync:system",
|
|
70
|
-
"session:sync:network",
|
|
71
|
-
"session:sync:timezone",
|
|
72
|
-
"session:sync:locales",
|
|
73
|
-
"session:sync:rating",
|
|
74
|
-
"session:sync:topic",
|
|
75
|
-
"session:set_state",
|
|
76
|
-
"session:set_block",
|
|
77
|
-
"session:set_segments",
|
|
78
|
-
"session:set_opened",
|
|
79
|
-
"session:set_closed",
|
|
80
|
-
"session:set_participants",
|
|
81
|
-
"session:set_mentions",
|
|
82
|
-
"session:set_routing",
|
|
83
|
-
"session:set_inbox",
|
|
84
|
-
"session:removed",
|
|
85
|
-
"session:error",
|
|
86
|
-
|
|
87
|
-
// Message Events
|
|
88
|
-
"message:updated",
|
|
89
|
-
"message:send",
|
|
90
|
-
"message:received",
|
|
91
|
-
"message:removed",
|
|
92
|
-
"message:compose:send",
|
|
93
|
-
"message:compose:receive",
|
|
94
|
-
"message:acknowledge:read:send",
|
|
95
|
-
"message:acknowledge:read:received",
|
|
96
|
-
"message:acknowledge:unread:send",
|
|
97
|
-
"message:acknowledge:delivered",
|
|
98
|
-
"message:acknowledge:ignored",
|
|
99
|
-
"message:notify:unread:send",
|
|
100
|
-
"message:notify:unread:received",
|
|
101
|
-
|
|
102
|
-
// Spam Events
|
|
103
|
-
"spam:message",
|
|
104
|
-
"spam:decision",
|
|
105
|
-
|
|
106
|
-
// People Events
|
|
107
|
-
"people:profile:created",
|
|
108
|
-
"people:profile:updated",
|
|
109
|
-
"people:profile:removed",
|
|
110
|
-
"people:bind:session",
|
|
111
|
-
"people:sync:profile",
|
|
112
|
-
"people:import:progress",
|
|
113
|
-
"people:import:done",
|
|
114
|
-
|
|
115
|
-
// Campaign Events
|
|
116
|
-
"campaign:progress",
|
|
117
|
-
"campaign:dispatched",
|
|
118
|
-
"campaign:running",
|
|
119
|
-
|
|
120
|
-
// Browsing Events
|
|
121
|
-
"browsing:request:initiated",
|
|
122
|
-
"browsing:request:rejected",
|
|
123
|
-
|
|
124
|
-
// Call Events
|
|
125
|
-
"call:request:initiated",
|
|
126
|
-
"call:request:rejected",
|
|
127
|
-
|
|
128
|
-
// Identity Events
|
|
129
|
-
"identity:verify:request",
|
|
130
|
-
|
|
131
|
-
// Status Events
|
|
132
|
-
"status:health:changed",
|
|
133
|
-
|
|
134
|
-
// Website Event
|
|
135
|
-
"website:update_visitors_count",
|
|
136
|
-
"website:update_operators_availability",
|
|
137
|
-
"website:users:available",
|
|
138
|
-
|
|
139
|
-
// Bucket Events
|
|
140
|
-
"bucket:url:upload:generated",
|
|
141
|
-
"bucket:url:avatar:generated",
|
|
142
|
-
"bucket:url:website:generated",
|
|
143
|
-
"bucket:url:campaign:generated",
|
|
144
|
-
"bucket:url:helpdesk:generated",
|
|
145
|
-
"bucket:url:status:generated",
|
|
146
|
-
"bucket:url:processing:generated",
|
|
147
|
-
"bucket:url:crawler:generated",
|
|
148
|
-
|
|
149
|
-
// Media Events
|
|
150
|
-
"media:animation:listed",
|
|
151
|
-
|
|
152
|
-
// Email Event
|
|
153
|
-
"email:subscribe",
|
|
154
|
-
"email:track:view",
|
|
155
|
-
|
|
156
|
-
// Plugin Events
|
|
157
|
-
"plugin:channel",
|
|
158
|
-
"plugin:event",
|
|
159
|
-
"plugin:settings:saved",
|
|
160
|
-
];
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
// REST API services
|
|
164
|
-
var services = {
|
|
165
|
-
Bucket : require("./services/Bucket"),
|
|
166
|
-
Media : require("./services/Media"),
|
|
167
|
-
Plugin : require("./services/Plugin"),
|
|
168
|
-
Website : require("./services/Website")
|
|
169
|
-
};
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
/**
|
|
173
|
-
* Crisp API Library
|
|
174
|
-
* @class
|
|
175
|
-
* @classdesc This is the Crisp Library. Handles REST and RTM operations
|
|
176
|
-
*/
|
|
177
|
-
function Crisp() {
|
|
178
|
-
/**
|
|
179
|
-
* @public
|
|
180
|
-
* @type {*}
|
|
181
|
-
*/
|
|
182
|
-
this.bucket = {};
|
|
183
|
-
|
|
184
|
-
/**
|
|
185
|
-
* @public
|
|
186
|
-
* @type {*}
|
|
187
|
-
*/
|
|
188
|
-
this.media = {};
|
|
189
|
-
|
|
190
|
-
/**
|
|
191
|
-
* @public
|
|
192
|
-
* @type {*}
|
|
193
|
-
*/
|
|
194
|
-
this.plugin = {};
|
|
195
|
-
|
|
196
|
-
/**
|
|
197
|
-
* @public
|
|
198
|
-
* @type {*}
|
|
199
|
-
*/
|
|
200
|
-
this.website = {};
|
|
201
|
-
|
|
202
|
-
/**
|
|
203
|
-
* @public
|
|
204
|
-
* @type {object}
|
|
205
|
-
*/
|
|
206
|
-
this.auth = {
|
|
207
|
-
tier : "user",
|
|
208
|
-
identifier : null,
|
|
209
|
-
key : null,
|
|
210
|
-
token : null
|
|
211
|
-
};
|
|
212
|
-
|
|
213
|
-
/**
|
|
214
|
-
* @private
|
|
215
|
-
* @type {object}
|
|
216
|
-
*/
|
|
217
|
-
this._rest = {
|
|
218
|
-
host : Crisp.DEFAULT_REST_HOST,
|
|
219
|
-
basePath : Crisp.DEFAULT_REST_BASE_PATH
|
|
220
|
-
};
|
|
221
|
-
|
|
222
|
-
/**
|
|
223
|
-
* @private
|
|
224
|
-
* @type {object}
|
|
225
|
-
*/
|
|
226
|
-
this._rtm = {
|
|
227
|
-
host : null,
|
|
228
|
-
mode : Crisp.DEFAULT_RTM_MODE
|
|
229
|
-
};
|
|
230
|
-
|
|
231
|
-
/**
|
|
232
|
-
* @private
|
|
233
|
-
* @type {string}
|
|
234
|
-
*/
|
|
235
|
-
this._useragent = (Crisp.DEFAULT_USERAGENT_PREFIX + pkg.version);
|
|
236
|
-
|
|
237
|
-
/**
|
|
238
|
-
* @private
|
|
239
|
-
* @type {object}
|
|
240
|
-
*/
|
|
241
|
-
this._emitter = new EventEmitter();
|
|
242
|
-
|
|
243
|
-
/**
|
|
244
|
-
* @private
|
|
245
|
-
* @type {object|null}
|
|
246
|
-
*/
|
|
247
|
-
this._socket = null;
|
|
248
|
-
|
|
249
|
-
/**
|
|
250
|
-
* @private
|
|
251
|
-
* @type {object|null}
|
|
252
|
-
*/
|
|
253
|
-
this._loopback = null;
|
|
254
|
-
|
|
255
|
-
/**
|
|
256
|
-
* @private
|
|
257
|
-
* @type {number|null}
|
|
258
|
-
*/
|
|
259
|
-
this._lastEventRebind = null;
|
|
260
|
-
|
|
261
|
-
/**
|
|
262
|
-
* @private
|
|
263
|
-
* @type {object|null}
|
|
264
|
-
*/
|
|
265
|
-
this._brokerScheduler = null;
|
|
266
|
-
|
|
267
|
-
/**
|
|
268
|
-
* @private
|
|
269
|
-
* @type {Array}
|
|
270
|
-
*/
|
|
271
|
-
this._brokerBindHooks = [];
|
|
272
|
-
|
|
273
|
-
/**
|
|
274
|
-
* @private
|
|
275
|
-
* @type {object}
|
|
276
|
-
*/
|
|
277
|
-
this._boundEvents = {};
|
|
278
|
-
|
|
279
|
-
// Prepare
|
|
280
|
-
this._prepareServices();
|
|
281
|
-
}
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
Crisp.prototype = {
|
|
285
|
-
/**
|
|
286
|
-
* Sets the REST API host
|
|
287
|
-
* @memberof Crisp
|
|
288
|
-
* @public
|
|
289
|
-
* @method setRestHost
|
|
290
|
-
* @param {string} host - Hostname
|
|
291
|
-
* @return {undefined}
|
|
292
|
-
*/
|
|
293
|
-
setRestHost : function(host) {
|
|
294
|
-
if (typeof host === "string") {
|
|
295
|
-
this._rest.host = host;
|
|
296
|
-
} else {
|
|
297
|
-
throw new Error("[Crisp] setRestHost: parameter host should be a string");
|
|
298
|
-
}
|
|
299
|
-
},
|
|
300
|
-
|
|
301
|
-
/**
|
|
302
|
-
* Sets the RTM API host
|
|
303
|
-
* @memberof Crisp
|
|
304
|
-
* @public
|
|
305
|
-
* @method setRtmHost
|
|
306
|
-
* @param {string} host - Hostname
|
|
307
|
-
* @return {undefined}
|
|
308
|
-
*/
|
|
309
|
-
setRtmHost : function(host) {
|
|
310
|
-
if (typeof host === "string") {
|
|
311
|
-
this._rtm.host = host;
|
|
312
|
-
} else {
|
|
313
|
-
throw new Error("[Crisp] setRtmHost: parameter host should be a string");
|
|
314
|
-
}
|
|
315
|
-
},
|
|
316
|
-
|
|
317
|
-
/**
|
|
318
|
-
* Sets the RTM channel mode (ie. WebSockets or Web Hooks)
|
|
319
|
-
* @memberof Crisp
|
|
320
|
-
* @public
|
|
321
|
-
* @method setRtmMode
|
|
322
|
-
* @param {string} mode - RTM mode ('websockets' or 'webhooks')
|
|
323
|
-
* @return {undefined}
|
|
324
|
-
*/
|
|
325
|
-
setRtmMode : function(mode) {
|
|
326
|
-
if (Crisp.AVAILABLE_RTM_MODES.indexOf(mode) !== -1) {
|
|
327
|
-
this._rtm.mode = mode;
|
|
328
|
-
} else {
|
|
329
|
-
throw new Error(
|
|
330
|
-
"[Crisp] setRtmMode: parameter mode value should be one of: " +
|
|
331
|
-
Crisp.AVAILABLE_RTM_MODES.join(", ")
|
|
332
|
-
);
|
|
333
|
-
}
|
|
334
|
-
},
|
|
335
|
-
|
|
336
|
-
/**
|
|
337
|
-
* Sets the authentication tier
|
|
338
|
-
* @memberof Crisp
|
|
339
|
-
* @public
|
|
340
|
-
* @method setTier
|
|
341
|
-
* @param {string} tier
|
|
342
|
-
* @return {undefined}
|
|
343
|
-
*/
|
|
344
|
-
setTier : function(tier) {
|
|
345
|
-
this.auth.tier = (tier || "user");
|
|
346
|
-
},
|
|
347
|
-
|
|
348
|
-
/**
|
|
349
|
-
* Authenticates
|
|
350
|
-
* @memberof Crisp
|
|
351
|
-
* @public
|
|
352
|
-
* @method authenticate
|
|
353
|
-
* @param {string} identifier
|
|
354
|
-
* @param {string} key
|
|
355
|
-
* @return {undefined}
|
|
356
|
-
*/
|
|
357
|
-
authenticate : function(identifier, key) {
|
|
358
|
-
var auth = this.auth;
|
|
359
|
-
|
|
360
|
-
// Store credentials
|
|
361
|
-
auth.identifier = identifier;
|
|
362
|
-
auth.key = key;
|
|
363
|
-
|
|
364
|
-
// Assign pre-computed authentication token
|
|
365
|
-
auth.token = Buffer.from(identifier + ":" + key).toString("base64");
|
|
366
|
-
},
|
|
367
|
-
|
|
368
|
-
/**
|
|
369
|
-
* Authenticates (with tier)
|
|
370
|
-
* @memberof Crisp
|
|
371
|
-
* @public
|
|
372
|
-
* @method authenticateTier
|
|
373
|
-
* @param {string} tier
|
|
374
|
-
* @param {string} identifier
|
|
375
|
-
* @param {string} key
|
|
376
|
-
* @return {undefined}
|
|
377
|
-
*/
|
|
378
|
-
authenticateTier : function(tier, identifier, key) {
|
|
379
|
-
this.setTier(tier);
|
|
380
|
-
this.authenticate(identifier, key);
|
|
381
|
-
},
|
|
382
|
-
|
|
383
|
-
/**
|
|
384
|
-
* Method wrapper to HEAD a resource
|
|
385
|
-
* @memberof Crisp
|
|
386
|
-
* @public
|
|
387
|
-
* @method head
|
|
388
|
-
* @param {string} resource
|
|
389
|
-
* @param {object} query
|
|
390
|
-
* @param {object} body
|
|
391
|
-
* @return {Promise}
|
|
392
|
-
*/
|
|
393
|
-
head : function(resource, query, body) {
|
|
394
|
-
var self = this;
|
|
395
|
-
|
|
396
|
-
return new Promise(function(resolve, reject) {
|
|
397
|
-
self._request(
|
|
398
|
-
resource, "head", (query || {}), null, resolve, reject
|
|
399
|
-
);
|
|
400
|
-
});
|
|
401
|
-
},
|
|
402
|
-
|
|
403
|
-
/**
|
|
404
|
-
* Method wrapper to GET a resource
|
|
405
|
-
* @memberof Crisp
|
|
406
|
-
* @public
|
|
407
|
-
* @method get
|
|
408
|
-
* @param {string} resource
|
|
409
|
-
* @param {object} query
|
|
410
|
-
* @param {object} body
|
|
411
|
-
* @return {Promise}
|
|
412
|
-
*/
|
|
413
|
-
get : function(resource, query) {
|
|
414
|
-
var self = this;
|
|
415
|
-
|
|
416
|
-
return new Promise(function(resolve, reject) {
|
|
417
|
-
self._request(
|
|
418
|
-
resource, "get", (query || {}), null, resolve, reject
|
|
419
|
-
);
|
|
420
|
-
});
|
|
421
|
-
},
|
|
422
|
-
|
|
423
|
-
/**
|
|
424
|
-
* Method wrapper to POST a resource
|
|
425
|
-
* @memberof Crisp
|
|
426
|
-
* @public
|
|
427
|
-
* @method post
|
|
428
|
-
* @param {string} resource
|
|
429
|
-
* @param {object} query
|
|
430
|
-
* @param {object} body
|
|
431
|
-
* @return {Promise}
|
|
432
|
-
*/
|
|
433
|
-
post : function(resource, query, body) {
|
|
434
|
-
var self = this;
|
|
435
|
-
|
|
436
|
-
return new Promise(function(resolve, reject) {
|
|
437
|
-
self._request(
|
|
438
|
-
resource, "post", (query || {}), (body || {}), resolve, reject
|
|
439
|
-
);
|
|
440
|
-
});
|
|
441
|
-
},
|
|
442
|
-
|
|
443
|
-
/**
|
|
444
|
-
* Method wrapper to PATCH a resource
|
|
445
|
-
* @memberof Crisp
|
|
446
|
-
* @public
|
|
447
|
-
* @method patch
|
|
448
|
-
* @param {string} resource
|
|
449
|
-
* @param {object} query
|
|
450
|
-
* @param {object} body
|
|
451
|
-
* @return {Promise}
|
|
452
|
-
*/
|
|
453
|
-
patch : function(resource, query, body) {
|
|
454
|
-
var self = this;
|
|
455
|
-
|
|
456
|
-
return new Promise(function(resolve, reject) {
|
|
457
|
-
self._request(
|
|
458
|
-
resource, "patch", (query || {}), (body || {}), resolve, reject
|
|
459
|
-
);
|
|
460
|
-
});
|
|
461
|
-
},
|
|
462
|
-
|
|
463
|
-
/**
|
|
464
|
-
* Method wrapper to PUT a resource
|
|
465
|
-
* @memberof Crisp
|
|
466
|
-
* @public
|
|
467
|
-
* @method put
|
|
468
|
-
* @param {string} resource
|
|
469
|
-
* @param {object} query
|
|
470
|
-
* @param {object} body
|
|
471
|
-
* @return {Promise}
|
|
472
|
-
*/
|
|
473
|
-
put : function(resource, query, body) {
|
|
474
|
-
var self = this;
|
|
475
|
-
|
|
476
|
-
return new Promise(function(resolve, reject) {
|
|
477
|
-
self._request(
|
|
478
|
-
resource, "put", (query || {}), (body || {}), resolve, reject
|
|
479
|
-
);
|
|
480
|
-
});
|
|
481
|
-
},
|
|
482
|
-
|
|
483
|
-
/**
|
|
484
|
-
* Method wrapper to DELETE a resource
|
|
485
|
-
* @memberof Crisp
|
|
486
|
-
* @public
|
|
487
|
-
* @method delete
|
|
488
|
-
* @param {string} resource
|
|
489
|
-
* @param {object} query
|
|
490
|
-
* @param {object} body
|
|
491
|
-
* @return {Promise}
|
|
492
|
-
*/
|
|
493
|
-
delete : function(resource, query, body) {
|
|
494
|
-
var self = this;
|
|
495
|
-
|
|
496
|
-
return new Promise(function(resolve, reject) {
|
|
497
|
-
self._request(
|
|
498
|
-
resource, "delete", (query || {}), (body || null), resolve, reject
|
|
499
|
-
);
|
|
500
|
-
});
|
|
501
|
-
},
|
|
502
|
-
|
|
503
|
-
/**
|
|
504
|
-
* Binds RTM event
|
|
505
|
-
* @memberof Crisp
|
|
506
|
-
* @public
|
|
507
|
-
* @method on
|
|
508
|
-
* @param {string} event
|
|
509
|
-
* @param {function} callback
|
|
510
|
-
* @return {Promise}
|
|
511
|
-
*/
|
|
512
|
-
on : function(event, callback) {
|
|
513
|
-
// Ensure all input arguments are set
|
|
514
|
-
if (typeof event !== "string") {
|
|
515
|
-
throw new Error("[Crisp] on: parameter event should be a string");
|
|
516
|
-
}
|
|
517
|
-
if (typeof callback !== "function") {
|
|
518
|
-
throw new Error("[Crisp] on: parameter callback should be a function");
|
|
519
|
-
}
|
|
520
|
-
|
|
521
|
-
// Disallow unrecognized event names
|
|
522
|
-
if (Crisp.DEFAULT_RTM_EVENTS.indexOf(event) === -1) {
|
|
523
|
-
throw new Error(
|
|
524
|
-
"[Crisp] on: parameter event value is not recognized: '" + event + "'"
|
|
525
|
-
);
|
|
526
|
-
}
|
|
527
|
-
|
|
528
|
-
// Important: we do not allow .on() to be called once socket is connected, \
|
|
529
|
-
// or loopback is bound as we consider event listeners must be bound \
|
|
530
|
-
// once all together. This prevents bogous integrations from sending \
|
|
531
|
-
// flood of 'socket:bind'` to the RTM API, if using WebSockets. Web \
|
|
532
|
-
// Hooks follows the same scheme for consistency's sake.
|
|
533
|
-
if (this._socket || this._loopback) {
|
|
534
|
-
throw new Error(
|
|
535
|
-
"[Crisp] on: connector is already bound, please listen to event " +
|
|
536
|
-
"earlier on: '" + event + "'"
|
|
537
|
-
);
|
|
538
|
-
}
|
|
539
|
-
|
|
540
|
-
// Add listener to emitter
|
|
541
|
-
this._emitter.addListener(event, callback);
|
|
542
|
-
|
|
543
|
-
// Subscribe event on the broker
|
|
544
|
-
if (this._boundEvents[event] !== true) {
|
|
545
|
-
var rtmMode = this._rtm.mode;
|
|
546
|
-
|
|
547
|
-
// Mark event as bound
|
|
548
|
-
this._boundEvents[event] = true;
|
|
549
|
-
|
|
550
|
-
// Broker not connected? Connect now.
|
|
551
|
-
return this._prepareBroker(
|
|
552
|
-
function(instance, emitter) {
|
|
553
|
-
// Listen for event? (once instance is bound)
|
|
554
|
-
switch (rtmMode) {
|
|
555
|
-
case Crisp.RTM_MODES.WebSockets: {
|
|
556
|
-
// Listen on socket event
|
|
557
|
-
instance.on(event, function(data) {
|
|
558
|
-
emitter.emit(event, data);
|
|
559
|
-
});
|
|
560
|
-
|
|
561
|
-
break;
|
|
562
|
-
}
|
|
563
|
-
}
|
|
564
|
-
}
|
|
565
|
-
);
|
|
566
|
-
}
|
|
567
|
-
|
|
568
|
-
return Promise.resolve();
|
|
569
|
-
},
|
|
570
|
-
|
|
571
|
-
/**
|
|
572
|
-
* Receives a raw event and dispatches it to the listener (used for Web Hooks)
|
|
573
|
-
* @memberof Crisp
|
|
574
|
-
* @public
|
|
575
|
-
* @method receiveHook
|
|
576
|
-
* @param {object} body
|
|
577
|
-
* @return {undefined}
|
|
578
|
-
*/
|
|
579
|
-
receiveHook : function(body) {
|
|
580
|
-
var self = this;
|
|
581
|
-
|
|
582
|
-
if (self._loopback) {
|
|
583
|
-
// Ensure payload is readable
|
|
584
|
-
if (!body || typeof body !== "object") {
|
|
585
|
-
return new Error("[Crisp] receiveHook: empty hook payload");
|
|
586
|
-
}
|
|
587
|
-
|
|
588
|
-
// Ensure payload is properly formatted
|
|
589
|
-
if (!body.event || !body.data ||
|
|
590
|
-
typeof body.event !== "string" || typeof body.data !== "object") {
|
|
591
|
-
return new Error("[Crisp] receiveHook: malformatted hook payload");
|
|
592
|
-
}
|
|
593
|
-
|
|
594
|
-
// Check if event is subscribed to? (in routing table)
|
|
595
|
-
// Notice: if not in routing table, then silently discard the event w/o \
|
|
596
|
-
// any error, as we do not want an HTTP failure status to be sent in \
|
|
597
|
-
// response by the implementor.
|
|
598
|
-
if (self._boundEvents[body.event] !== true) {
|
|
599
|
-
return null;
|
|
600
|
-
}
|
|
601
|
-
|
|
602
|
-
// Dispatch event to event bus
|
|
603
|
-
// Notice: go asynchronous, so that the event is processed ASAP and \
|
|
604
|
-
// dispatched on the event bus later, as the hook might be received \
|
|
605
|
-
// synchronously over HTTP.
|
|
606
|
-
process.nextTick(function() {
|
|
607
|
-
self._loopback.emit(body.event, body.data);
|
|
608
|
-
});
|
|
609
|
-
|
|
610
|
-
return null;
|
|
611
|
-
}
|
|
612
|
-
|
|
613
|
-
return new Error("[Crisp] receiveHook: hook loopback not bound");
|
|
614
|
-
},
|
|
615
|
-
|
|
616
|
-
/**
|
|
617
|
-
* Verifies an event string and checks that signatures match (used for Web \
|
|
618
|
-
* Hooks)
|
|
619
|
-
* @memberof Crisp
|
|
620
|
-
* @public
|
|
621
|
-
* @method verifyHook
|
|
622
|
-
* @param {string} secret
|
|
623
|
-
* @param {object} body
|
|
624
|
-
* @param {string} timestamp
|
|
625
|
-
* @param {string} signature
|
|
626
|
-
* @return {boolean}
|
|
627
|
-
*/
|
|
628
|
-
verifyHook : function(secret, body, timestamp, signature) {
|
|
629
|
-
if (this._loopback) {
|
|
630
|
-
return this._verifySignature(secret, body, timestamp, signature);
|
|
631
|
-
}
|
|
632
|
-
|
|
633
|
-
// Default: not verified (loopback not /yet?/ bound)
|
|
634
|
-
return false;
|
|
635
|
-
},
|
|
636
|
-
|
|
637
|
-
/**
|
|
638
|
-
* Verifies an event string and checks that signatures match (used for \
|
|
639
|
-
* Widgets)
|
|
640
|
-
* @memberof Crisp
|
|
641
|
-
* @public
|
|
642
|
-
* @method verifyWidget
|
|
643
|
-
* @param {string} secret
|
|
644
|
-
* @param {object} body
|
|
645
|
-
* @param {string} timestamp
|
|
646
|
-
* @param {string} signature
|
|
647
|
-
* @return {boolean}
|
|
648
|
-
*/
|
|
649
|
-
verifyWidget : function(secret, body, timestamp, signature) {
|
|
650
|
-
return this._verifySignature(secret, body, timestamp, signature);
|
|
651
|
-
},
|
|
652
|
-
|
|
653
|
-
/**
|
|
654
|
-
* Rebinds socket events (used for WebSockets)
|
|
655
|
-
* @memberof Crisp
|
|
656
|
-
* @public
|
|
657
|
-
* @method rebind
|
|
658
|
-
* @return {Promise}
|
|
659
|
-
*/
|
|
660
|
-
rebindSocket : function() {
|
|
661
|
-
var self = this;
|
|
662
|
-
|
|
663
|
-
if (!self._socket) {
|
|
664
|
-
throw new Error(
|
|
665
|
-
"[Crisp] rebindSocket: cannot rebind a socket that is not yet bound"
|
|
666
|
-
);
|
|
667
|
-
}
|
|
668
|
-
|
|
669
|
-
// Make sure that the library user is not rebinding too frequently (which \
|
|
670
|
-
// is illegal)
|
|
671
|
-
var nowTime = Date.now();
|
|
672
|
-
|
|
673
|
-
if (self._lastEventRebind !== null &&
|
|
674
|
-
((nowTime - self._lastEventRebind) <
|
|
675
|
-
Crisp.DEFAULT_EVENT_REBIND_INTERVAL_MIN)) {
|
|
676
|
-
throw new Error(
|
|
677
|
-
"[Crisp] rebindSocket: cannot rebind, last rebind was requested too " +
|
|
678
|
-
"recently"
|
|
679
|
-
);
|
|
680
|
-
}
|
|
681
|
-
|
|
682
|
-
return Promise.resolve()
|
|
683
|
-
.then(function() {
|
|
684
|
-
// Rebind to socket events (eg. newly bound websites)
|
|
685
|
-
self._lastEventRebind = nowTime;
|
|
686
|
-
|
|
687
|
-
self._socket.emit("socket:bind", {});
|
|
688
|
-
|
|
689
|
-
return Promise.resolve();
|
|
690
|
-
});
|
|
691
|
-
},
|
|
692
|
-
|
|
693
|
-
/**
|
|
694
|
-
* Prepares a URI based from path segments
|
|
695
|
-
* @memberof Crisp
|
|
696
|
-
* @private
|
|
697
|
-
* @method _prepareRestUrl
|
|
698
|
-
* @param {Array} paths - List of paths ['session', 'login']
|
|
699
|
-
* @return {string}
|
|
700
|
-
*/
|
|
701
|
-
_prepareRestUrl : function(paths) {
|
|
702
|
-
if (Array.isArray(paths) === true) {
|
|
703
|
-
var output = this._rest.host + this._rest.basePath;
|
|
704
|
-
|
|
705
|
-
output += paths.join("/");
|
|
706
|
-
|
|
707
|
-
return output;
|
|
708
|
-
}
|
|
709
|
-
|
|
710
|
-
throw new Error(
|
|
711
|
-
"[Crisp] prepareRestUrl: parameter host should be an Array"
|
|
712
|
-
);
|
|
713
|
-
},
|
|
714
|
-
|
|
715
|
-
/**
|
|
716
|
-
* Binds services to the main object
|
|
717
|
-
* @memberof Crisp
|
|
718
|
-
* @private
|
|
719
|
-
* @method _prepareServices
|
|
720
|
-
* @return {undefined}
|
|
721
|
-
*/
|
|
722
|
-
_prepareServices : function() {
|
|
723
|
-
// Bind services
|
|
724
|
-
for (var name in services) {
|
|
725
|
-
var serviceInstance = new services[name]();
|
|
726
|
-
|
|
727
|
-
// Acquire service map
|
|
728
|
-
var serviceMap = this[(name[0].toLowerCase() + name.substring(1))];
|
|
729
|
-
|
|
730
|
-
// No service map available?
|
|
731
|
-
if (!serviceMap) {
|
|
732
|
-
throw new Error(
|
|
733
|
-
"[Crisp] prepareServices: service '" + name + "' has no map available"
|
|
734
|
-
);
|
|
735
|
-
}
|
|
736
|
-
|
|
737
|
-
// No resources defined in service?
|
|
738
|
-
if (!serviceInstance._resources ||
|
|
739
|
-
serviceInstance._resources.length === 0) {
|
|
740
|
-
throw new Error(
|
|
741
|
-
"[Crisp] prepareServices: service '" + name + "' has no resources " +
|
|
742
|
-
"defined"
|
|
743
|
-
);
|
|
744
|
-
}
|
|
745
|
-
|
|
746
|
-
// Prepare all resources (for service)
|
|
747
|
-
this._prepareResources(
|
|
748
|
-
serviceMap, serviceInstance._resources
|
|
749
|
-
);
|
|
750
|
-
}
|
|
751
|
-
},
|
|
752
|
-
|
|
753
|
-
/**
|
|
754
|
-
* Binds resources to the service object
|
|
755
|
-
* @memberof Crisp
|
|
756
|
-
* @private
|
|
757
|
-
* @method _prepareResources
|
|
758
|
-
* @param {object} serviceMap
|
|
759
|
-
* @param {Array} resources
|
|
760
|
-
* @return {undefined}
|
|
761
|
-
*/
|
|
762
|
-
_prepareResources : function(serviceMap, resources) {
|
|
763
|
-
for (var i = 0; i < resources.length; i++) {
|
|
764
|
-
var resourceConstructor = require("./resources/" + resources[i]);
|
|
765
|
-
|
|
766
|
-
// Instanciate resource, which will auto-bind itself to service prototype
|
|
767
|
-
new resourceConstructor(serviceMap, this);
|
|
768
|
-
}
|
|
769
|
-
},
|
|
770
|
-
|
|
771
|
-
/**
|
|
772
|
-
* Binds broker to the main object
|
|
773
|
-
* @memberof Crisp
|
|
774
|
-
* @private
|
|
775
|
-
* @method _prepareBroker
|
|
776
|
-
* @param {function} fnBindHook
|
|
777
|
-
* @return {Promise}
|
|
778
|
-
*/
|
|
779
|
-
_prepareBroker : function(fnBindHook) {
|
|
780
|
-
var self = this;
|
|
781
|
-
|
|
782
|
-
return new Promise(function(resolve, reject) {
|
|
783
|
-
var rtmMode = self._rtm.mode,
|
|
784
|
-
rtmHostOverride = self._rtm.host;
|
|
785
|
-
|
|
786
|
-
// Append bind hook to pending stack
|
|
787
|
-
self._brokerBindHooks.push(fnBindHook);
|
|
788
|
-
|
|
789
|
-
// Make sure to prepare broker once? (defer broker binding, waiting that \
|
|
790
|
-
// all listeners have been bound, that way we submit the list of \
|
|
791
|
-
// filtered events to the RTM API once, and never again in the future)
|
|
792
|
-
if (self._brokerScheduler === null) {
|
|
793
|
-
// Socket or loopback already set? We should not even have entered \
|
|
794
|
-
// there.
|
|
795
|
-
if (self._socket || self._loopback) {
|
|
796
|
-
throw new Error(
|
|
797
|
-
"[Crisp] prepareBroker: illegal call to prepare broker (tie break)"
|
|
798
|
-
);
|
|
799
|
-
}
|
|
800
|
-
|
|
801
|
-
self._brokerScheduler = setTimeout(function() {
|
|
802
|
-
switch (rtmMode) {
|
|
803
|
-
case Crisp.RTM_MODES.WebSockets: {
|
|
804
|
-
// Connect to socket now
|
|
805
|
-
// Notice: will unstack broker bind hooks once ready
|
|
806
|
-
self._connectSocket(rtmHostOverride)
|
|
807
|
-
.then(resolve)
|
|
808
|
-
.catch(reject);
|
|
809
|
-
|
|
810
|
-
break;
|
|
811
|
-
}
|
|
812
|
-
|
|
813
|
-
case Crisp.RTM_MODES.WebHooks: {
|
|
814
|
-
// Connect to loopback now
|
|
815
|
-
self._connectLoopback()
|
|
816
|
-
.then(resolve)
|
|
817
|
-
.catch(reject);
|
|
818
|
-
|
|
819
|
-
break;
|
|
820
|
-
}
|
|
821
|
-
|
|
822
|
-
default: {
|
|
823
|
-
var unsupportedError = new Error(
|
|
824
|
-
"[Crisp] prepareBroker: mode of RTM broker unsupported " +
|
|
825
|
-
"('" + rtmMode + "')"
|
|
826
|
-
);
|
|
827
|
-
|
|
828
|
-
reject(unsupportedError);
|
|
829
|
-
}
|
|
830
|
-
}
|
|
831
|
-
}, Crisp.DEFAULT_BROKER_SCHEDULE);
|
|
832
|
-
} else {
|
|
833
|
-
// Pass-through
|
|
834
|
-
resolve();
|
|
835
|
-
}
|
|
836
|
-
});
|
|
837
|
-
},
|
|
838
|
-
|
|
839
|
-
/**
|
|
840
|
-
* Connects loopback (used for Web Hooks)
|
|
841
|
-
* @memberof Crisp
|
|
842
|
-
* @private
|
|
843
|
-
* @method _connectLoopback
|
|
844
|
-
* @return {Promise}
|
|
845
|
-
*/
|
|
846
|
-
_connectLoopback : function() {
|
|
847
|
-
var self = this;
|
|
848
|
-
|
|
849
|
-
return Promise.resolve()
|
|
850
|
-
.then(function() {
|
|
851
|
-
// Assign emitter to loopback
|
|
852
|
-
self._loopback = self._emitter;
|
|
853
|
-
|
|
854
|
-
// Unstack broker bind hooks immediately
|
|
855
|
-
self._unstackBrokerBindHooks(self._loopback);
|
|
856
|
-
|
|
857
|
-
return Promise.resolve();
|
|
858
|
-
});
|
|
859
|
-
},
|
|
860
|
-
|
|
861
|
-
/**
|
|
862
|
-
* Connects socket, using preferred RTM API host (used for WebSockets)
|
|
863
|
-
* @memberof Crisp
|
|
864
|
-
* @private
|
|
865
|
-
* @method _connectSocket
|
|
866
|
-
* @param {string} rtmHostOverride
|
|
867
|
-
* @return {Promise}
|
|
868
|
-
*/
|
|
869
|
-
_connectSocket : function(rtmHostOverride) {
|
|
870
|
-
var self = this;
|
|
871
|
-
|
|
872
|
-
return Promise.resolve()
|
|
873
|
-
.then(function() {
|
|
874
|
-
// Any override RTM API host?
|
|
875
|
-
if (rtmHostOverride) {
|
|
876
|
-
return Promise.resolve({
|
|
877
|
-
socket : {
|
|
878
|
-
app : rtmHostOverride
|
|
879
|
-
}
|
|
880
|
-
});
|
|
881
|
-
}
|
|
882
|
-
|
|
883
|
-
// Acquire RTM API URL from remote
|
|
884
|
-
var restUrlSegments;
|
|
885
|
-
|
|
886
|
-
switch (self.auth.tier) {
|
|
887
|
-
case "plugin": {
|
|
888
|
-
restUrlSegments = ["plugin", "connect", "endpoints"];
|
|
889
|
-
|
|
890
|
-
break;
|
|
891
|
-
}
|
|
892
|
-
|
|
893
|
-
default: {
|
|
894
|
-
restUrlSegments = ["user", "connect", "endpoints"];
|
|
895
|
-
}
|
|
896
|
-
}
|
|
897
|
-
|
|
898
|
-
return self.get(
|
|
899
|
-
self._prepareRestUrl(restUrlSegments)
|
|
900
|
-
)
|
|
901
|
-
.catch(function() {
|
|
902
|
-
// Void error (consider as empty response)
|
|
903
|
-
return Promise.resolve({});
|
|
904
|
-
});
|
|
905
|
-
})
|
|
906
|
-
.then(function(endpoints) {
|
|
907
|
-
var rtmHostAffinity = ((endpoints.socket || {}).app || null);
|
|
908
|
-
|
|
909
|
-
// No RTM API host acquired?
|
|
910
|
-
if (rtmHostAffinity === null) {
|
|
911
|
-
throw new Error(
|
|
912
|
-
"[Crisp] connectSocket: could not acquire target host to " +
|
|
913
|
-
"connect to, is your session valid for tier?"
|
|
914
|
-
);
|
|
915
|
-
}
|
|
916
|
-
|
|
917
|
-
// Parse target RTM API host as an URL object
|
|
918
|
-
var rtmHostUrl = new URL(rtmHostAffinity);
|
|
919
|
-
|
|
920
|
-
// Connect to socket
|
|
921
|
-
self._socket = require("socket.io-client")(rtmHostUrl.origin, {
|
|
922
|
-
path : (rtmHostUrl.pathname || "/"),
|
|
923
|
-
transports : ["websocket"],
|
|
924
|
-
timeout : Crisp.DEFAULT_SOCKET_TIMEOUT,
|
|
925
|
-
reconnection : true,
|
|
926
|
-
reconnectionDelay : Crisp.DEFAULT_SOCKET_RECONNECT_DELAY,
|
|
927
|
-
reconnectionDelayMax : Crisp.DEFAULT_SOCKET_RECONNECT_DELAY_MAX,
|
|
928
|
-
randomizationFactor : Crisp.DEFAULT_SOCKET_RECONNECT_FACTOR
|
|
929
|
-
});
|
|
930
|
-
|
|
931
|
-
self._emitAuthenticateSocket();
|
|
932
|
-
|
|
933
|
-
// Setup base socket event listeners
|
|
934
|
-
self._socket.io.on("reconnect", function() {
|
|
935
|
-
self._emitAuthenticateSocket();
|
|
936
|
-
});
|
|
937
|
-
|
|
938
|
-
self._socket.on("unauthorized", function() {
|
|
939
|
-
throw new Error(
|
|
940
|
-
"[Crisp] connectSocket: cannot listen for events as " +
|
|
941
|
-
"authentication is invalid"
|
|
942
|
-
);
|
|
943
|
-
});
|
|
944
|
-
|
|
945
|
-
// Setup user socket event listeners
|
|
946
|
-
self._unstackBrokerBindHooks(self._socket);
|
|
947
|
-
|
|
948
|
-
return Promise.resolve();
|
|
949
|
-
});
|
|
950
|
-
},
|
|
951
|
-
|
|
952
|
-
/**
|
|
953
|
-
* Authenticates client (used for WebSockets)
|
|
954
|
-
* @memberof Crisp
|
|
955
|
-
* @private
|
|
956
|
-
* @method _emitAuthenticateSocket
|
|
957
|
-
* @return {undefined}
|
|
958
|
-
*/
|
|
959
|
-
_emitAuthenticateSocket : function() {
|
|
960
|
-
var auth = this.auth,
|
|
961
|
-
boundEvents = Object.keys(this._boundEvents);
|
|
962
|
-
|
|
963
|
-
if (!this._socket) {
|
|
964
|
-
throw new Error(
|
|
965
|
-
"[Crisp] emitAuthenticateSocket: cannot listen for events as socket " +
|
|
966
|
-
"is not yet bound"
|
|
967
|
-
);
|
|
968
|
-
}
|
|
969
|
-
if (!auth.identifier || !auth.key) {
|
|
970
|
-
throw new Error(
|
|
971
|
-
"[Crisp] emitAuthenticateSocket: cannot listen for events as you " +
|
|
972
|
-
"did not authenticate"
|
|
973
|
-
);
|
|
974
|
-
}
|
|
975
|
-
if (boundEvents.length === 0) {
|
|
976
|
-
throw new Error(
|
|
977
|
-
"[Crisp] emitAuthenticateSocket: cannot listen for events as no " +
|
|
978
|
-
"event is being listened to"
|
|
979
|
-
);
|
|
980
|
-
}
|
|
981
|
-
|
|
982
|
-
this._socket.emit("authentication", {
|
|
983
|
-
username : auth.identifier,
|
|
984
|
-
password : auth.key,
|
|
985
|
-
tier : auth.tier,
|
|
986
|
-
events : boundEvents
|
|
987
|
-
});
|
|
988
|
-
},
|
|
989
|
-
|
|
990
|
-
/**
|
|
991
|
-
* Unstacks pending broker bind hooks
|
|
992
|
-
* @memberof Crisp
|
|
993
|
-
* @private
|
|
994
|
-
* @method _unstackBrokerBindHooks
|
|
995
|
-
* @param {object} modeInstance
|
|
996
|
-
* @return {undefined}
|
|
997
|
-
*/
|
|
998
|
-
_unstackBrokerBindHooks : function(modeInstance) {
|
|
999
|
-
// Setup user socket event listeners
|
|
1000
|
-
while (this._brokerBindHooks.length > 0) {
|
|
1001
|
-
this._brokerBindHooks.shift()(
|
|
1002
|
-
modeInstance, this._emitter
|
|
1003
|
-
);
|
|
1004
|
-
}
|
|
1005
|
-
},
|
|
1006
|
-
|
|
1007
|
-
/**
|
|
1008
|
-
* Performs a request to REST API
|
|
1009
|
-
* @memberof Crisp
|
|
1010
|
-
* @private
|
|
1011
|
-
* @method _request
|
|
1012
|
-
* @param {string} resource
|
|
1013
|
-
* @param {string} method
|
|
1014
|
-
* @param {object} query
|
|
1015
|
-
* @param {object} body
|
|
1016
|
-
* @param {function} resolve
|
|
1017
|
-
* @param {function} reject
|
|
1018
|
-
* @return {undefined}
|
|
1019
|
-
*/
|
|
1020
|
-
_request : function(resource, method, query, body, resolve, reject) {
|
|
1021
|
-
var self = this;
|
|
1022
|
-
|
|
1023
|
-
var requestParameters = {
|
|
1024
|
-
responseType : "json",
|
|
1025
|
-
timeout : Crisp.DEFAULT_REQUEST_TIMEOUT,
|
|
1026
|
-
|
|
1027
|
-
headers : {
|
|
1028
|
-
"User-Agent" : self._useragent,
|
|
1029
|
-
"X-Crisp-Tier" : self.auth.tier
|
|
1030
|
-
},
|
|
1031
|
-
|
|
1032
|
-
throwHttpErrors : false
|
|
1033
|
-
};
|
|
1034
|
-
|
|
1035
|
-
// Add authorization?
|
|
1036
|
-
if (self.auth.token) {
|
|
1037
|
-
requestParameters.headers.Authorization = ("Basic " + self.auth.token);
|
|
1038
|
-
}
|
|
1039
|
-
|
|
1040
|
-
// Add body?
|
|
1041
|
-
if (body) {
|
|
1042
|
-
requestParameters.json = body;
|
|
1043
|
-
}
|
|
1044
|
-
|
|
1045
|
-
// Add query?
|
|
1046
|
-
if (query) {
|
|
1047
|
-
requestParameters.searchParams = query;
|
|
1048
|
-
}
|
|
1049
|
-
|
|
1050
|
-
// Proceed request
|
|
1051
|
-
got[method](resource, requestParameters)
|
|
1052
|
-
.catch(function(error) {
|
|
1053
|
-
return Promise.resolve(error);
|
|
1054
|
-
})
|
|
1055
|
-
.then(function(response, error) {
|
|
1056
|
-
var data = response.body;
|
|
1057
|
-
|
|
1058
|
-
// Request error?
|
|
1059
|
-
if (!response.statusCode) {
|
|
1060
|
-
return reject({
|
|
1061
|
-
reason : "error",
|
|
1062
|
-
message : "internal_error",
|
|
1063
|
-
code : 500,
|
|
1064
|
-
|
|
1065
|
-
data : {
|
|
1066
|
-
namespace : "request",
|
|
1067
|
-
|
|
1068
|
-
message : (
|
|
1069
|
-
"Got request error: " + (response.name || "Unknown")
|
|
1070
|
-
)
|
|
1071
|
-
}
|
|
1072
|
-
});
|
|
1073
|
-
}
|
|
1074
|
-
|
|
1075
|
-
// Response error?
|
|
1076
|
-
if (response.statusCode >= 400) {
|
|
1077
|
-
var reason_message = self._readErrorResponseReason(
|
|
1078
|
-
method, response.statusCode, response
|
|
1079
|
-
);
|
|
1080
|
-
var data_message = ((response.body || {}).data || {}).message;
|
|
1081
|
-
|
|
1082
|
-
return reject({
|
|
1083
|
-
reason : "error",
|
|
1084
|
-
message : reason_message,
|
|
1085
|
-
code : response.statusCode,
|
|
1086
|
-
|
|
1087
|
-
data : {
|
|
1088
|
-
namespace : "response",
|
|
1089
|
-
|
|
1090
|
-
message : (
|
|
1091
|
-
"Got response error: " + (data_message || reason_message)
|
|
1092
|
-
)
|
|
1093
|
-
}
|
|
1094
|
-
});
|
|
1095
|
-
}
|
|
1096
|
-
|
|
1097
|
-
// Regular response
|
|
1098
|
-
return resolve(
|
|
1099
|
-
(response.body || {}).data || {}
|
|
1100
|
-
);
|
|
1101
|
-
});
|
|
1102
|
-
},
|
|
1103
|
-
|
|
1104
|
-
/**
|
|
1105
|
-
* Reads reason for error response
|
|
1106
|
-
* @memberof Crisp
|
|
1107
|
-
* @private
|
|
1108
|
-
* @method _readErrorResponseReason
|
|
1109
|
-
* @param {string} method
|
|
1110
|
-
* @param {number} statusCode
|
|
1111
|
-
* @param {object} response
|
|
1112
|
-
* @return {string}
|
|
1113
|
-
*/
|
|
1114
|
-
_readErrorResponseReason : function(method, statusCode, response) {
|
|
1115
|
-
// HEAD method? As HEAD requests do not expect any response body, then we \
|
|
1116
|
-
// cannot map a reason from the response.
|
|
1117
|
-
if (method === "head") {
|
|
1118
|
-
// 5xx errors?
|
|
1119
|
-
if (statusCode >= 500) {
|
|
1120
|
-
return "server_error";
|
|
1121
|
-
}
|
|
1122
|
-
|
|
1123
|
-
// 4xx errors?
|
|
1124
|
-
if (statusCode >= 400) {
|
|
1125
|
-
return "route_error";
|
|
1126
|
-
}
|
|
1127
|
-
}
|
|
1128
|
-
|
|
1129
|
-
// Other methods must hold a response body, therefore we can fallback on \
|
|
1130
|
-
// an HTTP error if we fail to acquire any reason at all.
|
|
1131
|
-
return ((response.body || {}).reason || "http_error");
|
|
1132
|
-
},
|
|
1133
|
-
|
|
1134
|
-
/**
|
|
1135
|
-
* Verifies an event string and checks that signatures match
|
|
1136
|
-
* @memberof Crisp
|
|
1137
|
-
* @private
|
|
1138
|
-
* @method verifyHook
|
|
1139
|
-
* @param {string} secret
|
|
1140
|
-
* @param {object} body
|
|
1141
|
-
* @param {string} timestamp
|
|
1142
|
-
* @param {string} signature
|
|
1143
|
-
* @return {boolean}
|
|
1144
|
-
*/
|
|
1145
|
-
_verifySignature : function(secret, body, timestamp, signature) {
|
|
1146
|
-
// Ensure all provided data is valid
|
|
1147
|
-
if (!secret || !signature || !body || typeof body !== "object" ||
|
|
1148
|
-
!timestamp || isNaN(timestamp) === true) {
|
|
1149
|
-
return false;
|
|
1150
|
-
}
|
|
1151
|
-
|
|
1152
|
-
// Compute local trace
|
|
1153
|
-
var localTrace = ("[" + timestamp + ";" + JSON.stringify(body) + "]");
|
|
1154
|
-
|
|
1155
|
-
// Create local HMAC
|
|
1156
|
-
var localMac = Crypto.createHmac("sha256", secret);
|
|
1157
|
-
|
|
1158
|
-
localMac.update(localTrace);
|
|
1159
|
-
|
|
1160
|
-
// Compute local signature, and compare
|
|
1161
|
-
var localSignature = localMac.digest("hex");
|
|
1162
|
-
|
|
1163
|
-
return (
|
|
1164
|
-
(signature === localSignature) ? true : false
|
|
1165
|
-
);
|
|
1166
|
-
}
|
|
1167
|
-
};
|
|
1168
|
-
|
|
1169
|
-
|
|
1170
|
-
module.exports = Crisp;
|
|
1171
|
-
module.exports.Crisp = Crisp;
|