wingbot 3.24.5 → 3.26.0-alpha.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/index.js +2 -0
- package/package.json +1 -1
- package/src/BotApp.js +63 -7
- package/src/BotAppSender.js +33 -2
- package/src/CallbackAuditLog.js +145 -0
- package/src/Responder.js +1 -1
- package/src/graphApi/GraphApi.js +50 -3
- package/src/graphApi/conversationTestApi.js +2 -0
- package/src/graphApi/conversationsApi.js +4 -0
- package/src/graphApi/postBackApi.js +1 -0
- package/src/graphApi/validateBotApi.js +1 -0
- package/src/utils/getUpdate.js +1 -1
- package/src/utils/headersToAuditMeta.js +12 -0
package/index.js
CHANGED
|
@@ -21,6 +21,7 @@ const { asserts } = require('./src/testTools');
|
|
|
21
21
|
const BuildRouter = require('./src/BuildRouter');
|
|
22
22
|
const MockAiModel = require('./src/MockAiModel');
|
|
23
23
|
const ReturnSender = require('./src/ReturnSender');
|
|
24
|
+
const CallbackAuditLog = require('./src/CallbackAuditLog');
|
|
24
25
|
const Plugins = require('./src/Plugins');
|
|
25
26
|
const NotificationsStorage = require('./src/notifications/NotificationsStorage');
|
|
26
27
|
const Notifications = require('./src/notifications/Notifications');
|
|
@@ -70,6 +71,7 @@ module.exports = {
|
|
|
70
71
|
bufferloader,
|
|
71
72
|
asserts,
|
|
72
73
|
MemoryStateStorage,
|
|
74
|
+
CallbackAuditLog,
|
|
73
75
|
MemoryBotConfigStorage,
|
|
74
76
|
CachedModel,
|
|
75
77
|
CustomEntityDetectionModel,
|
package/package.json
CHANGED
package/src/BotApp.js
CHANGED
|
@@ -9,6 +9,7 @@ const crypto = require('crypto');
|
|
|
9
9
|
const BotAppSender = require('./BotAppSender');
|
|
10
10
|
const Processor = require('./Processor');
|
|
11
11
|
const ReturnSender = require('./ReturnSender');
|
|
12
|
+
const headersToAuditMeta = require('./utils/headersToAuditMeta');
|
|
12
13
|
|
|
13
14
|
const DEFAULT_API_URL = 'https://orchestrator-api.wingbot.ai';
|
|
14
15
|
|
|
@@ -20,6 +21,9 @@ const DEFAULT_API_URL = 'https://orchestrator-api.wingbot.ai';
|
|
|
20
21
|
/** @typedef {import('./Responder')} Responder */
|
|
21
22
|
/** @typedef {import('./Processor').Plugin} Plugin */
|
|
22
23
|
|
|
24
|
+
/** @typedef {import('./CallbackAuditLog')} AuditLog */
|
|
25
|
+
/** @typedef {import('./BotAppSender').TlsOptions} TlsOptions */
|
|
26
|
+
|
|
23
27
|
/**
|
|
24
28
|
* @typedef {object} BotAppOptions
|
|
25
29
|
* @prop {string|Promise<string>} secret
|
|
@@ -28,6 +32,8 @@ const DEFAULT_API_URL = 'https://orchestrator-api.wingbot.ai';
|
|
|
28
32
|
* @prop {Function} [fetch]
|
|
29
33
|
* @prop {ChatLogStorage} [chatLogStorage]
|
|
30
34
|
* @prop {boolean} [preferSynchronousResponse]
|
|
35
|
+
* @prop {AuditLog} [auditLog]
|
|
36
|
+
* @prop {TlsOptions} [tls]
|
|
31
37
|
*
|
|
32
38
|
* @typedef {ProcessorOptions & BotAppOptions} Options
|
|
33
39
|
*/
|
|
@@ -58,12 +64,16 @@ class BotApp {
|
|
|
58
64
|
fetch = null,
|
|
59
65
|
appId = null,
|
|
60
66
|
preferSynchronousResponse = false,
|
|
67
|
+
auditLog = null,
|
|
68
|
+
tls = null,
|
|
61
69
|
...processorOptions
|
|
62
70
|
} = options;
|
|
63
71
|
|
|
64
72
|
this._secret = Promise.resolve(secret);
|
|
65
73
|
this._fetch = fetch; // mock
|
|
66
74
|
this._appId = appId;
|
|
75
|
+
this._auditLog = auditLog;
|
|
76
|
+
this._tls = tls;
|
|
67
77
|
|
|
68
78
|
let { apiUrl } = options;
|
|
69
79
|
|
|
@@ -90,6 +100,18 @@ class BotApp {
|
|
|
90
100
|
this._preferSynchronousResponse = preferSynchronousResponse;
|
|
91
101
|
}
|
|
92
102
|
|
|
103
|
+
/**
|
|
104
|
+
* Get authorization token for wingbot orchestrator
|
|
105
|
+
*
|
|
106
|
+
* @param {string} body
|
|
107
|
+
* @param {string} secret
|
|
108
|
+
* @param {string} appId
|
|
109
|
+
* @returns {Promise<string>}
|
|
110
|
+
*/
|
|
111
|
+
static signBody (body, secret, appId) {
|
|
112
|
+
return BotApp.signBody(body, secret, appId);
|
|
113
|
+
}
|
|
114
|
+
|
|
93
115
|
/**
|
|
94
116
|
* Returns processor plugin, which updates thread context automatically
|
|
95
117
|
*
|
|
@@ -140,13 +162,44 @@ class BotApp {
|
|
|
140
162
|
};
|
|
141
163
|
}
|
|
142
164
|
|
|
143
|
-
|
|
165
|
+
/**
|
|
166
|
+
* @param {ReturnSender} sender
|
|
167
|
+
* @param {string} senderId
|
|
168
|
+
* @param {string} pageId
|
|
169
|
+
* @param {object} headers
|
|
170
|
+
*/
|
|
171
|
+
async _processSenderResponses (sender, senderId, pageId, headers) {
|
|
172
|
+
if (!this._auditLog) {
|
|
173
|
+
return;
|
|
174
|
+
}
|
|
175
|
+
await Promise.all(
|
|
176
|
+
sender.tracking.events.map(async (event) => {
|
|
177
|
+
if (!['audit', 'report'].includes(event.type)) {
|
|
178
|
+
return;
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
await this._auditLog.log(
|
|
182
|
+
event,
|
|
183
|
+
{ senderId, pageId },
|
|
184
|
+
headersToAuditMeta(headers),
|
|
185
|
+
this._auditLog.defaultWid,
|
|
186
|
+
'Info',
|
|
187
|
+
event.type === 'audit' ? 'Important' : 'Debug'
|
|
188
|
+
);
|
|
189
|
+
})
|
|
190
|
+
);
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
async _processIncommingMessage (
|
|
194
|
+
message, senderId, pageId, appId, secret, sync = false, headers = {}
|
|
195
|
+
) {
|
|
144
196
|
const { mid = null } = message;
|
|
145
197
|
|
|
146
198
|
if (sync || this._preferSynchronousResponse) {
|
|
147
199
|
const sender = new ReturnSender({}, senderId, message, this._senderLogger);
|
|
148
200
|
sender.propagatesWaitEvent = true;
|
|
149
201
|
const res = await this._processor.processMessage(message, pageId, sender, { appId });
|
|
202
|
+
await this._processSenderResponses(sender, senderId, pageId, headers);
|
|
150
203
|
|
|
151
204
|
return {
|
|
152
205
|
status: res.status,
|
|
@@ -174,11 +227,13 @@ class BotApp {
|
|
|
174
227
|
appId,
|
|
175
228
|
secret,
|
|
176
229
|
mid,
|
|
177
|
-
fetch: this._fetch
|
|
230
|
+
fetch: this._fetch,
|
|
231
|
+
tls: this._tls
|
|
178
232
|
};
|
|
179
233
|
|
|
180
234
|
const sender = new BotAppSender(options, senderId, message, this._senderLogger);
|
|
181
235
|
const res = await this._processor.processMessage(message, pageId, sender, { appId });
|
|
236
|
+
await this._processSenderResponses(sender, senderId, pageId, headers);
|
|
182
237
|
|
|
183
238
|
return {
|
|
184
239
|
status: res.status,
|
|
@@ -280,7 +335,7 @@ class BotApp {
|
|
|
280
335
|
|
|
281
336
|
const body = JSON.parse(rawBody);
|
|
282
337
|
|
|
283
|
-
const entry = await this._processEntries(appId, secret, body.entry);
|
|
338
|
+
const entry = await this._processEntries(appId, secret, body.entry, rawHeaders);
|
|
284
339
|
|
|
285
340
|
return {
|
|
286
341
|
statusCode: 200,
|
|
@@ -293,7 +348,7 @@ class BotApp {
|
|
|
293
348
|
};
|
|
294
349
|
}
|
|
295
350
|
|
|
296
|
-
async _processEntries (appId, secret, entry = []) {
|
|
351
|
+
async _processEntries (appId, secret, entry = [], headers = {}) {
|
|
297
352
|
return Promise.all(
|
|
298
353
|
entry.map(async (event) => {
|
|
299
354
|
const {
|
|
@@ -308,7 +363,8 @@ class BotApp {
|
|
|
308
363
|
...standby.map((e) => ({ ...e, isStandby: true }))
|
|
309
364
|
];
|
|
310
365
|
|
|
311
|
-
const responses = await this
|
|
366
|
+
const responses = await this
|
|
367
|
+
._processMessaging(events, pageId, appId, secret, sync, headers);
|
|
312
368
|
|
|
313
369
|
return {
|
|
314
370
|
id: pageId,
|
|
@@ -318,7 +374,7 @@ class BotApp {
|
|
|
318
374
|
);
|
|
319
375
|
}
|
|
320
376
|
|
|
321
|
-
async _processMessaging (process, pageId, appId, secret, sync) {
|
|
377
|
+
async _processMessaging (process, pageId, appId, secret, sync, headers) {
|
|
322
378
|
const eventsBySenderId = new Map();
|
|
323
379
|
process.forEach((e) => this._processMessagingArrayItem(e, eventsBySenderId));
|
|
324
380
|
|
|
@@ -329,7 +385,7 @@ class BotApp {
|
|
|
329
385
|
|
|
330
386
|
for (const message of messaging) {
|
|
331
387
|
const res = await this._processIncommingMessage(
|
|
332
|
-
message, senderId, pageId, appId, secret, sync
|
|
388
|
+
message, senderId, pageId, appId, secret, sync, headers
|
|
333
389
|
);
|
|
334
390
|
|
|
335
391
|
responses.push(res);
|
package/src/BotAppSender.js
CHANGED
|
@@ -6,17 +6,25 @@
|
|
|
6
6
|
const jwt = require('jsonwebtoken');
|
|
7
7
|
const { default: fetch, Headers } = require('node-fetch');
|
|
8
8
|
const crypto = require('crypto');
|
|
9
|
+
const { Agent } = require('https');
|
|
9
10
|
const { promisify } = require('util');
|
|
10
11
|
const ReturnSender = require('./ReturnSender');
|
|
11
12
|
|
|
12
13
|
/** @typedef {import('./ReturnSender').ReturnSenderOptions} ReturnSenderOptions */
|
|
13
14
|
/** @typedef {import('./ReturnSender').ChatLogStorage} ChatLogStorage */
|
|
14
15
|
|
|
16
|
+
/**
|
|
17
|
+
* @typedef {object} TlsOptions
|
|
18
|
+
* @prop {string|Promise<string>} key
|
|
19
|
+
* @prop {string|Promise<string>} cert
|
|
20
|
+
*/
|
|
21
|
+
|
|
15
22
|
/**
|
|
16
23
|
* @typedef {object} BotAppSenderOptions
|
|
17
24
|
* @prop {string} apiUrl
|
|
18
25
|
* @prop {string} pageId
|
|
19
26
|
* @prop {string} appId
|
|
27
|
+
* @prop {TlsOptions} [tls]
|
|
20
28
|
* @prop {string} [mid]
|
|
21
29
|
* @prop {Function} [fetch]
|
|
22
30
|
* @prop {string|Promise<string>} secret
|
|
@@ -47,6 +55,9 @@ class BotAppSender extends ReturnSender {
|
|
|
47
55
|
|
|
48
56
|
this._secret = Promise.resolve(options.secret);
|
|
49
57
|
|
|
58
|
+
this._tls = options.tls;
|
|
59
|
+
this._agent = null;
|
|
60
|
+
|
|
50
61
|
this._fetch = options.fetch || fetch;
|
|
51
62
|
}
|
|
52
63
|
|
|
@@ -65,6 +76,21 @@ class BotAppSender extends ReturnSender {
|
|
|
65
76
|
}, goodSecret);
|
|
66
77
|
}
|
|
67
78
|
|
|
79
|
+
async _getAgent () {
|
|
80
|
+
if (!this._tls) {
|
|
81
|
+
return null;
|
|
82
|
+
}
|
|
83
|
+
if (!this._agent) {
|
|
84
|
+
const [key, cert] = await Promise.all([
|
|
85
|
+
Promise.resolve(this._tls.key), Promise.resolve(this._tls.cert)
|
|
86
|
+
]);
|
|
87
|
+
|
|
88
|
+
this._agent = new Agent({ cert, key });
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
return this._agent;
|
|
92
|
+
}
|
|
93
|
+
|
|
68
94
|
async _send (payload) {
|
|
69
95
|
// attach sender
|
|
70
96
|
if (typeof payload.sender === 'undefined') {
|
|
@@ -78,14 +104,19 @@ class BotAppSender extends ReturnSender {
|
|
|
78
104
|
|
|
79
105
|
const body = JSON.stringify(payload);
|
|
80
106
|
|
|
81
|
-
const token = await
|
|
107
|
+
const [token, agent] = await Promise.all([
|
|
108
|
+
BotAppSender.signBody(body, this._secret, this._appId),
|
|
109
|
+
this._getAgent()
|
|
110
|
+
]);
|
|
82
111
|
|
|
83
112
|
const headers = new Headers();
|
|
84
113
|
|
|
85
114
|
headers.set('Authorization', token);
|
|
86
115
|
headers.set('Content-Type', 'application/json');
|
|
87
116
|
|
|
88
|
-
const response = await this._fetch(this._apiUrl, {
|
|
117
|
+
const response = await this._fetch(this._apiUrl, {
|
|
118
|
+
headers, body, agent, method: 'POST'
|
|
119
|
+
})
|
|
89
120
|
.then((r) => r.json());
|
|
90
121
|
|
|
91
122
|
const { request, errors = null } = response;
|
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @author wingbot.ai
|
|
3
|
+
*/
|
|
4
|
+
'use strict';
|
|
5
|
+
|
|
6
|
+
const LEVEL_CRITICAL = 'Critical';
|
|
7
|
+
const LEVEL_IMPORTANT = 'Important';
|
|
8
|
+
const LEVEL_DEBUG = 'Debug';
|
|
9
|
+
|
|
10
|
+
const TYPE_ERROR = 'Error';
|
|
11
|
+
const TYPE_WARN = 'Warn';
|
|
12
|
+
const TYPE_INFO = 'Info';
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* @typedef {object} TrackingEvent
|
|
16
|
+
* @prop {string} [type='audit']
|
|
17
|
+
* @prop {string} category
|
|
18
|
+
* @prop {string} action
|
|
19
|
+
* @prop {string} [label]
|
|
20
|
+
* @prop {object} [payload]
|
|
21
|
+
*/
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* @typedef {object} User
|
|
25
|
+
* @prop {string} [id]
|
|
26
|
+
* @prop {string} [senderId]
|
|
27
|
+
* @prop {string} [pageId]
|
|
28
|
+
* @prop {string} [jwt] - jwt to check the authorship
|
|
29
|
+
*/
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* @typedef {object} Meta
|
|
33
|
+
* @prop {string} [ip]
|
|
34
|
+
* @prop {string} [ua]
|
|
35
|
+
* @prop {string} [ro] - referrer || origin
|
|
36
|
+
*/
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* @typedef {object} Logger
|
|
40
|
+
* @prop {Function} log
|
|
41
|
+
* @prop {Function} error
|
|
42
|
+
*/
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* @typedef {object} AuditLogEntry
|
|
46
|
+
* @prop {string} date - ISO date
|
|
47
|
+
* @prop {string} [eventType='audit']
|
|
48
|
+
* @prop {string} category
|
|
49
|
+
* @prop {string} action
|
|
50
|
+
* @prop {string} [label]
|
|
51
|
+
* @prop {object} [payload]
|
|
52
|
+
* @prop {string} level - (Critical|Important|Debug)
|
|
53
|
+
* @prop {string} type - (Error|Warn|Info)
|
|
54
|
+
* @prop {User} user
|
|
55
|
+
* @prop {string} wid - workspace id
|
|
56
|
+
* @prop {Meta} meta
|
|
57
|
+
*/
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* Audit Log Callback
|
|
61
|
+
*
|
|
62
|
+
* @callback AuditLogCallback
|
|
63
|
+
* @param {AuditLogEntry} entry
|
|
64
|
+
* @returns {Promise}
|
|
65
|
+
*/
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* Just a simple auditlog interface
|
|
69
|
+
*/
|
|
70
|
+
class CallbackAuditLog {
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
*
|
|
74
|
+
* @param {AuditLogCallback} callback
|
|
75
|
+
* @param {Logger} log
|
|
76
|
+
*/
|
|
77
|
+
constructor (callback = null, log = console) {
|
|
78
|
+
this._log = log;
|
|
79
|
+
this.defaultWid = '0';
|
|
80
|
+
|
|
81
|
+
this.LEVEL_CRITICAL = LEVEL_CRITICAL;
|
|
82
|
+
this.LEVEL_IMPORTANT = LEVEL_IMPORTANT;
|
|
83
|
+
this.LEVEL_DEBUG = LEVEL_DEBUG;
|
|
84
|
+
|
|
85
|
+
this.TYPE_ERROR = TYPE_ERROR;
|
|
86
|
+
this.TYPE_WARN = TYPE_WARN;
|
|
87
|
+
this.TYPE_INFO = TYPE_INFO;
|
|
88
|
+
|
|
89
|
+
/** @type {AuditLogCallback} */
|
|
90
|
+
this.callback = callback || (async (e) => {
|
|
91
|
+
const {
|
|
92
|
+
category,
|
|
93
|
+
action,
|
|
94
|
+
...rest
|
|
95
|
+
} = e;
|
|
96
|
+
log.log(`AuditLog: ${category} - ${action}`, rest);
|
|
97
|
+
});
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
/**
|
|
101
|
+
* Add a log
|
|
102
|
+
*
|
|
103
|
+
* @param {TrackingEvent} event
|
|
104
|
+
* @param {User} user
|
|
105
|
+
* @param {Meta} [meta]
|
|
106
|
+
* @param {string} [wid] - workspace ID
|
|
107
|
+
* @param {string} [type]
|
|
108
|
+
* @param {string} [level]
|
|
109
|
+
* @param {Date} [date]
|
|
110
|
+
* @returns {Promise}
|
|
111
|
+
*/
|
|
112
|
+
async log (
|
|
113
|
+
event,
|
|
114
|
+
user = {},
|
|
115
|
+
meta = {},
|
|
116
|
+
wid = this.defaultWid,
|
|
117
|
+
type = TYPE_INFO,
|
|
118
|
+
level = LEVEL_IMPORTANT,
|
|
119
|
+
date = new Date()
|
|
120
|
+
) {
|
|
121
|
+
const {
|
|
122
|
+
type: eventType = 'audit',
|
|
123
|
+
...rest
|
|
124
|
+
} = event;
|
|
125
|
+
const entry = {
|
|
126
|
+
date: date.toISOString(),
|
|
127
|
+
eventType,
|
|
128
|
+
...rest,
|
|
129
|
+
level,
|
|
130
|
+
meta,
|
|
131
|
+
type,
|
|
132
|
+
user,
|
|
133
|
+
wid
|
|
134
|
+
};
|
|
135
|
+
|
|
136
|
+
try {
|
|
137
|
+
await this.callback(entry);
|
|
138
|
+
} catch (e) {
|
|
139
|
+
this._log.error('Failed to send AuditLog', e, entry);
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
module.exports = CallbackAuditLog;
|
package/src/Responder.js
CHANGED
|
@@ -190,7 +190,7 @@ class Responder {
|
|
|
190
190
|
* Events are aggregated within ReturnSender and can be caught
|
|
191
191
|
* within Processor's `interaction` event (event.tracking.events)
|
|
192
192
|
*
|
|
193
|
-
* @param {string} type
|
|
193
|
+
* @param {string} type - (log,report,conversation,audit,user)
|
|
194
194
|
* @param {string} category
|
|
195
195
|
* @param {string} [action]
|
|
196
196
|
* @param {string} [label]
|
package/src/graphApi/GraphApi.js
CHANGED
|
@@ -8,6 +8,7 @@ const { graphql, buildSchema } = require('graphql');
|
|
|
8
8
|
const WingbotApiConnector = require('./WingbotApiConnector');
|
|
9
9
|
// @ts-ignore
|
|
10
10
|
const packageJson = require('../../package.json');
|
|
11
|
+
const headersToAuditMeta = require('../utils/headersToAuditMeta');
|
|
11
12
|
|
|
12
13
|
const DEFAULT_GROUPS = ['botEditor', 'botAdmin', 'appToken'];
|
|
13
14
|
const KEYS_URL = 'https://api.wingbot.ai/keys';
|
|
@@ -19,6 +20,8 @@ const DEFAULT_CACHE = 86400000; // 24 hours
|
|
|
19
20
|
* @param {object[]} [errors]
|
|
20
21
|
*/
|
|
21
22
|
|
|
23
|
+
/** @typedef {import('../CallbackAuditLog')} AuditLog */
|
|
24
|
+
|
|
22
25
|
/**
|
|
23
26
|
* Experimental chatbot API
|
|
24
27
|
*/
|
|
@@ -32,6 +35,7 @@ class GraphApi {
|
|
|
32
35
|
* @param {string} [options.appToken] - public token
|
|
33
36
|
* @param {string[]} [options.groups] - list of allowed bot groups
|
|
34
37
|
* @param {boolean} [options.useBundledGql] - uses library bundled graphql definition
|
|
38
|
+
* @param {AuditLog} [options.auditLog]
|
|
35
39
|
*/
|
|
36
40
|
constructor (apis, options) {
|
|
37
41
|
this._root = {
|
|
@@ -44,7 +48,16 @@ class GraphApi {
|
|
|
44
48
|
token: null,
|
|
45
49
|
groups: DEFAULT_GROUPS,
|
|
46
50
|
keysUrl: KEYS_URL,
|
|
47
|
-
cacheKeys: DEFAULT_CACHE
|
|
51
|
+
cacheKeys: DEFAULT_CACHE,
|
|
52
|
+
auditLog: {
|
|
53
|
+
async callback () {
|
|
54
|
+
// noop
|
|
55
|
+
},
|
|
56
|
+
defaultWid: '0',
|
|
57
|
+
async log () {
|
|
58
|
+
// noop
|
|
59
|
+
}
|
|
60
|
+
}
|
|
48
61
|
};
|
|
49
62
|
|
|
50
63
|
Object.assign(opts, options);
|
|
@@ -57,6 +70,10 @@ class GraphApi {
|
|
|
57
70
|
|
|
58
71
|
this._defaultGroups = opts.groups;
|
|
59
72
|
|
|
73
|
+
/** @type {AuditLog} */
|
|
74
|
+
// @ts-ignore
|
|
75
|
+
this.auditLog = opts.auditLog;
|
|
76
|
+
|
|
60
77
|
this._apiConnector = new WingbotApiConnector({
|
|
61
78
|
token: opts.token,
|
|
62
79
|
appToken: opts.appToken,
|
|
@@ -75,6 +92,10 @@ class GraphApi {
|
|
|
75
92
|
* @param {object} headers
|
|
76
93
|
* @param {string} [headers.Authorization]
|
|
77
94
|
* @param {string} [headers.authorization]
|
|
95
|
+
* @param {string} [headers.Origin]
|
|
96
|
+
* @param {string} [headers.origin]
|
|
97
|
+
* @param {string} [headers.Referer]
|
|
98
|
+
* @param {string} [headers.referer]
|
|
78
99
|
* @param {string} [wingbotToken]
|
|
79
100
|
* @returns {Promise<GraphQlResponse>}
|
|
80
101
|
*/
|
|
@@ -83,13 +104,39 @@ class GraphApi {
|
|
|
83
104
|
assert.equal(typeof body.query, 'string', 'GraphQL request should contain a query property');
|
|
84
105
|
|
|
85
106
|
const authHeader = headers.Authorization || headers.authorization;
|
|
86
|
-
|
|
107
|
+
let token = {};
|
|
108
|
+
|
|
109
|
+
const audit = async (action, payload = {}, important = false, warn = false) => {
|
|
110
|
+
await this.auditLog.log(
|
|
111
|
+
{
|
|
112
|
+
category: 'API',
|
|
113
|
+
action,
|
|
114
|
+
payload
|
|
115
|
+
},
|
|
116
|
+
{
|
|
117
|
+
id: token.id,
|
|
118
|
+
jwt: token.id && authHeader.replace(/^bearer\s/i, '')
|
|
119
|
+
},
|
|
120
|
+
headersToAuditMeta(headers),
|
|
121
|
+
this.auditLog.defaultWid,
|
|
122
|
+
warn ? 'Warn' : 'Info',
|
|
123
|
+
important ? 'Important' : 'Debug'
|
|
124
|
+
);
|
|
125
|
+
};
|
|
126
|
+
|
|
127
|
+
try {
|
|
128
|
+
token = await this._apiConnector.verifyToken(authHeader, wingbotToken);
|
|
129
|
+
} catch (e) {
|
|
130
|
+
await audit('authorization failed', { message: e.message, authHeader }, true, true);
|
|
131
|
+
throw e;
|
|
132
|
+
}
|
|
87
133
|
|
|
88
134
|
const schema = await this._schema();
|
|
89
135
|
|
|
90
136
|
const ctx = {
|
|
91
137
|
token,
|
|
92
|
-
groups: this._defaultGroups
|
|
138
|
+
groups: this._defaultGroups,
|
|
139
|
+
audit
|
|
93
140
|
};
|
|
94
141
|
|
|
95
142
|
// @ts-ignore
|
|
@@ -42,6 +42,8 @@ function conversationTestApi (testsSource, botFactory, options, acl) {
|
|
|
42
42
|
|
|
43
43
|
const { bot: validationRequestBody, step = null, lang = null } = args;
|
|
44
44
|
|
|
45
|
+
await ctx.audit('conversationTest', args);
|
|
46
|
+
|
|
45
47
|
return test.test(validationRequestBody, step, lang);
|
|
46
48
|
}
|
|
47
49
|
};
|
|
@@ -131,6 +131,8 @@ function conversationsApi (
|
|
|
131
131
|
condition
|
|
132
132
|
} = args;
|
|
133
133
|
|
|
134
|
+
await ctx.audit('conversations', args);
|
|
135
|
+
|
|
134
136
|
const { data, lastKey: nextKey } = await stateStorage
|
|
135
137
|
.getStates(condition || {}, limit, lastKey);
|
|
136
138
|
|
|
@@ -154,6 +156,8 @@ function conversationsApi (
|
|
|
154
156
|
senderId
|
|
155
157
|
} = args;
|
|
156
158
|
|
|
159
|
+
await ctx.audit('conversation', args);
|
|
160
|
+
|
|
157
161
|
const state = await stateStorage.getState(senderId, pageId);
|
|
158
162
|
|
|
159
163
|
if (!state) {
|
package/src/utils/getUpdate.js
CHANGED
|
@@ -179,7 +179,7 @@ function getSetState (setState = {}, req, res = null, useState = null) {
|
|
|
179
179
|
const useValue = typeof value === 'string'
|
|
180
180
|
? handlebars.compile(value)(stateData(req, res))
|
|
181
181
|
.split(/(?<!\\),/g)
|
|
182
|
-
.map((v) => v.trim())
|
|
182
|
+
.map((v) => v.replace(/\\,/g, ',').trim())
|
|
183
183
|
: value;
|
|
184
184
|
values = toArray(useValue);
|
|
185
185
|
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @author wingbot.ai
|
|
3
|
+
*/
|
|
4
|
+
'use strict';
|
|
5
|
+
|
|
6
|
+
module.exports = function headersToAuditMeta (headers) {
|
|
7
|
+
return {
|
|
8
|
+
ua: headers['User-Agent'] || headers['user-agent'] || headers['User-agent'],
|
|
9
|
+
ro: headers.Referer || headers.referer || headers.Origin || headers.origin,
|
|
10
|
+
ip: headers['X-Forwarded-For'] || headers['x-forwarded-for'] || headers['X-Azure-ClientIP'] || headers['x-azure-clientip']
|
|
11
|
+
};
|
|
12
|
+
};
|