@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.
@@ -64,32 +64,75 @@ class FacadeChatSDK {
64
64
 
65
65
  // compare expiration time with current time
66
66
  if (now > this.expiration) {
67
- console.log("Token is expired", now, this.expiration, now > this.expiration);
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
- var _this$token;
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(tokenDecoded.exp);
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("New token is already expired, with epoch time " + this.expiration);
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,
@@ -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.log("Token is expired", now, this.expiration, now > this.expiration);
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
- var _this$token;
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(tokenDecoded.exp);
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("New token is already expired, with epoch time " + this.expiration);
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,
@@ -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.6",
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.13",
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",