@microsoft/omnichannel-chat-widget 1.7.6 → 1.7.7-main.4955cc8
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/facades/FacadeChatSDK.js +62 -19
- package/lib/cjs/components/footerstateful/downloadtranscriptstateful/DownloadTranscriptStateful.js +15 -0
- package/lib/esm/common/facades/FacadeChatSDK.js +62 -19
- package/lib/esm/components/footerstateful/downloadtranscriptstateful/DownloadTranscriptStateful.js +15 -0
- package/lib/types/common/facades/FacadeChatSDK.d.ts +2 -0
- package/package.json +2 -2
|
@@ -64,32 +64,75 @@ class FacadeChatSDK {
|
|
|
64
64
|
|
|
65
65
|
// compare expiration time with current time
|
|
66
66
|
if (now > this.expiration) {
|
|
67
|
-
console.
|
|
67
|
+
console.error("Token is expired", now, this.expiration, now > this.expiration);
|
|
68
68
|
return true;
|
|
69
69
|
}
|
|
70
70
|
return false;
|
|
71
71
|
}
|
|
72
|
+
enforceBase64Encoding(payload) {
|
|
73
|
+
//base64url when present, switches the "-" and "_" characters with "+" and "/"
|
|
74
|
+
const base64Payload = payload.replace(/-/g, "+").replace(/_/g, "/");
|
|
75
|
+
// since base64 encoding requires padding, we need to add padding to the payload
|
|
76
|
+
return base64Payload.padEnd(base64Payload.length + (4 - base64Payload.length % 4) % 4, "=");
|
|
77
|
+
}
|
|
78
|
+
extractExpFromToken(token) {
|
|
79
|
+
const tokenParts = token.split(".");
|
|
80
|
+
const last3digits = token.slice(-3);
|
|
81
|
+
|
|
82
|
+
// token must have 3 parts as JWT format
|
|
83
|
+
if (tokenParts.length !== 3) {
|
|
84
|
+
_TelemetryHelper.TelemetryHelper.logFacadeChatSDKEvent(_TelemetryConstants.LogLevel.ERROR, {
|
|
85
|
+
Event: _TelemetryConstants.TelemetryEvent.NewTokenFailed,
|
|
86
|
+
Description: "Invalid token format",
|
|
87
|
+
ExceptionDetails: {
|
|
88
|
+
message: "Invalid token format, must be in JWT format",
|
|
89
|
+
token: last3digits
|
|
90
|
+
}
|
|
91
|
+
});
|
|
92
|
+
throw new Error("Invalid token format, must be in JWT format");
|
|
93
|
+
}
|
|
94
|
+
try {
|
|
95
|
+
const payload = this.enforceBase64Encoding(tokenParts[1]);
|
|
96
|
+
// decode payload
|
|
97
|
+
const decodedPayload = atob(payload);
|
|
98
|
+
const jsonPayload = JSON.parse(decodedPayload);
|
|
99
|
+
// check if exp is present in payload
|
|
100
|
+
if (jsonPayload) {
|
|
101
|
+
if (jsonPayload.exp) {
|
|
102
|
+
return jsonPayload.exp;
|
|
103
|
+
}
|
|
104
|
+
return 0;
|
|
105
|
+
}
|
|
106
|
+
_TelemetryHelper.TelemetryHelper.logFacadeChatSDKEvent(_TelemetryConstants.LogLevel.ERROR, {
|
|
107
|
+
Event: _TelemetryConstants.TelemetryEvent.NewTokenFailed,
|
|
108
|
+
Description: "Invalid token payload",
|
|
109
|
+
ExceptionDetails: {
|
|
110
|
+
message: "Token payload is not valid JSON",
|
|
111
|
+
token: last3digits
|
|
112
|
+
}
|
|
113
|
+
});
|
|
114
|
+
throw new Error("Invalid token payload, payload is not valid JSON");
|
|
115
|
+
} catch (e) {
|
|
116
|
+
console.error("Failed to decode token", e);
|
|
117
|
+
_TelemetryHelper.TelemetryHelper.logFacadeChatSDKEvent(_TelemetryConstants.LogLevel.ERROR, {
|
|
118
|
+
Event: _TelemetryConstants.TelemetryEvent.NewTokenFailed,
|
|
119
|
+
Description: "Failed to decode token",
|
|
120
|
+
ExceptionDetails: {
|
|
121
|
+
message: "Failed to decode token",
|
|
122
|
+
token: last3digits
|
|
123
|
+
}
|
|
124
|
+
});
|
|
125
|
+
throw new Error("Failed to decode token");
|
|
126
|
+
}
|
|
127
|
+
}
|
|
72
128
|
async setToken(token) {
|
|
73
129
|
// token must be not null, and must be new
|
|
74
130
|
if (!(0, _utils.isNullOrEmptyString)(token) && token !== this.token) {
|
|
75
|
-
|
|
131
|
+
const last3digits = token.slice(-3);
|
|
76
132
|
const instant = Math.floor(Date.now() / 1000);
|
|
77
133
|
this.token = token;
|
|
78
|
-
// decompose token
|
|
79
|
-
const tokenParts = (_this$token = this.token) === null || _this$token === void 0 ? void 0 : _this$token.split(".");
|
|
80
|
-
if (!tokenParts || tokenParts.length <= 1) {
|
|
81
|
-
_TelemetryHelper.TelemetryHelper.logFacadeChatSDKEvent(_TelemetryConstants.LogLevel.ERROR, {
|
|
82
|
-
Event: _TelemetryConstants.TelemetryEvent.NewTokenFailed,
|
|
83
|
-
Description: "Invalid token format",
|
|
84
|
-
ExceptionDetails: "Token must be in JWT format"
|
|
85
|
-
});
|
|
86
|
-
throw new Error("Invalid token format, must be in JWT format");
|
|
87
|
-
}
|
|
88
|
-
// decode token
|
|
89
|
-
const tokenDecoded = JSON.parse(atob(tokenParts[1]));
|
|
90
134
|
// calculate expiration time
|
|
91
|
-
this.expiration = this.convertExpiration(
|
|
92
|
-
|
|
135
|
+
this.expiration = this.convertExpiration(this.extractExpFromToken(token) || 0);
|
|
93
136
|
// this is a control , in case the getAuthToken function returns same token
|
|
94
137
|
if (this.expiration > 0 && this.expiration < instant) {
|
|
95
138
|
_TelemetryHelper.TelemetryHelper.logFacadeChatSDKEvent(_TelemetryConstants.LogLevel.ERROR, {
|
|
@@ -97,10 +140,11 @@ class FacadeChatSDK {
|
|
|
97
140
|
Description: "New token is already expired",
|
|
98
141
|
ExceptionDetails: {
|
|
99
142
|
"Instant": instant,
|
|
100
|
-
"Expiration": this.expiration
|
|
143
|
+
"Expiration": this.expiration,
|
|
144
|
+
"Token": last3digits
|
|
101
145
|
}
|
|
102
146
|
});
|
|
103
|
-
throw new Error(
|
|
147
|
+
throw new Error(`New token is already expired, with epoch time ${this.expiration} , last 3 digits of token: ${last3digits}`);
|
|
104
148
|
}
|
|
105
149
|
}
|
|
106
150
|
}
|
|
@@ -164,7 +208,6 @@ class FacadeChatSDK {
|
|
|
164
208
|
};
|
|
165
209
|
} else {
|
|
166
210
|
var _ring$error, _ring$error2;
|
|
167
|
-
console.error("Failed to get token", ring);
|
|
168
211
|
_TelemetryHelper.TelemetryHelper.logFacadeChatSDKEvent(_TelemetryConstants.LogLevel.ERROR, {
|
|
169
212
|
Event: _TelemetryConstants.TelemetryEvent.NewTokenFailed,
|
|
170
213
|
Description: (_ring$error = ring.error) === null || _ring$error === void 0 ? void 0 : _ring$error.message,
|
package/lib/cjs/components/footerstateful/downloadtranscriptstateful/DownloadTranscriptStateful.js
CHANGED
|
@@ -14,6 +14,8 @@ var _NotificationScenarios = require("../../webchatcontainerstateful/webchatcont
|
|
|
14
14
|
var _TelemetryHelper = require("../../../common/telemetry/TelemetryHelper");
|
|
15
15
|
var _createChatTranscript = _interopRequireDefault(require("../../../plugins/createChatTranscript"));
|
|
16
16
|
var _createReducer = require("../../../contexts/createReducer");
|
|
17
|
+
var _omnichannelChatSdk = require("@microsoft/omnichannel-chat-sdk");
|
|
18
|
+
var _ConversationState = require("../../../contexts/common/ConversationState");
|
|
17
19
|
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
|
18
20
|
const processDisplayName = displayName => {
|
|
19
21
|
// if displayname matches "teamsvisitor:<some alphanumeric string>", we replace it with "Customer"
|
|
@@ -168,11 +170,24 @@ const downloadTranscript = async (facadeChatSDK, downloadTranscriptProps, state)
|
|
|
168
170
|
// Need to keep existing live chat context for scenarios when transcript is downloaded after endchat
|
|
169
171
|
let liveChatContext = state === null || state === void 0 ? void 0 : (_state$domainStates = state.domainStates) === null || _state$domainStates === void 0 ? void 0 : _state$domainStates.liveChatContext;
|
|
170
172
|
if (!liveChatContext) {
|
|
173
|
+
var _inMemoryState$appSta;
|
|
171
174
|
const inMemoryState = (0, _createReducer.executeReducer)(state, {
|
|
172
175
|
type: _LiveChatWidgetActionType.LiveChatWidgetActionType.GET_IN_MEMORY_STATE,
|
|
173
176
|
payload: null
|
|
174
177
|
});
|
|
175
178
|
liveChatContext = inMemoryState.domainStates.liveChatContext;
|
|
179
|
+
if ((inMemoryState === null || inMemoryState === void 0 ? void 0 : (_inMemoryState$appSta = inMemoryState.appStates) === null || _inMemoryState$appSta === void 0 ? void 0 : _inMemoryState$appSta.conversationState) !== _ConversationState.ConversationState.Active && !liveChatContext) {
|
|
180
|
+
var _state$domainStates2;
|
|
181
|
+
const chatToken = (state === null || state === void 0 ? void 0 : (_state$domainStates2 = state.domainStates) === null || _state$domainStates2 === void 0 ? void 0 : _state$domainStates2.chatToken) || inMemoryState.domainStates.chatToken;
|
|
182
|
+
if (chatToken && Object.keys(chatToken).length > 0) {
|
|
183
|
+
liveChatContext = {
|
|
184
|
+
chatToken: chatToken,
|
|
185
|
+
requestId: chatToken.requestId || (0, _omnichannelChatSdk.uuidv4)()
|
|
186
|
+
};
|
|
187
|
+
} else {
|
|
188
|
+
liveChatContext = await (facadeChatSDK === null || facadeChatSDK === void 0 ? void 0 : facadeChatSDK.getCurrentLiveChatContext());
|
|
189
|
+
}
|
|
190
|
+
}
|
|
176
191
|
}
|
|
177
192
|
let data = await (facadeChatSDK === null || facadeChatSDK === void 0 ? void 0 : facadeChatSDK.getLiveChatTranscript({
|
|
178
193
|
liveChatContext
|
|
@@ -58,32 +58,75 @@ export class FacadeChatSDK {
|
|
|
58
58
|
|
|
59
59
|
// compare expiration time with current time
|
|
60
60
|
if (now > this.expiration) {
|
|
61
|
-
console.
|
|
61
|
+
console.error("Token is expired", now, this.expiration, now > this.expiration);
|
|
62
62
|
return true;
|
|
63
63
|
}
|
|
64
64
|
return false;
|
|
65
65
|
}
|
|
66
|
+
enforceBase64Encoding(payload) {
|
|
67
|
+
//base64url when present, switches the "-" and "_" characters with "+" and "/"
|
|
68
|
+
const base64Payload = payload.replace(/-/g, "+").replace(/_/g, "/");
|
|
69
|
+
// since base64 encoding requires padding, we need to add padding to the payload
|
|
70
|
+
return base64Payload.padEnd(base64Payload.length + (4 - base64Payload.length % 4) % 4, "=");
|
|
71
|
+
}
|
|
72
|
+
extractExpFromToken(token) {
|
|
73
|
+
const tokenParts = token.split(".");
|
|
74
|
+
const last3digits = token.slice(-3);
|
|
75
|
+
|
|
76
|
+
// token must have 3 parts as JWT format
|
|
77
|
+
if (tokenParts.length !== 3) {
|
|
78
|
+
TelemetryHelper.logFacadeChatSDKEvent(LogLevel.ERROR, {
|
|
79
|
+
Event: TelemetryEvent.NewTokenFailed,
|
|
80
|
+
Description: "Invalid token format",
|
|
81
|
+
ExceptionDetails: {
|
|
82
|
+
message: "Invalid token format, must be in JWT format",
|
|
83
|
+
token: last3digits
|
|
84
|
+
}
|
|
85
|
+
});
|
|
86
|
+
throw new Error("Invalid token format, must be in JWT format");
|
|
87
|
+
}
|
|
88
|
+
try {
|
|
89
|
+
const payload = this.enforceBase64Encoding(tokenParts[1]);
|
|
90
|
+
// decode payload
|
|
91
|
+
const decodedPayload = atob(payload);
|
|
92
|
+
const jsonPayload = JSON.parse(decodedPayload);
|
|
93
|
+
// check if exp is present in payload
|
|
94
|
+
if (jsonPayload) {
|
|
95
|
+
if (jsonPayload.exp) {
|
|
96
|
+
return jsonPayload.exp;
|
|
97
|
+
}
|
|
98
|
+
return 0;
|
|
99
|
+
}
|
|
100
|
+
TelemetryHelper.logFacadeChatSDKEvent(LogLevel.ERROR, {
|
|
101
|
+
Event: TelemetryEvent.NewTokenFailed,
|
|
102
|
+
Description: "Invalid token payload",
|
|
103
|
+
ExceptionDetails: {
|
|
104
|
+
message: "Token payload is not valid JSON",
|
|
105
|
+
token: last3digits
|
|
106
|
+
}
|
|
107
|
+
});
|
|
108
|
+
throw new Error("Invalid token payload, payload is not valid JSON");
|
|
109
|
+
} catch (e) {
|
|
110
|
+
console.error("Failed to decode token", e);
|
|
111
|
+
TelemetryHelper.logFacadeChatSDKEvent(LogLevel.ERROR, {
|
|
112
|
+
Event: TelemetryEvent.NewTokenFailed,
|
|
113
|
+
Description: "Failed to decode token",
|
|
114
|
+
ExceptionDetails: {
|
|
115
|
+
message: "Failed to decode token",
|
|
116
|
+
token: last3digits
|
|
117
|
+
}
|
|
118
|
+
});
|
|
119
|
+
throw new Error("Failed to decode token");
|
|
120
|
+
}
|
|
121
|
+
}
|
|
66
122
|
async setToken(token) {
|
|
67
123
|
// token must be not null, and must be new
|
|
68
124
|
if (!isNullOrEmptyString(token) && token !== this.token) {
|
|
69
|
-
|
|
125
|
+
const last3digits = token.slice(-3);
|
|
70
126
|
const instant = Math.floor(Date.now() / 1000);
|
|
71
127
|
this.token = token;
|
|
72
|
-
// decompose token
|
|
73
|
-
const tokenParts = (_this$token = this.token) === null || _this$token === void 0 ? void 0 : _this$token.split(".");
|
|
74
|
-
if (!tokenParts || tokenParts.length <= 1) {
|
|
75
|
-
TelemetryHelper.logFacadeChatSDKEvent(LogLevel.ERROR, {
|
|
76
|
-
Event: TelemetryEvent.NewTokenFailed,
|
|
77
|
-
Description: "Invalid token format",
|
|
78
|
-
ExceptionDetails: "Token must be in JWT format"
|
|
79
|
-
});
|
|
80
|
-
throw new Error("Invalid token format, must be in JWT format");
|
|
81
|
-
}
|
|
82
|
-
// decode token
|
|
83
|
-
const tokenDecoded = JSON.parse(atob(tokenParts[1]));
|
|
84
128
|
// calculate expiration time
|
|
85
|
-
this.expiration = this.convertExpiration(
|
|
86
|
-
|
|
129
|
+
this.expiration = this.convertExpiration(this.extractExpFromToken(token) || 0);
|
|
87
130
|
// this is a control , in case the getAuthToken function returns same token
|
|
88
131
|
if (this.expiration > 0 && this.expiration < instant) {
|
|
89
132
|
TelemetryHelper.logFacadeChatSDKEvent(LogLevel.ERROR, {
|
|
@@ -91,10 +134,11 @@ export class FacadeChatSDK {
|
|
|
91
134
|
Description: "New token is already expired",
|
|
92
135
|
ExceptionDetails: {
|
|
93
136
|
"Instant": instant,
|
|
94
|
-
"Expiration": this.expiration
|
|
137
|
+
"Expiration": this.expiration,
|
|
138
|
+
"Token": last3digits
|
|
95
139
|
}
|
|
96
140
|
});
|
|
97
|
-
throw new Error(
|
|
141
|
+
throw new Error(`New token is already expired, with epoch time ${this.expiration} , last 3 digits of token: ${last3digits}`);
|
|
98
142
|
}
|
|
99
143
|
}
|
|
100
144
|
}
|
|
@@ -158,7 +202,6 @@ export class FacadeChatSDK {
|
|
|
158
202
|
};
|
|
159
203
|
} else {
|
|
160
204
|
var _ring$error, _ring$error2;
|
|
161
|
-
console.error("Failed to get token", ring);
|
|
162
205
|
TelemetryHelper.logFacadeChatSDKEvent(LogLevel.ERROR, {
|
|
163
206
|
Event: TelemetryEvent.NewTokenFailed,
|
|
164
207
|
Description: (_ring$error = ring.error) === null || _ring$error === void 0 ? void 0 : _ring$error.message,
|
package/lib/esm/components/footerstateful/downloadtranscriptstateful/DownloadTranscriptStateful.js
CHANGED
|
@@ -8,6 +8,8 @@ import { NotificationScenarios } from "../../webchatcontainerstateful/webchatcon
|
|
|
8
8
|
import { TelemetryHelper } from "../../../common/telemetry/TelemetryHelper";
|
|
9
9
|
import createChatTranscript from "../../../plugins/createChatTranscript";
|
|
10
10
|
import { executeReducer } from "../../../contexts/createReducer";
|
|
11
|
+
import { uuidv4 } from "@microsoft/omnichannel-chat-sdk";
|
|
12
|
+
import { ConversationState } from "../../../contexts/common/ConversationState";
|
|
11
13
|
const processDisplayName = displayName => {
|
|
12
14
|
// if displayname matches "teamsvisitor:<some alphanumeric string>", we replace it with "Customer"
|
|
13
15
|
const displayNameRegex = ".+:.+";
|
|
@@ -161,11 +163,24 @@ export const downloadTranscript = async (facadeChatSDK, downloadTranscriptProps,
|
|
|
161
163
|
// Need to keep existing live chat context for scenarios when transcript is downloaded after endchat
|
|
162
164
|
let liveChatContext = state === null || state === void 0 ? void 0 : (_state$domainStates = state.domainStates) === null || _state$domainStates === void 0 ? void 0 : _state$domainStates.liveChatContext;
|
|
163
165
|
if (!liveChatContext) {
|
|
166
|
+
var _inMemoryState$appSta;
|
|
164
167
|
const inMemoryState = executeReducer(state, {
|
|
165
168
|
type: LiveChatWidgetActionType.GET_IN_MEMORY_STATE,
|
|
166
169
|
payload: null
|
|
167
170
|
});
|
|
168
171
|
liveChatContext = inMemoryState.domainStates.liveChatContext;
|
|
172
|
+
if ((inMemoryState === null || inMemoryState === void 0 ? void 0 : (_inMemoryState$appSta = inMemoryState.appStates) === null || _inMemoryState$appSta === void 0 ? void 0 : _inMemoryState$appSta.conversationState) !== ConversationState.Active && !liveChatContext) {
|
|
173
|
+
var _state$domainStates2;
|
|
174
|
+
const chatToken = (state === null || state === void 0 ? void 0 : (_state$domainStates2 = state.domainStates) === null || _state$domainStates2 === void 0 ? void 0 : _state$domainStates2.chatToken) || inMemoryState.domainStates.chatToken;
|
|
175
|
+
if (chatToken && Object.keys(chatToken).length > 0) {
|
|
176
|
+
liveChatContext = {
|
|
177
|
+
chatToken: chatToken,
|
|
178
|
+
requestId: chatToken.requestId || uuidv4()
|
|
179
|
+
};
|
|
180
|
+
} else {
|
|
181
|
+
liveChatContext = await (facadeChatSDK === null || facadeChatSDK === void 0 ? void 0 : facadeChatSDK.getCurrentLiveChatContext());
|
|
182
|
+
}
|
|
183
|
+
}
|
|
169
184
|
}
|
|
170
185
|
let data = await (facadeChatSDK === null || facadeChatSDK === void 0 ? void 0 : facadeChatSDK.getLiveChatTranscript({
|
|
171
186
|
liveChatContext
|
|
@@ -40,6 +40,8 @@ export declare class FacadeChatSDK {
|
|
|
40
40
|
constructor(input: IFacadeChatSDKInput, disableReauthentication: boolean);
|
|
41
41
|
private convertExpiration;
|
|
42
42
|
private isTokenExpired;
|
|
43
|
+
private enforceBase64Encoding;
|
|
44
|
+
private extractExpFromToken;
|
|
43
45
|
private setToken;
|
|
44
46
|
private tokenRing;
|
|
45
47
|
private validateAndExecuteCall;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@microsoft/omnichannel-chat-widget",
|
|
3
|
-
"version": "1.7.
|
|
3
|
+
"version": "1.7.7-main.4955cc8",
|
|
4
4
|
"description": "Microsoft Omnichannel Chat Widget",
|
|
5
5
|
"main": "lib/cjs/index.js",
|
|
6
6
|
"types": "lib/types/index.d.ts",
|
|
@@ -78,7 +78,7 @@
|
|
|
78
78
|
"dependencies": {
|
|
79
79
|
"@azure/core-tracing": "^1.2.0",
|
|
80
80
|
"@microsoft/omnichannel-chat-components": "1.1.8",
|
|
81
|
-
"@microsoft/omnichannel-chat-sdk": "^1.10.
|
|
81
|
+
"@microsoft/omnichannel-chat-sdk": "^1.10.15",
|
|
82
82
|
"@opentelemetry/api": "^1.9.0",
|
|
83
83
|
"abort-controller-es5": "^2.0.1",
|
|
84
84
|
"dompurify": "^3.2.4",
|