@microsoft/omnichannel-chat-widget 1.2.3-main.f8e3363 → 1.2.3
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/lib/cjs/common/telemetry/TelemetryConstants.js +1 -0
- package/lib/cjs/components/livechatwidget/common/ActivitySubscriber/BotAuthActivitySubscriber.js +4 -1
- package/lib/cjs/components/livechatwidget/common/reconnectChatHelper.js +12 -7
- package/lib/cjs/components/livechatwidget/common/startChat.js +6 -5
- package/lib/cjs/components/livechatwidget/livechatwidgetstateful/LiveChatWidgetStateful.js +16 -15
- package/lib/cjs/components/webchatcontainerstateful/webchatcontroller/middlewares/renderingmiddlewares/activityMiddleware.js +6 -3
- package/lib/cjs/components/webchatcontainerstateful/webchatcontroller/middlewares/renderingmiddlewares/activityMiddleware.spec.js +190 -0
- package/lib/esm/common/telemetry/TelemetryConstants.js +1 -0
- package/lib/esm/components/livechatwidget/common/ActivitySubscriber/BotAuthActivitySubscriber.js +4 -1
- package/lib/esm/components/livechatwidget/common/reconnectChatHelper.js +12 -7
- package/lib/esm/components/livechatwidget/common/startChat.js +6 -5
- package/lib/esm/components/livechatwidget/livechatwidgetstateful/LiveChatWidgetStateful.js +16 -15
- package/lib/esm/components/webchatcontainerstateful/webchatcontroller/middlewares/renderingmiddlewares/activityMiddleware.js +6 -3
- package/lib/esm/components/webchatcontainerstateful/webchatcontroller/middlewares/renderingmiddlewares/activityMiddleware.spec.js +188 -0
- package/lib/types/common/telemetry/TelemetryConstants.d.ts +1 -0
- package/lib/types/components/livechatwidget/common/reconnectChatHelper.d.ts +1 -1
- package/lib/types/components/webchatcontainerstateful/webchatcontroller/middlewares/renderingmiddlewares/activityMiddleware.spec.d.ts +1 -0
- package/package.json +1 -1
|
@@ -164,6 +164,7 @@ exports.TelemetryEvent = TelemetryEvent;
|
|
|
164
164
|
TelemetryEvent["SetBotAuthProviderHideCard"] = "SetBotAuthProviderHideCard";
|
|
165
165
|
TelemetryEvent["SetBotAuthProviderDisplayCard"] = "SetBotAuthProviderDisplayCard";
|
|
166
166
|
TelemetryEvent["SetBotAuthProviderNotFound"] = "SetBotAuthProviderNotFound";
|
|
167
|
+
TelemetryEvent["BotAuthActivityUndefinedSignInId"] = "BotAuthActivityUndefinedSignInId";
|
|
167
168
|
TelemetryEvent["ThirdPartyCookiesBlocked"] = "ThirdPartyCookiesBlocked";
|
|
168
169
|
TelemetryEvent["ProcessingHTMLTextMiddlewareFailed"] = "ProcessingHTMLTextMiddlewareFailed";
|
|
169
170
|
TelemetryEvent["ProcessingSanitizationMiddlewareFailed"] = "ProcessingSanitizationMiddlewareFailed";
|
package/lib/cjs/components/livechatwidget/common/ActivitySubscriber/BotAuthActivitySubscriber.js
CHANGED
|
@@ -83,7 +83,10 @@ class BotAuthActivitySubscriber {
|
|
|
83
83
|
const signInUrl = attachment.content.buttons[0].value;
|
|
84
84
|
const signInId = extractSignInId(signInUrl);
|
|
85
85
|
if (!signInId) {
|
|
86
|
-
|
|
86
|
+
_TelemetryHelper.TelemetryHelper.logLoadingEvent(_TelemetryConstants.LogLevel.INFO, {
|
|
87
|
+
Event: _TelemetryConstants.TelemetryEvent.BotAuthActivityUndefinedSignInId
|
|
88
|
+
});
|
|
89
|
+
return activity;
|
|
87
90
|
}
|
|
88
91
|
if (this.signInCardSeen.has(signInId)) {
|
|
89
92
|
// Prevents duplicate auth
|
|
@@ -13,10 +13,11 @@ var _Constants = require("../../../common/Constants");
|
|
|
13
13
|
var _ConversationState = require("../../../contexts/common/ConversationState");
|
|
14
14
|
var _LiveChatWidgetActionType = require("../../../contexts/common/LiveChatWidgetActionType");
|
|
15
15
|
var _TelemetryHelper = require("../../../common/telemetry/TelemetryHelper");
|
|
16
|
+
// Return value: should start normal chat flow when reconnect is enabled
|
|
16
17
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
17
18
|
const handleChatReconnect = async (chatSDK, props, dispatch, setAdapter, initStartChat, state) => {
|
|
18
19
|
var _props$chatConfig, _props$chatConfig$Liv;
|
|
19
|
-
if (!isReconnectEnabled(props.chatConfig) || isPersistentEnabled(props.chatConfig)) return;
|
|
20
|
+
if (!isReconnectEnabled(props.chatConfig) || isPersistentEnabled(props.chatConfig)) return false;
|
|
20
21
|
|
|
21
22
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
22
23
|
const isAuthenticatedChat = (_props$chatConfig = props.chatConfig) !== null && _props$chatConfig !== void 0 && (_props$chatConfig$Liv = _props$chatConfig.LiveChatConfigAuthSettings) !== null && _props$chatConfig$Liv !== void 0 && _props$chatConfig$Liv.msdyn_javascriptclientfunction ? true : false;
|
|
@@ -28,14 +29,14 @@ const handleChatReconnect = async (chatSDK, props, dispatch, setAdapter, initSta
|
|
|
28
29
|
if (reconnectChatContext !== null && reconnectChatContext !== void 0 && reconnectChatContext.redirectURL) {
|
|
29
30
|
var _props$reconnectChatP;
|
|
30
31
|
redirectPage(reconnectChatContext.redirectURL, (_props$reconnectChatP = props.reconnectChatPaneProps) === null || _props$reconnectChatP === void 0 ? void 0 : _props$reconnectChatP.redirectInSameWindow);
|
|
31
|
-
return;
|
|
32
|
+
return false;
|
|
32
33
|
}
|
|
33
34
|
if (hasReconnectId(reconnectChatContext)) {
|
|
34
35
|
var _props$reconnectChatP2, _props$reconnectChatP3;
|
|
35
36
|
//if reconnect id is provided in props, don't show reconnect pane
|
|
36
37
|
if ((_props$reconnectChatP2 = props.reconnectChatPaneProps) !== null && _props$reconnectChatP2 !== void 0 && _props$reconnectChatP2.reconnectId && !(0, _utils.isNullOrEmptyString)((_props$reconnectChatP3 = props.reconnectChatPaneProps) === null || _props$reconnectChatP3 === void 0 ? void 0 : _props$reconnectChatP3.reconnectId)) {
|
|
37
|
-
await setReconnectIdAndStartChat(isAuthenticatedChat, chatSDK, props, dispatch, setAdapter, reconnectChatContext.reconnectId ?? "", initStartChat);
|
|
38
|
-
return;
|
|
38
|
+
await setReconnectIdAndStartChat(isAuthenticatedChat, chatSDK, state, props, dispatch, setAdapter, reconnectChatContext.reconnectId ?? "", initStartChat);
|
|
39
|
+
return false;
|
|
39
40
|
}
|
|
40
41
|
|
|
41
42
|
//show reconnect pane
|
|
@@ -48,8 +49,12 @@ const handleChatReconnect = async (chatSDK, props, dispatch, setAdapter, initSta
|
|
|
48
49
|
type: _LiveChatWidgetActionType.LiveChatWidgetActionType.SET_CONVERSATION_STATE,
|
|
49
50
|
payload: _ConversationState.ConversationState.ReconnectChat
|
|
50
51
|
});
|
|
51
|
-
return;
|
|
52
|
+
return false;
|
|
52
53
|
}
|
|
54
|
+
|
|
55
|
+
// If we have reached this point, it means there is no valid reconnect id or redirectUrl
|
|
56
|
+
// This is a unauth reconnect refresh scenario - returns true so that we can start normal hydration process
|
|
57
|
+
return true;
|
|
53
58
|
};
|
|
54
59
|
|
|
55
60
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
@@ -88,7 +93,7 @@ const getChatReconnectContext = async (chatSDK, chatConfig, props, isAuthenticat
|
|
|
88
93
|
|
|
89
94
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
90
95
|
exports.getChatReconnectContext = getChatReconnectContext;
|
|
91
|
-
const setReconnectIdAndStartChat = async (isAuthenticatedChat, chatSDK, props, dispatch, setAdapter, reconnectId, initStartChat) => {
|
|
96
|
+
const setReconnectIdAndStartChat = async (isAuthenticatedChat, chatSDK, state, props, dispatch, setAdapter, reconnectId, initStartChat) => {
|
|
92
97
|
if (!isAuthenticatedChat) {
|
|
93
98
|
const startUnauthenticatedReconnectChat = {
|
|
94
99
|
eventName: _TelemetryConstants.BroadcastEvent.StartUnauthenticatedReconnectChat
|
|
@@ -106,7 +111,7 @@ const setReconnectIdAndStartChat = async (isAuthenticatedChat, chatSDK, props, d
|
|
|
106
111
|
type: _LiveChatWidgetActionType.LiveChatWidgetActionType.SET_CONVERSATION_STATE,
|
|
107
112
|
payload: _ConversationState.ConversationState.Loading
|
|
108
113
|
});
|
|
109
|
-
await initStartChat(chatSDK, dispatch, setAdapter, props, optionalParams);
|
|
114
|
+
await initStartChat(chatSDK, dispatch, setAdapter, state, props, optionalParams);
|
|
110
115
|
};
|
|
111
116
|
const redirectPage = (redirectURL, redirectInSameWindow) => {
|
|
112
117
|
const redirectPageRequest = {
|
|
@@ -303,16 +303,17 @@ const canConnectToExistingChat = async (props, chatSDK, state, dispatch, setAdap
|
|
|
303
303
|
|
|
304
304
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
305
305
|
const setCustomContextParams = async (state, props) => {
|
|
306
|
-
var _props$chatConfig, _props$chatConfig$Liv, _persistedState$domai8;
|
|
306
|
+
var _props$chatConfig, _props$chatConfig$Liv, _state$domainStates, _persistedState$domai8;
|
|
307
307
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
308
308
|
const isAuthenticatedChat = props !== null && props !== void 0 && (_props$chatConfig = props.chatConfig) !== null && _props$chatConfig !== void 0 && (_props$chatConfig$Liv = _props$chatConfig.LiveChatConfigAuthSettings) !== null && _props$chatConfig$Liv !== void 0 && _props$chatConfig$Liv.msdyn_javascriptclientfunction ? true : false;
|
|
309
309
|
//Should not set custom context for auth chat
|
|
310
310
|
if (isAuthenticatedChat) {
|
|
311
311
|
return;
|
|
312
312
|
}
|
|
313
|
-
if (state !== null && state !== void 0 && state.domainStates.customContext) {
|
|
313
|
+
if (state !== null && state !== void 0 && (_state$domainStates = state.domainStates) !== null && _state$domainStates !== void 0 && _state$domainStates.customContext) {
|
|
314
|
+
var _state$domainStates2;
|
|
314
315
|
optionalParams = Object.assign({}, optionalParams, {
|
|
315
|
-
customContext: JSON.parse(JSON.stringify(state === null || state === void 0 ? void 0 : state.domainStates.customContext))
|
|
316
|
+
customContext: JSON.parse(JSON.stringify(state === null || state === void 0 ? void 0 : (_state$domainStates2 = state.domainStates) === null || _state$domainStates2 === void 0 ? void 0 : _state$domainStates2.customContext))
|
|
316
317
|
});
|
|
317
318
|
return;
|
|
318
319
|
}
|
|
@@ -360,8 +361,8 @@ const canStartPopoutChat = async props => {
|
|
|
360
361
|
|
|
361
362
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
362
363
|
const checkIfConversationStillValid = async (chatSDK, dispatch, state) => {
|
|
363
|
-
var _state$
|
|
364
|
-
const requestIdFromCache = (_state$
|
|
364
|
+
var _state$domainStates3, _state$domainStates3$;
|
|
365
|
+
const requestIdFromCache = (_state$domainStates3 = state.domainStates) === null || _state$domainStates3 === void 0 ? void 0 : (_state$domainStates3$ = _state$domainStates3.liveChatContext) === null || _state$domainStates3$ === void 0 ? void 0 : _state$domainStates3$.requestId;
|
|
365
366
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
366
367
|
let conversationDetails = undefined;
|
|
367
368
|
|
|
@@ -116,6 +116,16 @@ const LiveChatWidgetStateful = props => {
|
|
|
116
116
|
|
|
117
117
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
118
118
|
const startChat = async (props, localState) => {
|
|
119
|
+
const isReconnectTriggered = async () => {
|
|
120
|
+
if ((0, _reconnectChatHelper.isReconnectEnabled)(props.chatConfig) === true && !(0, _reconnectChatHelper.isPersistentEnabled)(props.chatConfig)) {
|
|
121
|
+
const noValidReconnectId = await (0, _reconnectChatHelper.handleChatReconnect)(chatSDK, props, dispatch, setAdapter, _startChat.initStartChat, state);
|
|
122
|
+
// If chat reconnect has kicked in chat state will become Active or Reconnect. So just exit, else go next
|
|
123
|
+
if (!noValidReconnectId && (state.appStates.conversationState === _ConversationState.ConversationState.Active || state.appStates.conversationState === _ConversationState.ConversationState.ReconnectChat)) {
|
|
124
|
+
return true;
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
return false;
|
|
128
|
+
};
|
|
119
129
|
let isChatValid = false;
|
|
120
130
|
//Start a chat from cache/reconnectid
|
|
121
131
|
if (activeCachedChatExist === true) {
|
|
@@ -130,29 +140,20 @@ const LiveChatWidgetStateful = props => {
|
|
|
130
140
|
//Check if conversation state is not in wrapup or closed state
|
|
131
141
|
isChatValid = await (0, _startChat.checkIfConversationStillValid)(chatSDK, dispatch, state);
|
|
132
142
|
if (isChatValid === true) {
|
|
133
|
-
|
|
134
|
-
if (
|
|
135
|
-
await (0,
|
|
136
|
-
// If chat reconnect has kicked in chat state will become Active or Reconnect. So just exit, else go next
|
|
137
|
-
if (state.appStates.conversationState === _ConversationState.ConversationState.Active || state.appStates.conversationState === _ConversationState.ConversationState.ReconnectChat) {
|
|
138
|
-
return;
|
|
139
|
-
}
|
|
143
|
+
const reconnectTriggered = await isReconnectTriggered();
|
|
144
|
+
if (!reconnectTriggered) {
|
|
145
|
+
await (0, _startChat.initStartChat)(chatSDK, dispatch, setAdapter, state, props, optionalParams);
|
|
140
146
|
}
|
|
141
|
-
await (0, _startChat.initStartChat)(chatSDK, dispatch, setAdapter, state, props, optionalParams);
|
|
142
147
|
return;
|
|
143
148
|
}
|
|
144
149
|
}
|
|
145
150
|
if (isChatValid === false) {
|
|
146
151
|
if (localState) {
|
|
147
152
|
// adding the reconnect logic for the case when customer tries to reconnect from a new browser or InPrivate browser
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
if (state.appStates.conversationState === _ConversationState.ConversationState.Active || state.appStates.conversationState === _ConversationState.ConversationState.ReconnectChat) {
|
|
152
|
-
return;
|
|
153
|
-
}
|
|
153
|
+
const reconnectTriggered = await isReconnectTriggered();
|
|
154
|
+
if (!reconnectTriggered) {
|
|
155
|
+
await (0, _startChat.setPreChatAndInitiateChat)(chatSDK, dispatch, setAdapter, undefined, undefined, localState, props);
|
|
154
156
|
}
|
|
155
|
-
await (0, _startChat.setPreChatAndInitiateChat)(chatSDK, dispatch, setAdapter, undefined, undefined, localState, props);
|
|
156
157
|
return;
|
|
157
158
|
} else {
|
|
158
159
|
var _state$appStates4;
|
|
@@ -51,12 +51,15 @@ const handleSystemMessage = (next, args, card, systemMessageStyleProps) => {
|
|
|
51
51
|
return () => false;
|
|
52
52
|
}
|
|
53
53
|
|
|
54
|
-
// eslint-disable-next-line react/display-name
|
|
54
|
+
// eslint-disable-next-line react/display-name
|
|
55
55
|
return () => /*#__PURE__*/_react.default.createElement("div", {
|
|
56
56
|
key: card.activity.id,
|
|
57
57
|
style: systemMessageStyles,
|
|
58
|
-
"aria-hidden": "true"
|
|
59
|
-
|
|
58
|
+
"aria-hidden": "true",
|
|
59
|
+
dangerouslySetInnerHTML: {
|
|
60
|
+
__html: (0, _utils.escapeHtml)(card.activity.text)
|
|
61
|
+
}
|
|
62
|
+
});
|
|
60
63
|
};
|
|
61
64
|
|
|
62
65
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
@@ -0,0 +1,190 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
var _Constants = require("../../../../../common/Constants");
|
|
4
|
+
var _DirectLineActivityType = require("../../enums/DirectLineActivityType");
|
|
5
|
+
var _DirectLineSenderRole = require("../../enums/DirectLineSenderRole");
|
|
6
|
+
var _MessageType = require("../../enums/MessageType");
|
|
7
|
+
var _TelemetryHelper = require("../../../../../common/telemetry/TelemetryHelper");
|
|
8
|
+
var _activityMiddleware = require("./activityMiddleware");
|
|
9
|
+
describe("activityMiddleware test", () => {
|
|
10
|
+
it("createActivityMiddleware() with Channel role sender should returns nothing", () => {
|
|
11
|
+
spyOn(_TelemetryHelper.TelemetryHelper, "logActionEvent").and.callFake(() => false);
|
|
12
|
+
const next = args => () => args; // eslint-disable-line @typescript-eslint/no-explicit-any
|
|
13
|
+
const args = {
|
|
14
|
+
activity: {
|
|
15
|
+
channelData: {
|
|
16
|
+
type: _MessageType.MessageTypes.Thread
|
|
17
|
+
},
|
|
18
|
+
from: {
|
|
19
|
+
role: _DirectLineSenderRole.DirectLineSenderRole.Channel
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
};
|
|
23
|
+
const results = (0, _activityMiddleware.createActivityMiddleware)()()(next)(args);
|
|
24
|
+
expect(results()).toEqual(false);
|
|
25
|
+
expect(_TelemetryHelper.TelemetryHelper.logActionEvent).toHaveBeenCalledTimes(1);
|
|
26
|
+
});
|
|
27
|
+
it("createActivityMiddleware() with Hidden tag should return nothing", () => {
|
|
28
|
+
spyOn(_TelemetryHelper.TelemetryHelper, "logActionEvent").and.callFake(() => false);
|
|
29
|
+
const next = args => () => args; // eslint-disable-line @typescript-eslint/no-explicit-any
|
|
30
|
+
const args = {
|
|
31
|
+
activity: {
|
|
32
|
+
channelData: {
|
|
33
|
+
tags: [_Constants.Constants.hiddenTag]
|
|
34
|
+
},
|
|
35
|
+
from: {
|
|
36
|
+
role: _DirectLineSenderRole.DirectLineSenderRole.User
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
};
|
|
40
|
+
const results = (0, _activityMiddleware.createActivityMiddleware)()()(next)(args);
|
|
41
|
+
expect(results()).toEqual(false);
|
|
42
|
+
expect(_TelemetryHelper.TelemetryHelper.logActionEvent).toHaveBeenCalledTimes(0);
|
|
43
|
+
});
|
|
44
|
+
it("createActivityMiddleware() with System tag should return system message", () => {
|
|
45
|
+
var _results$props, _results$props$danger;
|
|
46
|
+
spyOn(_TelemetryHelper.TelemetryHelper, "logActionEvent").and.callFake(() => false);
|
|
47
|
+
const next = args => () => args; // eslint-disable-line @typescript-eslint/no-explicit-any
|
|
48
|
+
const systemMessage = "system message";
|
|
49
|
+
const args = {
|
|
50
|
+
activity: {
|
|
51
|
+
text: systemMessage,
|
|
52
|
+
channelData: {
|
|
53
|
+
tags: [_Constants.Constants.systemMessageTag]
|
|
54
|
+
},
|
|
55
|
+
from: {
|
|
56
|
+
role: _DirectLineSenderRole.DirectLineSenderRole.User
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
};
|
|
60
|
+
const results = (0, _activityMiddleware.createActivityMiddleware)()()(next)(args);
|
|
61
|
+
expect(_TelemetryHelper.TelemetryHelper.logActionEvent).toHaveBeenCalledTimes(0);
|
|
62
|
+
expect((_results$props = results().props) === null || _results$props === void 0 ? void 0 : (_results$props$danger = _results$props.dangerouslySetInnerHTML) === null || _results$props$danger === void 0 ? void 0 : _results$props$danger.__html).toEqual(systemMessage);
|
|
63
|
+
});
|
|
64
|
+
it("createActivityMiddleware() should escape html texts to prevent XSS attacks", () => {
|
|
65
|
+
var _results$props2, _results$props2$dange;
|
|
66
|
+
spyOn(_TelemetryHelper.TelemetryHelper, "logActionEvent").and.callFake(() => false);
|
|
67
|
+
const next = args => () => args; // eslint-disable-line @typescript-eslint/no-explicit-any
|
|
68
|
+
const systemMessage = "<img src='' onerror=\"alert('XSS attack')\"/>";
|
|
69
|
+
const args = {
|
|
70
|
+
activity: {
|
|
71
|
+
text: systemMessage,
|
|
72
|
+
channelData: {
|
|
73
|
+
tags: [_Constants.Constants.systemMessageTag]
|
|
74
|
+
},
|
|
75
|
+
from: {
|
|
76
|
+
role: _DirectLineSenderRole.DirectLineSenderRole.User
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
};
|
|
80
|
+
const results = (0, _activityMiddleware.createActivityMiddleware)()()(next)(args);
|
|
81
|
+
expect(_TelemetryHelper.TelemetryHelper.logActionEvent).toHaveBeenCalledTimes(0);
|
|
82
|
+
expect((_results$props2 = results().props) === null || _results$props2 === void 0 ? void 0 : (_results$props2$dange = _results$props2.dangerouslySetInnerHTML) === null || _results$props2$dange === void 0 ? void 0 : _results$props2$dange.__html).toEqual("<img src='' onerror="alert('XSS attack')"/>");
|
|
83
|
+
});
|
|
84
|
+
it("createActivityMiddleware() with QueuePosition tag should log QueuePosition message", () => {
|
|
85
|
+
spyOn(_TelemetryHelper.TelemetryHelper, "logActionEvent").and.callFake(() => false);
|
|
86
|
+
const next = args => () => args; // eslint-disable-line @typescript-eslint/no-explicit-any
|
|
87
|
+
const systemMessage = "system message";
|
|
88
|
+
const args = {
|
|
89
|
+
activity: {
|
|
90
|
+
text: systemMessage,
|
|
91
|
+
channelData: {
|
|
92
|
+
tags: [_Constants.Constants.systemMessageTag, _Constants.Constants.queuePositionMessageTag]
|
|
93
|
+
},
|
|
94
|
+
from: {
|
|
95
|
+
role: _DirectLineSenderRole.DirectLineSenderRole.User
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
};
|
|
99
|
+
(0, _activityMiddleware.createActivityMiddleware)()()(next)(args);
|
|
100
|
+
expect(_TelemetryHelper.TelemetryHelper.logActionEvent).toHaveBeenCalledTimes(1);
|
|
101
|
+
});
|
|
102
|
+
it("createActivityMiddleware() with same clientmessageid with next activity should return nothing", () => {
|
|
103
|
+
spyOn(_TelemetryHelper.TelemetryHelper, "logActionEvent").and.callFake(() => false);
|
|
104
|
+
const next = args => () => args; // eslint-disable-line @typescript-eslint/no-explicit-any
|
|
105
|
+
const systemMessage = "system message";
|
|
106
|
+
const args = {
|
|
107
|
+
activity: {
|
|
108
|
+
text: systemMessage,
|
|
109
|
+
channelData: {
|
|
110
|
+
tags: [_Constants.Constants.systemMessageTag],
|
|
111
|
+
clientmessageid: "1234"
|
|
112
|
+
},
|
|
113
|
+
from: {
|
|
114
|
+
role: _DirectLineSenderRole.DirectLineSenderRole.User
|
|
115
|
+
}
|
|
116
|
+
},
|
|
117
|
+
nextVisibleActivity: {
|
|
118
|
+
channelData: {
|
|
119
|
+
clientmessageid: "1234"
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
};
|
|
123
|
+
const results = (0, _activityMiddleware.createActivityMiddleware)()()(next)(args);
|
|
124
|
+
expect(results()).toEqual(false);
|
|
125
|
+
});
|
|
126
|
+
it("createActivityMiddleware() with same messageid with next activity should return nothing", () => {
|
|
127
|
+
spyOn(_TelemetryHelper.TelemetryHelper, "logActionEvent").and.callFake(() => false);
|
|
128
|
+
const next = args => () => args; // eslint-disable-line @typescript-eslint/no-explicit-any
|
|
129
|
+
const systemMessage = "system message";
|
|
130
|
+
const args = {
|
|
131
|
+
activity: {
|
|
132
|
+
text: systemMessage,
|
|
133
|
+
channelData: {
|
|
134
|
+
tags: [_Constants.Constants.systemMessageTag]
|
|
135
|
+
},
|
|
136
|
+
from: {
|
|
137
|
+
role: _DirectLineSenderRole.DirectLineSenderRole.User
|
|
138
|
+
},
|
|
139
|
+
messageid: "1234"
|
|
140
|
+
},
|
|
141
|
+
nextVisibleActivity: {
|
|
142
|
+
messageid: "1234"
|
|
143
|
+
}
|
|
144
|
+
};
|
|
145
|
+
const results = (0, _activityMiddleware.createActivityMiddleware)()()(next)(args);
|
|
146
|
+
expect(results()).toEqual(false);
|
|
147
|
+
});
|
|
148
|
+
it("createActivityMiddleware() should render normal user messages", () => {
|
|
149
|
+
var _results$props3, _results$props3$child, _results$props3$child2;
|
|
150
|
+
spyOn(_TelemetryHelper.TelemetryHelper, "logActionEvent").and.callFake(() => false);
|
|
151
|
+
const next = args => () => args; // eslint-disable-line @typescript-eslint/no-explicit-any
|
|
152
|
+
const userMessage = "Hello World";
|
|
153
|
+
const args = {
|
|
154
|
+
activity: {
|
|
155
|
+
text: userMessage,
|
|
156
|
+
channelId: "webchat",
|
|
157
|
+
channelData: {
|
|
158
|
+
isHtmlEncoded: false
|
|
159
|
+
},
|
|
160
|
+
from: {
|
|
161
|
+
role: _DirectLineSenderRole.DirectLineSenderRole.User
|
|
162
|
+
},
|
|
163
|
+
type: _DirectLineActivityType.DirectLineActivityType.Message
|
|
164
|
+
}
|
|
165
|
+
};
|
|
166
|
+
const results = (0, _activityMiddleware.createActivityMiddleware)()()(next)(args);
|
|
167
|
+
expect((_results$props3 = results().props) === null || _results$props3 === void 0 ? void 0 : (_results$props3$child = _results$props3.children) === null || _results$props3$child === void 0 ? void 0 : (_results$props3$child2 = _results$props3$child.activity) === null || _results$props3$child2 === void 0 ? void 0 : _results$props3$child2.text).toEqual(userMessage);
|
|
168
|
+
});
|
|
169
|
+
it("createActivityMiddleware() should not render typing messages", () => {
|
|
170
|
+
var _results$activity;
|
|
171
|
+
spyOn(_TelemetryHelper.TelemetryHelper, "logActionEvent").and.callFake(() => false);
|
|
172
|
+
const next = args => () => args; // eslint-disable-line @typescript-eslint/no-explicit-any
|
|
173
|
+
const userMessage = "Hello World";
|
|
174
|
+
const args = {
|
|
175
|
+
activity: {
|
|
176
|
+
text: userMessage,
|
|
177
|
+
channelId: "webchat",
|
|
178
|
+
channelData: {
|
|
179
|
+
isHtmlEncoded: false
|
|
180
|
+
},
|
|
181
|
+
from: {
|
|
182
|
+
role: _DirectLineSenderRole.DirectLineSenderRole.User
|
|
183
|
+
},
|
|
184
|
+
type: _DirectLineActivityType.DirectLineActivityType.Typing
|
|
185
|
+
}
|
|
186
|
+
};
|
|
187
|
+
const results = (0, _activityMiddleware.createActivityMiddleware)()()(next)(args);
|
|
188
|
+
expect((_results$activity = results().activity) === null || _results$activity === void 0 ? void 0 : _results$activity.text).toEqual(userMessage);
|
|
189
|
+
});
|
|
190
|
+
});
|
|
@@ -158,6 +158,7 @@ export let TelemetryEvent;
|
|
|
158
158
|
TelemetryEvent["SetBotAuthProviderHideCard"] = "SetBotAuthProviderHideCard";
|
|
159
159
|
TelemetryEvent["SetBotAuthProviderDisplayCard"] = "SetBotAuthProviderDisplayCard";
|
|
160
160
|
TelemetryEvent["SetBotAuthProviderNotFound"] = "SetBotAuthProviderNotFound";
|
|
161
|
+
TelemetryEvent["BotAuthActivityUndefinedSignInId"] = "BotAuthActivityUndefinedSignInId";
|
|
161
162
|
TelemetryEvent["ThirdPartyCookiesBlocked"] = "ThirdPartyCookiesBlocked";
|
|
162
163
|
TelemetryEvent["ProcessingHTMLTextMiddlewareFailed"] = "ProcessingHTMLTextMiddlewareFailed";
|
|
163
164
|
TelemetryEvent["ProcessingSanitizationMiddlewareFailed"] = "ProcessingSanitizationMiddlewareFailed";
|
package/lib/esm/components/livechatwidget/common/ActivitySubscriber/BotAuthActivitySubscriber.js
CHANGED
|
@@ -79,7 +79,10 @@ export class BotAuthActivitySubscriber {
|
|
|
79
79
|
const signInUrl = attachment.content.buttons[0].value;
|
|
80
80
|
const signInId = extractSignInId(signInUrl);
|
|
81
81
|
if (!signInId) {
|
|
82
|
-
|
|
82
|
+
TelemetryHelper.logLoadingEvent(LogLevel.INFO, {
|
|
83
|
+
Event: TelemetryEvent.BotAuthActivityUndefinedSignInId
|
|
84
|
+
});
|
|
85
|
+
return activity;
|
|
83
86
|
}
|
|
84
87
|
if (this.signInCardSeen.has(signInId)) {
|
|
85
88
|
// Prevents duplicate auth
|
|
@@ -8,10 +8,11 @@ import { ConversationState } from "../../../contexts/common/ConversationState";
|
|
|
8
8
|
import { LiveChatWidgetActionType } from "../../../contexts/common/LiveChatWidgetActionType";
|
|
9
9
|
import { TelemetryHelper } from "../../../common/telemetry/TelemetryHelper";
|
|
10
10
|
|
|
11
|
+
// Return value: should start normal chat flow when reconnect is enabled
|
|
11
12
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
12
13
|
const handleChatReconnect = async (chatSDK, props, dispatch, setAdapter, initStartChat, state) => {
|
|
13
14
|
var _props$chatConfig, _props$chatConfig$Liv;
|
|
14
|
-
if (!isReconnectEnabled(props.chatConfig) || isPersistentEnabled(props.chatConfig)) return;
|
|
15
|
+
if (!isReconnectEnabled(props.chatConfig) || isPersistentEnabled(props.chatConfig)) return false;
|
|
15
16
|
|
|
16
17
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
17
18
|
const isAuthenticatedChat = (_props$chatConfig = props.chatConfig) !== null && _props$chatConfig !== void 0 && (_props$chatConfig$Liv = _props$chatConfig.LiveChatConfigAuthSettings) !== null && _props$chatConfig$Liv !== void 0 && _props$chatConfig$Liv.msdyn_javascriptclientfunction ? true : false;
|
|
@@ -23,14 +24,14 @@ const handleChatReconnect = async (chatSDK, props, dispatch, setAdapter, initSta
|
|
|
23
24
|
if (reconnectChatContext !== null && reconnectChatContext !== void 0 && reconnectChatContext.redirectURL) {
|
|
24
25
|
var _props$reconnectChatP;
|
|
25
26
|
redirectPage(reconnectChatContext.redirectURL, (_props$reconnectChatP = props.reconnectChatPaneProps) === null || _props$reconnectChatP === void 0 ? void 0 : _props$reconnectChatP.redirectInSameWindow);
|
|
26
|
-
return;
|
|
27
|
+
return false;
|
|
27
28
|
}
|
|
28
29
|
if (hasReconnectId(reconnectChatContext)) {
|
|
29
30
|
var _props$reconnectChatP2, _props$reconnectChatP3;
|
|
30
31
|
//if reconnect id is provided in props, don't show reconnect pane
|
|
31
32
|
if ((_props$reconnectChatP2 = props.reconnectChatPaneProps) !== null && _props$reconnectChatP2 !== void 0 && _props$reconnectChatP2.reconnectId && !isNullOrEmptyString((_props$reconnectChatP3 = props.reconnectChatPaneProps) === null || _props$reconnectChatP3 === void 0 ? void 0 : _props$reconnectChatP3.reconnectId)) {
|
|
32
|
-
await setReconnectIdAndStartChat(isAuthenticatedChat, chatSDK, props, dispatch, setAdapter, reconnectChatContext.reconnectId ?? "", initStartChat);
|
|
33
|
-
return;
|
|
33
|
+
await setReconnectIdAndStartChat(isAuthenticatedChat, chatSDK, state, props, dispatch, setAdapter, reconnectChatContext.reconnectId ?? "", initStartChat);
|
|
34
|
+
return false;
|
|
34
35
|
}
|
|
35
36
|
|
|
36
37
|
//show reconnect pane
|
|
@@ -43,8 +44,12 @@ const handleChatReconnect = async (chatSDK, props, dispatch, setAdapter, initSta
|
|
|
43
44
|
type: LiveChatWidgetActionType.SET_CONVERSATION_STATE,
|
|
44
45
|
payload: ConversationState.ReconnectChat
|
|
45
46
|
});
|
|
46
|
-
return;
|
|
47
|
+
return false;
|
|
47
48
|
}
|
|
49
|
+
|
|
50
|
+
// If we have reached this point, it means there is no valid reconnect id or redirectUrl
|
|
51
|
+
// This is a unauth reconnect refresh scenario - returns true so that we can start normal hydration process
|
|
52
|
+
return true;
|
|
48
53
|
};
|
|
49
54
|
|
|
50
55
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
@@ -81,7 +86,7 @@ const getChatReconnectContext = async (chatSDK, chatConfig, props, isAuthenticat
|
|
|
81
86
|
};
|
|
82
87
|
|
|
83
88
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
84
|
-
const setReconnectIdAndStartChat = async (isAuthenticatedChat, chatSDK, props, dispatch, setAdapter, reconnectId, initStartChat) => {
|
|
89
|
+
const setReconnectIdAndStartChat = async (isAuthenticatedChat, chatSDK, state, props, dispatch, setAdapter, reconnectId, initStartChat) => {
|
|
85
90
|
if (!isAuthenticatedChat) {
|
|
86
91
|
const startUnauthenticatedReconnectChat = {
|
|
87
92
|
eventName: BroadcastEvent.StartUnauthenticatedReconnectChat
|
|
@@ -99,7 +104,7 @@ const setReconnectIdAndStartChat = async (isAuthenticatedChat, chatSDK, props, d
|
|
|
99
104
|
type: LiveChatWidgetActionType.SET_CONVERSATION_STATE,
|
|
100
105
|
payload: ConversationState.Loading
|
|
101
106
|
});
|
|
102
|
-
await initStartChat(chatSDK, dispatch, setAdapter, props, optionalParams);
|
|
107
|
+
await initStartChat(chatSDK, dispatch, setAdapter, state, props, optionalParams);
|
|
103
108
|
};
|
|
104
109
|
const redirectPage = (redirectURL, redirectInSameWindow) => {
|
|
105
110
|
const redirectPageRequest = {
|
|
@@ -295,16 +295,17 @@ const canConnectToExistingChat = async (props, chatSDK, state, dispatch, setAdap
|
|
|
295
295
|
|
|
296
296
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
297
297
|
const setCustomContextParams = async (state, props) => {
|
|
298
|
-
var _props$chatConfig, _props$chatConfig$Liv, _persistedState$domai8;
|
|
298
|
+
var _props$chatConfig, _props$chatConfig$Liv, _state$domainStates, _persistedState$domai8;
|
|
299
299
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
300
300
|
const isAuthenticatedChat = props !== null && props !== void 0 && (_props$chatConfig = props.chatConfig) !== null && _props$chatConfig !== void 0 && (_props$chatConfig$Liv = _props$chatConfig.LiveChatConfigAuthSettings) !== null && _props$chatConfig$Liv !== void 0 && _props$chatConfig$Liv.msdyn_javascriptclientfunction ? true : false;
|
|
301
301
|
//Should not set custom context for auth chat
|
|
302
302
|
if (isAuthenticatedChat) {
|
|
303
303
|
return;
|
|
304
304
|
}
|
|
305
|
-
if (state !== null && state !== void 0 && state.domainStates.customContext) {
|
|
305
|
+
if (state !== null && state !== void 0 && (_state$domainStates = state.domainStates) !== null && _state$domainStates !== void 0 && _state$domainStates.customContext) {
|
|
306
|
+
var _state$domainStates2;
|
|
306
307
|
optionalParams = Object.assign({}, optionalParams, {
|
|
307
|
-
customContext: JSON.parse(JSON.stringify(state === null || state === void 0 ? void 0 : state.domainStates.customContext))
|
|
308
|
+
customContext: JSON.parse(JSON.stringify(state === null || state === void 0 ? void 0 : (_state$domainStates2 = state.domainStates) === null || _state$domainStates2 === void 0 ? void 0 : _state$domainStates2.customContext))
|
|
308
309
|
});
|
|
309
310
|
return;
|
|
310
311
|
}
|
|
@@ -352,8 +353,8 @@ const canStartPopoutChat = async props => {
|
|
|
352
353
|
|
|
353
354
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
354
355
|
const checkIfConversationStillValid = async (chatSDK, dispatch, state) => {
|
|
355
|
-
var _state$
|
|
356
|
-
const requestIdFromCache = (_state$
|
|
356
|
+
var _state$domainStates3, _state$domainStates3$;
|
|
357
|
+
const requestIdFromCache = (_state$domainStates3 = state.domainStates) === null || _state$domainStates3 === void 0 ? void 0 : (_state$domainStates3$ = _state$domainStates3.liveChatContext) === null || _state$domainStates3$ === void 0 ? void 0 : _state$domainStates3$.requestId;
|
|
357
358
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
358
359
|
let conversationDetails = undefined;
|
|
359
360
|
|
|
@@ -108,6 +108,16 @@ export const LiveChatWidgetStateful = props => {
|
|
|
108
108
|
|
|
109
109
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
110
110
|
const startChat = async (props, localState) => {
|
|
111
|
+
const isReconnectTriggered = async () => {
|
|
112
|
+
if (isReconnectEnabled(props.chatConfig) === true && !isPersistentEnabled(props.chatConfig)) {
|
|
113
|
+
const noValidReconnectId = await handleChatReconnect(chatSDK, props, dispatch, setAdapter, initStartChat, state);
|
|
114
|
+
// If chat reconnect has kicked in chat state will become Active or Reconnect. So just exit, else go next
|
|
115
|
+
if (!noValidReconnectId && (state.appStates.conversationState === ConversationState.Active || state.appStates.conversationState === ConversationState.ReconnectChat)) {
|
|
116
|
+
return true;
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
return false;
|
|
120
|
+
};
|
|
111
121
|
let isChatValid = false;
|
|
112
122
|
//Start a chat from cache/reconnectid
|
|
113
123
|
if (activeCachedChatExist === true) {
|
|
@@ -122,29 +132,20 @@ export const LiveChatWidgetStateful = props => {
|
|
|
122
132
|
//Check if conversation state is not in wrapup or closed state
|
|
123
133
|
isChatValid = await checkIfConversationStillValid(chatSDK, dispatch, state);
|
|
124
134
|
if (isChatValid === true) {
|
|
125
|
-
|
|
126
|
-
if (
|
|
127
|
-
await
|
|
128
|
-
// If chat reconnect has kicked in chat state will become Active or Reconnect. So just exit, else go next
|
|
129
|
-
if (state.appStates.conversationState === ConversationState.Active || state.appStates.conversationState === ConversationState.ReconnectChat) {
|
|
130
|
-
return;
|
|
131
|
-
}
|
|
135
|
+
const reconnectTriggered = await isReconnectTriggered();
|
|
136
|
+
if (!reconnectTriggered) {
|
|
137
|
+
await initStartChat(chatSDK, dispatch, setAdapter, state, props, optionalParams);
|
|
132
138
|
}
|
|
133
|
-
await initStartChat(chatSDK, dispatch, setAdapter, state, props, optionalParams);
|
|
134
139
|
return;
|
|
135
140
|
}
|
|
136
141
|
}
|
|
137
142
|
if (isChatValid === false) {
|
|
138
143
|
if (localState) {
|
|
139
144
|
// adding the reconnect logic for the case when customer tries to reconnect from a new browser or InPrivate browser
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
if (state.appStates.conversationState === ConversationState.Active || state.appStates.conversationState === ConversationState.ReconnectChat) {
|
|
144
|
-
return;
|
|
145
|
-
}
|
|
145
|
+
const reconnectTriggered = await isReconnectTriggered();
|
|
146
|
+
if (!reconnectTriggered) {
|
|
147
|
+
await setPreChatAndInitiateChat(chatSDK, dispatch, setAdapter, undefined, undefined, localState, props);
|
|
146
148
|
}
|
|
147
|
-
await setPreChatAndInitiateChat(chatSDK, dispatch, setAdapter, undefined, undefined, localState, props);
|
|
148
149
|
return;
|
|
149
150
|
} else {
|
|
150
151
|
var _state$appStates4;
|
|
@@ -44,12 +44,15 @@ const handleSystemMessage = (next, args, card, systemMessageStyleProps) => {
|
|
|
44
44
|
return () => false;
|
|
45
45
|
}
|
|
46
46
|
|
|
47
|
-
// eslint-disable-next-line react/display-name
|
|
47
|
+
// eslint-disable-next-line react/display-name
|
|
48
48
|
return () => /*#__PURE__*/React.createElement("div", {
|
|
49
49
|
key: card.activity.id,
|
|
50
50
|
style: systemMessageStyles,
|
|
51
|
-
"aria-hidden": "true"
|
|
52
|
-
|
|
51
|
+
"aria-hidden": "true",
|
|
52
|
+
dangerouslySetInnerHTML: {
|
|
53
|
+
__html: escapeHtml(card.activity.text)
|
|
54
|
+
}
|
|
55
|
+
});
|
|
53
56
|
};
|
|
54
57
|
|
|
55
58
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
@@ -0,0 +1,188 @@
|
|
|
1
|
+
import { Constants } from "../../../../../common/Constants";
|
|
2
|
+
import { DirectLineActivityType } from "../../enums/DirectLineActivityType";
|
|
3
|
+
import { DirectLineSenderRole } from "../../enums/DirectLineSenderRole";
|
|
4
|
+
import { MessageTypes } from "../../enums/MessageType";
|
|
5
|
+
import { TelemetryHelper } from "../../../../../common/telemetry/TelemetryHelper";
|
|
6
|
+
import { createActivityMiddleware } from "./activityMiddleware";
|
|
7
|
+
describe("activityMiddleware test", () => {
|
|
8
|
+
it("createActivityMiddleware() with Channel role sender should returns nothing", () => {
|
|
9
|
+
spyOn(TelemetryHelper, "logActionEvent").and.callFake(() => false);
|
|
10
|
+
const next = args => () => args; // eslint-disable-line @typescript-eslint/no-explicit-any
|
|
11
|
+
const args = {
|
|
12
|
+
activity: {
|
|
13
|
+
channelData: {
|
|
14
|
+
type: MessageTypes.Thread
|
|
15
|
+
},
|
|
16
|
+
from: {
|
|
17
|
+
role: DirectLineSenderRole.Channel
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
};
|
|
21
|
+
const results = createActivityMiddleware()()(next)(args);
|
|
22
|
+
expect(results()).toEqual(false);
|
|
23
|
+
expect(TelemetryHelper.logActionEvent).toHaveBeenCalledTimes(1);
|
|
24
|
+
});
|
|
25
|
+
it("createActivityMiddleware() with Hidden tag should return nothing", () => {
|
|
26
|
+
spyOn(TelemetryHelper, "logActionEvent").and.callFake(() => false);
|
|
27
|
+
const next = args => () => args; // eslint-disable-line @typescript-eslint/no-explicit-any
|
|
28
|
+
const args = {
|
|
29
|
+
activity: {
|
|
30
|
+
channelData: {
|
|
31
|
+
tags: [Constants.hiddenTag]
|
|
32
|
+
},
|
|
33
|
+
from: {
|
|
34
|
+
role: DirectLineSenderRole.User
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
};
|
|
38
|
+
const results = createActivityMiddleware()()(next)(args);
|
|
39
|
+
expect(results()).toEqual(false);
|
|
40
|
+
expect(TelemetryHelper.logActionEvent).toHaveBeenCalledTimes(0);
|
|
41
|
+
});
|
|
42
|
+
it("createActivityMiddleware() with System tag should return system message", () => {
|
|
43
|
+
var _results$props, _results$props$danger;
|
|
44
|
+
spyOn(TelemetryHelper, "logActionEvent").and.callFake(() => false);
|
|
45
|
+
const next = args => () => args; // eslint-disable-line @typescript-eslint/no-explicit-any
|
|
46
|
+
const systemMessage = "system message";
|
|
47
|
+
const args = {
|
|
48
|
+
activity: {
|
|
49
|
+
text: systemMessage,
|
|
50
|
+
channelData: {
|
|
51
|
+
tags: [Constants.systemMessageTag]
|
|
52
|
+
},
|
|
53
|
+
from: {
|
|
54
|
+
role: DirectLineSenderRole.User
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
};
|
|
58
|
+
const results = createActivityMiddleware()()(next)(args);
|
|
59
|
+
expect(TelemetryHelper.logActionEvent).toHaveBeenCalledTimes(0);
|
|
60
|
+
expect((_results$props = results().props) === null || _results$props === void 0 ? void 0 : (_results$props$danger = _results$props.dangerouslySetInnerHTML) === null || _results$props$danger === void 0 ? void 0 : _results$props$danger.__html).toEqual(systemMessage);
|
|
61
|
+
});
|
|
62
|
+
it("createActivityMiddleware() should escape html texts to prevent XSS attacks", () => {
|
|
63
|
+
var _results$props2, _results$props2$dange;
|
|
64
|
+
spyOn(TelemetryHelper, "logActionEvent").and.callFake(() => false);
|
|
65
|
+
const next = args => () => args; // eslint-disable-line @typescript-eslint/no-explicit-any
|
|
66
|
+
const systemMessage = "<img src='' onerror=\"alert('XSS attack')\"/>";
|
|
67
|
+
const args = {
|
|
68
|
+
activity: {
|
|
69
|
+
text: systemMessage,
|
|
70
|
+
channelData: {
|
|
71
|
+
tags: [Constants.systemMessageTag]
|
|
72
|
+
},
|
|
73
|
+
from: {
|
|
74
|
+
role: DirectLineSenderRole.User
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
};
|
|
78
|
+
const results = createActivityMiddleware()()(next)(args);
|
|
79
|
+
expect(TelemetryHelper.logActionEvent).toHaveBeenCalledTimes(0);
|
|
80
|
+
expect((_results$props2 = results().props) === null || _results$props2 === void 0 ? void 0 : (_results$props2$dange = _results$props2.dangerouslySetInnerHTML) === null || _results$props2$dange === void 0 ? void 0 : _results$props2$dange.__html).toEqual("<img src='' onerror="alert('XSS attack')"/>");
|
|
81
|
+
});
|
|
82
|
+
it("createActivityMiddleware() with QueuePosition tag should log QueuePosition message", () => {
|
|
83
|
+
spyOn(TelemetryHelper, "logActionEvent").and.callFake(() => false);
|
|
84
|
+
const next = args => () => args; // eslint-disable-line @typescript-eslint/no-explicit-any
|
|
85
|
+
const systemMessage = "system message";
|
|
86
|
+
const args = {
|
|
87
|
+
activity: {
|
|
88
|
+
text: systemMessage,
|
|
89
|
+
channelData: {
|
|
90
|
+
tags: [Constants.systemMessageTag, Constants.queuePositionMessageTag]
|
|
91
|
+
},
|
|
92
|
+
from: {
|
|
93
|
+
role: DirectLineSenderRole.User
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
};
|
|
97
|
+
createActivityMiddleware()()(next)(args);
|
|
98
|
+
expect(TelemetryHelper.logActionEvent).toHaveBeenCalledTimes(1);
|
|
99
|
+
});
|
|
100
|
+
it("createActivityMiddleware() with same clientmessageid with next activity should return nothing", () => {
|
|
101
|
+
spyOn(TelemetryHelper, "logActionEvent").and.callFake(() => false);
|
|
102
|
+
const next = args => () => args; // eslint-disable-line @typescript-eslint/no-explicit-any
|
|
103
|
+
const systemMessage = "system message";
|
|
104
|
+
const args = {
|
|
105
|
+
activity: {
|
|
106
|
+
text: systemMessage,
|
|
107
|
+
channelData: {
|
|
108
|
+
tags: [Constants.systemMessageTag],
|
|
109
|
+
clientmessageid: "1234"
|
|
110
|
+
},
|
|
111
|
+
from: {
|
|
112
|
+
role: DirectLineSenderRole.User
|
|
113
|
+
}
|
|
114
|
+
},
|
|
115
|
+
nextVisibleActivity: {
|
|
116
|
+
channelData: {
|
|
117
|
+
clientmessageid: "1234"
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
};
|
|
121
|
+
const results = createActivityMiddleware()()(next)(args);
|
|
122
|
+
expect(results()).toEqual(false);
|
|
123
|
+
});
|
|
124
|
+
it("createActivityMiddleware() with same messageid with next activity should return nothing", () => {
|
|
125
|
+
spyOn(TelemetryHelper, "logActionEvent").and.callFake(() => false);
|
|
126
|
+
const next = args => () => args; // eslint-disable-line @typescript-eslint/no-explicit-any
|
|
127
|
+
const systemMessage = "system message";
|
|
128
|
+
const args = {
|
|
129
|
+
activity: {
|
|
130
|
+
text: systemMessage,
|
|
131
|
+
channelData: {
|
|
132
|
+
tags: [Constants.systemMessageTag]
|
|
133
|
+
},
|
|
134
|
+
from: {
|
|
135
|
+
role: DirectLineSenderRole.User
|
|
136
|
+
},
|
|
137
|
+
messageid: "1234"
|
|
138
|
+
},
|
|
139
|
+
nextVisibleActivity: {
|
|
140
|
+
messageid: "1234"
|
|
141
|
+
}
|
|
142
|
+
};
|
|
143
|
+
const results = createActivityMiddleware()()(next)(args);
|
|
144
|
+
expect(results()).toEqual(false);
|
|
145
|
+
});
|
|
146
|
+
it("createActivityMiddleware() should render normal user messages", () => {
|
|
147
|
+
var _results$props3, _results$props3$child, _results$props3$child2;
|
|
148
|
+
spyOn(TelemetryHelper, "logActionEvent").and.callFake(() => false);
|
|
149
|
+
const next = args => () => args; // eslint-disable-line @typescript-eslint/no-explicit-any
|
|
150
|
+
const userMessage = "Hello World";
|
|
151
|
+
const args = {
|
|
152
|
+
activity: {
|
|
153
|
+
text: userMessage,
|
|
154
|
+
channelId: "webchat",
|
|
155
|
+
channelData: {
|
|
156
|
+
isHtmlEncoded: false
|
|
157
|
+
},
|
|
158
|
+
from: {
|
|
159
|
+
role: DirectLineSenderRole.User
|
|
160
|
+
},
|
|
161
|
+
type: DirectLineActivityType.Message
|
|
162
|
+
}
|
|
163
|
+
};
|
|
164
|
+
const results = createActivityMiddleware()()(next)(args);
|
|
165
|
+
expect((_results$props3 = results().props) === null || _results$props3 === void 0 ? void 0 : (_results$props3$child = _results$props3.children) === null || _results$props3$child === void 0 ? void 0 : (_results$props3$child2 = _results$props3$child.activity) === null || _results$props3$child2 === void 0 ? void 0 : _results$props3$child2.text).toEqual(userMessage);
|
|
166
|
+
});
|
|
167
|
+
it("createActivityMiddleware() should not render typing messages", () => {
|
|
168
|
+
var _results$activity;
|
|
169
|
+
spyOn(TelemetryHelper, "logActionEvent").and.callFake(() => false);
|
|
170
|
+
const next = args => () => args; // eslint-disable-line @typescript-eslint/no-explicit-any
|
|
171
|
+
const userMessage = "Hello World";
|
|
172
|
+
const args = {
|
|
173
|
+
activity: {
|
|
174
|
+
text: userMessage,
|
|
175
|
+
channelId: "webchat",
|
|
176
|
+
channelData: {
|
|
177
|
+
isHtmlEncoded: false
|
|
178
|
+
},
|
|
179
|
+
from: {
|
|
180
|
+
role: DirectLineSenderRole.User
|
|
181
|
+
},
|
|
182
|
+
type: DirectLineActivityType.Typing
|
|
183
|
+
}
|
|
184
|
+
};
|
|
185
|
+
const results = createActivityMiddleware()()(next)(args);
|
|
186
|
+
expect((_results$activity = results().activity) === null || _results$activity === void 0 ? void 0 : _results$activity.text).toEqual(userMessage);
|
|
187
|
+
});
|
|
188
|
+
});
|
|
@@ -151,6 +151,7 @@ export declare enum TelemetryEvent {
|
|
|
151
151
|
SetBotAuthProviderHideCard = "SetBotAuthProviderHideCard",
|
|
152
152
|
SetBotAuthProviderDisplayCard = "SetBotAuthProviderDisplayCard",
|
|
153
153
|
SetBotAuthProviderNotFound = "SetBotAuthProviderNotFound",
|
|
154
|
+
BotAuthActivityUndefinedSignInId = "BotAuthActivityUndefinedSignInId",
|
|
154
155
|
ThirdPartyCookiesBlocked = "ThirdPartyCookiesBlocked",
|
|
155
156
|
ProcessingHTMLTextMiddlewareFailed = "ProcessingHTMLTextMiddlewareFailed",
|
|
156
157
|
ProcessingSanitizationMiddlewareFailed = "ProcessingSanitizationMiddlewareFailed",
|
|
@@ -3,7 +3,7 @@ import ChatConfig from "@microsoft/omnichannel-chat-sdk/lib/core/ChatConfig";
|
|
|
3
3
|
import { Dispatch } from "react";
|
|
4
4
|
import { ILiveChatWidgetAction } from "../../../contexts/common/ILiveChatWidgetAction";
|
|
5
5
|
import { ILiveChatWidgetContext } from "../../../contexts/common/ILiveChatWidgetContext";
|
|
6
|
-
declare const handleChatReconnect: (chatSDK: any, props: any, dispatch: Dispatch<ILiveChatWidgetAction>, setAdapter: any, initStartChat: any, state: ILiveChatWidgetContext) => Promise<
|
|
6
|
+
declare const handleChatReconnect: (chatSDK: any, props: any, dispatch: Dispatch<ILiveChatWidgetAction>, setAdapter: any, initStartChat: any, state: ILiveChatWidgetContext) => Promise<boolean>;
|
|
7
7
|
declare const getChatReconnectContext: (chatSDK: any, chatConfig: ChatConfig, props: any, isAuthenticatedChat: boolean) => Promise<any>;
|
|
8
8
|
declare const isReconnectEnabled: (chatConfig?: ChatConfig | undefined) => boolean;
|
|
9
9
|
declare const isPersistentEnabled: (chatConfig?: ChatConfig | undefined) => boolean;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|