wingbot 3.24.3 → 3.25.1
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 +45 -6
- package/src/CallbackAuditLog.js +145 -0
- package/src/Request.js +8 -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 +3 -0
- 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,8 @@ 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
|
+
|
|
23
26
|
/**
|
|
24
27
|
* @typedef {object} BotAppOptions
|
|
25
28
|
* @prop {string|Promise<string>} secret
|
|
@@ -28,6 +31,7 @@ const DEFAULT_API_URL = 'https://orchestrator-api.wingbot.ai';
|
|
|
28
31
|
* @prop {Function} [fetch]
|
|
29
32
|
* @prop {ChatLogStorage} [chatLogStorage]
|
|
30
33
|
* @prop {boolean} [preferSynchronousResponse]
|
|
34
|
+
* @prop {AuditLog} [auditLog]
|
|
31
35
|
*
|
|
32
36
|
* @typedef {ProcessorOptions & BotAppOptions} Options
|
|
33
37
|
*/
|
|
@@ -58,12 +62,14 @@ class BotApp {
|
|
|
58
62
|
fetch = null,
|
|
59
63
|
appId = null,
|
|
60
64
|
preferSynchronousResponse = false,
|
|
65
|
+
auditLog = null,
|
|
61
66
|
...processorOptions
|
|
62
67
|
} = options;
|
|
63
68
|
|
|
64
69
|
this._secret = Promise.resolve(secret);
|
|
65
70
|
this._fetch = fetch; // mock
|
|
66
71
|
this._appId = appId;
|
|
72
|
+
this._auditLog = auditLog;
|
|
67
73
|
|
|
68
74
|
let { apiUrl } = options;
|
|
69
75
|
|
|
@@ -140,13 +146,44 @@ class BotApp {
|
|
|
140
146
|
};
|
|
141
147
|
}
|
|
142
148
|
|
|
143
|
-
|
|
149
|
+
/**
|
|
150
|
+
* @param {ReturnSender} sender
|
|
151
|
+
* @param {string} senderId
|
|
152
|
+
* @param {string} pageId
|
|
153
|
+
* @param {object} headers
|
|
154
|
+
*/
|
|
155
|
+
async _processSenderResponses (sender, senderId, pageId, headers) {
|
|
156
|
+
if (!this._auditLog) {
|
|
157
|
+
return;
|
|
158
|
+
}
|
|
159
|
+
await Promise.all(
|
|
160
|
+
sender.tracking.events.map(async (event) => {
|
|
161
|
+
if (!['audit', 'report'].includes(event.type)) {
|
|
162
|
+
return;
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
await this._auditLog.log(
|
|
166
|
+
event,
|
|
167
|
+
{ senderId, pageId },
|
|
168
|
+
headersToAuditMeta(headers),
|
|
169
|
+
this._auditLog.defaultWid,
|
|
170
|
+
'Info',
|
|
171
|
+
event.type === 'audit' ? 'Important' : 'Debug'
|
|
172
|
+
);
|
|
173
|
+
})
|
|
174
|
+
);
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
async _processIncommingMessage (
|
|
178
|
+
message, senderId, pageId, appId, secret, sync = false, headers = {}
|
|
179
|
+
) {
|
|
144
180
|
const { mid = null } = message;
|
|
145
181
|
|
|
146
182
|
if (sync || this._preferSynchronousResponse) {
|
|
147
183
|
const sender = new ReturnSender({}, senderId, message, this._senderLogger);
|
|
148
184
|
sender.propagatesWaitEvent = true;
|
|
149
185
|
const res = await this._processor.processMessage(message, pageId, sender, { appId });
|
|
186
|
+
await this._processSenderResponses(sender, senderId, pageId, headers);
|
|
150
187
|
|
|
151
188
|
return {
|
|
152
189
|
status: res.status,
|
|
@@ -179,6 +216,7 @@ class BotApp {
|
|
|
179
216
|
|
|
180
217
|
const sender = new BotAppSender(options, senderId, message, this._senderLogger);
|
|
181
218
|
const res = await this._processor.processMessage(message, pageId, sender, { appId });
|
|
219
|
+
await this._processSenderResponses(sender, senderId, pageId, headers);
|
|
182
220
|
|
|
183
221
|
return {
|
|
184
222
|
status: res.status,
|
|
@@ -280,7 +318,7 @@ class BotApp {
|
|
|
280
318
|
|
|
281
319
|
const body = JSON.parse(rawBody);
|
|
282
320
|
|
|
283
|
-
const entry = await this._processEntries(appId, secret, body.entry);
|
|
321
|
+
const entry = await this._processEntries(appId, secret, body.entry, rawHeaders);
|
|
284
322
|
|
|
285
323
|
return {
|
|
286
324
|
statusCode: 200,
|
|
@@ -293,7 +331,7 @@ class BotApp {
|
|
|
293
331
|
};
|
|
294
332
|
}
|
|
295
333
|
|
|
296
|
-
async _processEntries (appId, secret, entry = []) {
|
|
334
|
+
async _processEntries (appId, secret, entry = [], headers = {}) {
|
|
297
335
|
return Promise.all(
|
|
298
336
|
entry.map(async (event) => {
|
|
299
337
|
const {
|
|
@@ -308,7 +346,8 @@ class BotApp {
|
|
|
308
346
|
...standby.map((e) => ({ ...e, isStandby: true }))
|
|
309
347
|
];
|
|
310
348
|
|
|
311
|
-
const responses = await this
|
|
349
|
+
const responses = await this
|
|
350
|
+
._processMessaging(events, pageId, appId, secret, sync, headers);
|
|
312
351
|
|
|
313
352
|
return {
|
|
314
353
|
id: pageId,
|
|
@@ -318,7 +357,7 @@ class BotApp {
|
|
|
318
357
|
);
|
|
319
358
|
}
|
|
320
359
|
|
|
321
|
-
async _processMessaging (process, pageId, appId, secret, sync) {
|
|
360
|
+
async _processMessaging (process, pageId, appId, secret, sync, headers) {
|
|
322
361
|
const eventsBySenderId = new Map();
|
|
323
362
|
process.forEach((e) => this._processMessagingArrayItem(e, eventsBySenderId));
|
|
324
363
|
|
|
@@ -329,7 +368,7 @@ class BotApp {
|
|
|
329
368
|
|
|
330
369
|
for (const message of messaging) {
|
|
331
370
|
const res = await this._processIncommingMessage(
|
|
332
|
-
message, senderId, pageId, appId, secret, sync
|
|
371
|
+
message, senderId, pageId, appId, secret, sync, headers
|
|
333
372
|
);
|
|
334
373
|
|
|
335
374
|
responses.push(res);
|
|
@@ -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/Request.js
CHANGED
|
@@ -322,6 +322,7 @@ class Request {
|
|
|
322
322
|
}
|
|
323
323
|
|
|
324
324
|
const text = this.text();
|
|
325
|
+
const knownTexts = new Set();
|
|
325
326
|
|
|
326
327
|
return (aiActions || this._aiActions)
|
|
327
328
|
.filter((a) => a.title)
|
|
@@ -381,6 +382,13 @@ class Request {
|
|
|
381
382
|
if (match) Object.assign(res, { match });
|
|
382
383
|
|
|
383
384
|
return res;
|
|
385
|
+
})
|
|
386
|
+
.filter((qr) => {
|
|
387
|
+
if (knownTexts.has(qr.title)) {
|
|
388
|
+
return false;
|
|
389
|
+
}
|
|
390
|
+
knownTexts.add(qr.title);
|
|
391
|
+
return true;
|
|
384
392
|
});
|
|
385
393
|
}
|
|
386
394
|
|
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
|
@@ -168,6 +168,9 @@ function getSetState (setState = {}, req, res = null, useState = null) {
|
|
|
168
168
|
if (entity && (!rear || req.entities.some((e) => e.entity === entity))) {
|
|
169
169
|
values = req.entities.filter((e) => e.entity === entity)
|
|
170
170
|
.map((e) => e.value);
|
|
171
|
+
if (values.length === 0 && useState && useState[`@${entity}`]) {
|
|
172
|
+
values = [useState[`@${entity}`]];
|
|
173
|
+
}
|
|
171
174
|
} else if (variable) {
|
|
172
175
|
values = toArray(getValue(variable, state));
|
|
173
176
|
} else if (value === '' || value === null || value === undefined) {
|
|
@@ -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
|
+
};
|