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.
Files changed (116) hide show
  1. package/CHANGELOG.md +8 -0
  2. package/README.md +2 -2
  3. package/dist/crisp.d.ts +167 -0
  4. package/dist/crisp.js +764 -0
  5. package/dist/resources/BaseResource.d.ts +15 -0
  6. package/dist/resources/BaseResource.js +20 -0
  7. package/dist/resources/BucketURL.d.ts +28 -0
  8. package/dist/resources/BucketURL.js +29 -0
  9. package/dist/resources/MediaAnimation.d.ts +14 -0
  10. package/dist/resources/MediaAnimation.js +32 -0
  11. package/dist/resources/PluginConnect.d.ts +50 -0
  12. package/dist/resources/PluginConnect.js +73 -0
  13. package/dist/resources/PluginSubscription.d.ts +103 -0
  14. package/dist/resources/PluginSubscription.js +122 -0
  15. package/dist/resources/WebsiteAnalytics.d.ts +14 -0
  16. package/dist/resources/WebsiteAnalytics.js +29 -0
  17. package/dist/resources/WebsiteAvailability.d.ts +31 -0
  18. package/dist/resources/WebsiteAvailability.js +36 -0
  19. package/dist/resources/WebsiteBase.d.ts +60 -0
  20. package/dist/resources/WebsiteBase.js +71 -0
  21. package/dist/resources/WebsiteBatch.d.ts +52 -0
  22. package/dist/resources/WebsiteBatch.js +70 -0
  23. package/dist/resources/WebsiteCampaign.d.ts +199 -0
  24. package/dist/resources/WebsiteCampaign.js +194 -0
  25. package/dist/resources/WebsiteConversation.d.ts +701 -0
  26. package/dist/resources/WebsiteConversation.js +595 -0
  27. package/dist/resources/WebsiteHelpdesk.d.ts +347 -0
  28. package/dist/resources/WebsiteHelpdesk.js +587 -0
  29. package/dist/resources/WebsiteOperator.d.ts +79 -0
  30. package/dist/resources/WebsiteOperator.js +93 -0
  31. package/dist/resources/WebsitePeople.d.ts +248 -0
  32. package/dist/resources/WebsitePeople.js +276 -0
  33. package/dist/resources/WebsiteSettings.d.ts +159 -0
  34. package/dist/resources/WebsiteSettings.js +36 -0
  35. package/dist/resources/WebsiteVerify.d.ts +38 -0
  36. package/dist/resources/WebsiteVerify.js +50 -0
  37. package/dist/resources/WebsiteVisitors.d.ts +113 -0
  38. package/dist/resources/WebsiteVisitors.js +88 -0
  39. package/dist/resources/index.d.ts +17 -0
  40. package/dist/resources/index.js +40 -0
  41. package/dist/services/bucket.d.ts +13 -0
  42. package/dist/services/bucket.js +28 -0
  43. package/dist/services/media.d.ts +13 -0
  44. package/dist/services/media.js +28 -0
  45. package/dist/services/plugin.d.ts +14 -0
  46. package/dist/services/plugin.js +30 -0
  47. package/dist/services/website.d.ts +24 -0
  48. package/dist/services/website.js +50 -0
  49. package/eslint.config.mjs +208 -0
  50. package/lib/crisp.ts +957 -0
  51. package/lib/resources/BaseResource.ts +29 -0
  52. package/lib/resources/BucketURL.ts +49 -0
  53. package/lib/resources/MediaAnimation.ts +34 -0
  54. package/lib/resources/PluginConnect.ts +128 -0
  55. package/lib/resources/PluginSubscription.ts +208 -0
  56. package/lib/resources/WebsiteAnalytics.ts +31 -0
  57. package/lib/resources/WebsiteAvailability.ts +54 -0
  58. package/lib/resources/WebsiteBase.ts +108 -0
  59. package/lib/resources/WebsiteBatch.ts +96 -0
  60. package/lib/resources/WebsiteCampaign.ts +399 -0
  61. package/lib/resources/WebsiteConversation.ts +1416 -0
  62. package/lib/resources/WebsiteHelpdesk.ts +982 -0
  63. package/lib/resources/WebsiteOperator.ts +161 -0
  64. package/lib/resources/WebsitePeople.ts +527 -0
  65. package/lib/resources/WebsiteSettings.ts +192 -0
  66. package/lib/resources/WebsiteVerify.ts +76 -0
  67. package/lib/resources/WebsiteVisitors.ts +196 -0
  68. package/lib/resources/index.ts +25 -0
  69. package/lib/services/bucket.ts +28 -0
  70. package/lib/services/media.ts +28 -0
  71. package/lib/services/plugin.ts +32 -0
  72. package/lib/services/website.ts +62 -0
  73. package/package.json +16 -11
  74. package/tsconfig.json +12 -5
  75. package/lib/crisp.js +0 -1171
  76. package/lib/resources/BucketURL.js +0 -34
  77. package/lib/resources/MediaAnimation.js +0 -41
  78. package/lib/resources/PluginConnect.js +0 -119
  79. package/lib/resources/PluginSubscription.js +0 -234
  80. package/lib/resources/WebsiteAnalytics.js +0 -37
  81. package/lib/resources/WebsiteAvailability.js +0 -48
  82. package/lib/resources/WebsiteBase.js +0 -100
  83. package/lib/resources/WebsiteBatch.js +0 -92
  84. package/lib/resources/WebsiteCampaign.js +0 -396
  85. package/lib/resources/WebsiteConversation.js +0 -1261
  86. package/lib/resources/WebsiteHelpdesk.js +0 -1198
  87. package/lib/resources/WebsiteOperator.js +0 -167
  88. package/lib/resources/WebsitePeople.js +0 -516
  89. package/lib/resources/WebsiteSettings.js +0 -50
  90. package/lib/resources/WebsiteVerify.js +0 -79
  91. package/lib/resources/WebsiteVisitors.js +0 -148
  92. package/lib/services/Bucket.js +0 -28
  93. package/lib/services/Media.js +0 -28
  94. package/lib/services/Plugin.js +0 -29
  95. package/lib/services/Website.js +0 -39
  96. package/types/crisp.d.ts +0 -151
  97. package/types/resources/BucketURL.d.ts +0 -15
  98. package/types/resources/MediaAnimation.d.ts +0 -15
  99. package/types/resources/PluginConnect.d.ts +0 -15
  100. package/types/resources/PluginSubscription.d.ts +0 -15
  101. package/types/resources/WebsiteAnalytics.d.ts +0 -15
  102. package/types/resources/WebsiteAvailability.d.ts +0 -15
  103. package/types/resources/WebsiteBase.d.ts +0 -15
  104. package/types/resources/WebsiteBatch.d.ts +0 -15
  105. package/types/resources/WebsiteCampaign.d.ts +0 -15
  106. package/types/resources/WebsiteConversation.d.ts +0 -15
  107. package/types/resources/WebsiteHelpdesk.d.ts +0 -15
  108. package/types/resources/WebsiteOperator.d.ts +0 -15
  109. package/types/resources/WebsitePeople.d.ts +0 -15
  110. package/types/resources/WebsiteSettings.d.ts +0 -15
  111. package/types/resources/WebsiteVerify.d.ts +0 -15
  112. package/types/resources/WebsiteVisitors.d.ts +0 -15
  113. package/types/services/Bucket.d.ts +0 -14
  114. package/types/services/Media.d.ts +0 -14
  115. package/types/services/Plugin.d.ts +0 -14
  116. 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;