@microsoft/omnichannel-chat-widget 1.7.6 → 1.7.7-main.5abcb8f

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,77 @@ 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
+ const payload = this.enforceBase64Encoding(tokenParts[1]);
95
+ // decode payload
96
+ const decodedPayload = Buffer.from(payload, "base64").toString("utf-8");
97
+
98
+ // check if decoded payload is valid JSON
99
+ try {
100
+ const jsonPayload = JSON.parse(decodedPayload);
101
+ // check if exp is present in payload
102
+ if (jsonPayload) {
103
+ if (jsonPayload.exp) {
104
+ return jsonPayload.exp;
105
+ }
106
+ return 0;
107
+ }
108
+ _TelemetryHelper.TelemetryHelper.logFacadeChatSDKEvent(_TelemetryConstants.LogLevel.ERROR, {
109
+ Event: _TelemetryConstants.TelemetryEvent.NewTokenFailed,
110
+ Description: "Invalid token payload",
111
+ ExceptionDetails: {
112
+ message: "Token payload is not valid JSON",
113
+ token: last3digits
114
+ }
115
+ });
116
+ throw new Error("Invalid token payload, payload is not valid JSON");
117
+ } catch (e) {
118
+ console.error("Failed to decode token", e);
119
+ _TelemetryHelper.TelemetryHelper.logFacadeChatSDKEvent(_TelemetryConstants.LogLevel.ERROR, {
120
+ Event: _TelemetryConstants.TelemetryEvent.NewTokenFailed,
121
+ Description: "Failed to decode token",
122
+ ExceptionDetails: {
123
+ message: "Failed to decode token",
124
+ token: last3digits
125
+ }
126
+ });
127
+ throw new Error("Failed to decode token");
128
+ }
129
+ }
72
130
  async setToken(token) {
73
131
  // token must be not null, and must be new
74
132
  if (!(0, _utils.isNullOrEmptyString)(token) && token !== this.token) {
75
- var _this$token;
133
+ const last3digits = token.slice(-3);
76
134
  const instant = Math.floor(Date.now() / 1000);
77
135
  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
136
  // calculate expiration time
91
- this.expiration = this.convertExpiration(tokenDecoded.exp);
92
-
137
+ this.expiration = this.convertExpiration(this.extractExpFromToken(token) || 0);
93
138
  // this is a control , in case the getAuthToken function returns same token
94
139
  if (this.expiration > 0 && this.expiration < instant) {
95
140
  _TelemetryHelper.TelemetryHelper.logFacadeChatSDKEvent(_TelemetryConstants.LogLevel.ERROR, {
@@ -97,10 +142,11 @@ class FacadeChatSDK {
97
142
  Description: "New token is already expired",
98
143
  ExceptionDetails: {
99
144
  "Instant": instant,
100
- "Expiration": this.expiration
145
+ "Expiration": this.expiration,
146
+ "Token": last3digits
101
147
  }
102
148
  });
103
- throw new Error("New token is already expired, with epoch time " + this.expiration);
149
+ throw new Error(`New token is already expired, with epoch time ${this.expiration} , last 3 digits of token: ${last3digits}`);
104
150
  }
105
151
  }
106
152
  }
@@ -164,7 +210,6 @@ class FacadeChatSDK {
164
210
  };
165
211
  } else {
166
212
  var _ring$error, _ring$error2;
167
- console.error("Failed to get token", ring);
168
213
  _TelemetryHelper.TelemetryHelper.logFacadeChatSDKEvent(_TelemetryConstants.LogLevel.ERROR, {
169
214
  Event: _TelemetryConstants.TelemetryEvent.NewTokenFailed,
170
215
  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,77 @@ 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
+ const payload = this.enforceBase64Encoding(tokenParts[1]);
89
+ // decode payload
90
+ const decodedPayload = Buffer.from(payload, "base64").toString("utf-8");
91
+
92
+ // check if decoded payload is valid JSON
93
+ try {
94
+ const jsonPayload = JSON.parse(decodedPayload);
95
+ // check if exp is present in payload
96
+ if (jsonPayload) {
97
+ if (jsonPayload.exp) {
98
+ return jsonPayload.exp;
99
+ }
100
+ return 0;
101
+ }
102
+ TelemetryHelper.logFacadeChatSDKEvent(LogLevel.ERROR, {
103
+ Event: TelemetryEvent.NewTokenFailed,
104
+ Description: "Invalid token payload",
105
+ ExceptionDetails: {
106
+ message: "Token payload is not valid JSON",
107
+ token: last3digits
108
+ }
109
+ });
110
+ throw new Error("Invalid token payload, payload is not valid JSON");
111
+ } catch (e) {
112
+ console.error("Failed to decode token", e);
113
+ TelemetryHelper.logFacadeChatSDKEvent(LogLevel.ERROR, {
114
+ Event: TelemetryEvent.NewTokenFailed,
115
+ Description: "Failed to decode token",
116
+ ExceptionDetails: {
117
+ message: "Failed to decode token",
118
+ token: last3digits
119
+ }
120
+ });
121
+ throw new Error("Failed to decode token");
122
+ }
123
+ }
66
124
  async setToken(token) {
67
125
  // token must be not null, and must be new
68
126
  if (!isNullOrEmptyString(token) && token !== this.token) {
69
- var _this$token;
127
+ const last3digits = token.slice(-3);
70
128
  const instant = Math.floor(Date.now() / 1000);
71
129
  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
130
  // calculate expiration time
85
- this.expiration = this.convertExpiration(tokenDecoded.exp);
86
-
131
+ this.expiration = this.convertExpiration(this.extractExpFromToken(token) || 0);
87
132
  // this is a control , in case the getAuthToken function returns same token
88
133
  if (this.expiration > 0 && this.expiration < instant) {
89
134
  TelemetryHelper.logFacadeChatSDKEvent(LogLevel.ERROR, {
@@ -91,10 +136,11 @@ export class FacadeChatSDK {
91
136
  Description: "New token is already expired",
92
137
  ExceptionDetails: {
93
138
  "Instant": instant,
94
- "Expiration": this.expiration
139
+ "Expiration": this.expiration,
140
+ "Token": last3digits
95
141
  }
96
142
  });
97
- throw new Error("New token is already expired, with epoch time " + this.expiration);
143
+ throw new Error(`New token is already expired, with epoch time ${this.expiration} , last 3 digits of token: ${last3digits}`);
98
144
  }
99
145
  }
100
146
  }
@@ -158,7 +204,6 @@ export class FacadeChatSDK {
158
204
  };
159
205
  } else {
160
206
  var _ring$error, _ring$error2;
161
- console.error("Failed to get token", ring);
162
207
  TelemetryHelper.logFacadeChatSDKEvent(LogLevel.ERROR, {
163
208
  Event: TelemetryEvent.NewTokenFailed,
164
209
  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.5abcb8f",
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.14",
82
82
  "@opentelemetry/api": "^1.9.0",
83
83
  "abort-controller-es5": "^2.0.1",
84
84
  "dompurify": "^3.2.4",