@thoughtspot/visual-embed-sdk 1.20.0-prerender.2 → 1.20.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/dist/src/auth.d.ts +2 -38
- package/dist/src/auth.d.ts.map +1 -1
- package/dist/src/config.d.ts +0 -1
- package/dist/src/config.d.ts.map +1 -1
- package/dist/src/embed/app.d.ts +5 -17
- package/dist/src/embed/app.d.ts.map +1 -1
- package/dist/src/embed/base.d.ts +9 -20
- package/dist/src/embed/base.d.ts.map +1 -1
- package/dist/src/embed/liveboard.d.ts +5 -17
- package/dist/src/embed/liveboard.d.ts.map +1 -1
- package/dist/src/embed/search-bar.d.ts +0 -3
- package/dist/src/embed/search-bar.d.ts.map +1 -1
- package/dist/src/embed/search.d.ts +5 -9
- package/dist/src/embed/search.d.ts.map +1 -1
- package/dist/src/embed/ts-embed.d.ts +6 -43
- package/dist/src/embed/ts-embed.d.ts.map +1 -1
- package/dist/src/errors.d.ts.map +1 -1
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/mixpanel-service.d.ts +0 -8
- package/dist/src/mixpanel-service.d.ts.map +1 -1
- package/dist/src/react/index.d.ts.map +1 -1
- package/dist/src/react/util.d.ts +0 -4
- package/dist/src/react/util.d.ts.map +1 -1
- package/dist/src/test/test-utils.d.ts +2 -11
- package/dist/src/test/test-utils.d.ts.map +1 -1
- package/dist/src/types.d.ts +76 -273
- package/dist/src/types.d.ts.map +1 -1
- package/dist/src/utils/answerService.d.ts +0 -7
- package/dist/src/utils/answerService.d.ts.map +1 -1
- package/dist/src/utils/authService.d.ts +0 -30
- package/dist/src/utils/authService.d.ts.map +1 -1
- package/dist/src/utils/processData.d.ts +0 -12
- package/dist/src/utils/processData.d.ts.map +1 -1
- package/dist/src/utils/processTrigger.d.ts +0 -7
- package/dist/src/utils/processTrigger.d.ts.map +1 -1
- package/dist/src/utils.d.ts +0 -12
- package/dist/src/utils.d.ts.map +1 -1
- package/dist/tsembed.es.js +262 -637
- package/dist/tsembed.js +261 -629
- package/lib/package.json +8 -3
- package/lib/src/auth.d.ts +2 -38
- package/lib/src/auth.d.ts.map +1 -1
- package/lib/src/auth.js +25 -70
- package/lib/src/auth.js.map +1 -1
- package/lib/src/auth.spec.js +5 -14
- package/lib/src/auth.spec.js.map +1 -1
- package/lib/src/config.d.ts +0 -1
- package/lib/src/config.d.ts.map +1 -1
- package/lib/src/config.js +3 -5
- package/lib/src/config.js.map +1 -1
- package/lib/src/config.spec.js.map +1 -1
- package/lib/src/embed/app.d.ts +5 -17
- package/lib/src/embed/app.d.ts.map +1 -1
- package/lib/src/embed/app.js +15 -25
- package/lib/src/embed/app.js.map +1 -1
- package/lib/src/embed/app.spec.js +12 -12
- package/lib/src/embed/app.spec.js.map +1 -1
- package/lib/src/embed/base.d.ts +9 -20
- package/lib/src/embed/base.d.ts.map +1 -1
- package/lib/src/embed/base.js +15 -31
- package/lib/src/embed/base.js.map +1 -1
- package/lib/src/embed/base.spec.js.map +1 -1
- package/lib/src/embed/embed.spec.js +1 -1
- package/lib/src/embed/embed.spec.js.map +1 -1
- package/lib/src/embed/liveboard.d.ts +5 -17
- package/lib/src/embed/liveboard.d.ts.map +1 -1
- package/lib/src/embed/liveboard.js +37 -49
- package/lib/src/embed/liveboard.js.map +1 -1
- package/lib/src/embed/liveboard.spec.js +30 -37
- package/lib/src/embed/liveboard.spec.js.map +1 -1
- package/lib/src/embed/pinboard.spec.js +26 -14
- package/lib/src/embed/pinboard.spec.js.map +1 -1
- package/lib/src/embed/search-bar.d.ts +0 -3
- package/lib/src/embed/search-bar.d.ts.map +1 -1
- package/lib/src/embed/search-bar.js +6 -5
- package/lib/src/embed/search-bar.js.map +1 -1
- package/lib/src/embed/search.d.ts +5 -9
- package/lib/src/embed/search.d.ts.map +1 -1
- package/lib/src/embed/search.js +14 -18
- package/lib/src/embed/search.js.map +1 -1
- package/lib/src/embed/search.spec.js +19 -16
- package/lib/src/embed/search.spec.js.map +1 -1
- package/lib/src/embed/searchEmbed-basic-auth.spec.js +0 -4
- package/lib/src/embed/searchEmbed-basic-auth.spec.js.map +1 -1
- package/lib/src/embed/ts-embed.d.ts +6 -43
- package/lib/src/embed/ts-embed.d.ts.map +1 -1
- package/lib/src/embed/ts-embed.js +72 -117
- package/lib/src/embed/ts-embed.js.map +1 -1
- package/lib/src/embed/ts-embed.spec.js +24 -23
- package/lib/src/embed/ts-embed.spec.js.map +1 -1
- package/lib/src/errors.d.ts.map +1 -1
- package/lib/src/errors.js.map +1 -1
- package/lib/src/index.d.ts.map +1 -1
- package/lib/src/index.js +2 -2
- package/lib/src/index.js.map +1 -1
- package/lib/src/mixpanel-service.d.ts +0 -8
- package/lib/src/mixpanel-service.d.ts.map +1 -1
- package/lib/src/mixpanel-service.js +1 -13
- package/lib/src/mixpanel-service.js.map +1 -1
- package/lib/src/mixpanel-service.spec.js.map +1 -1
- package/lib/src/react/index.d.ts.map +1 -1
- package/lib/src/react/index.js +6 -6
- package/lib/src/react/index.js.map +1 -1
- package/lib/src/react/index.spec.js +6 -15
- package/lib/src/react/index.spec.js.map +1 -1
- package/lib/src/react/util.d.ts +0 -4
- package/lib/src/react/util.d.ts.map +1 -1
- package/lib/src/react/util.js +0 -4
- package/lib/src/react/util.js.map +1 -1
- package/lib/src/test/test-utils.d.ts +2 -11
- package/lib/src/test/test-utils.d.ts.map +1 -1
- package/lib/src/test/test-utils.js +25 -36
- package/lib/src/test/test-utils.js.map +1 -1
- package/lib/src/types.d.ts +76 -273
- package/lib/src/types.d.ts.map +1 -1
- package/lib/src/types.js +54 -200
- package/lib/src/types.js.map +1 -1
- package/lib/src/utils/answerService.d.ts +0 -7
- package/lib/src/utils/answerService.d.ts.map +1 -1
- package/lib/src/utils/answerService.js +0 -7
- package/lib/src/utils/answerService.js.map +1 -1
- package/lib/src/utils/answerService.spec.js.map +1 -1
- package/lib/src/utils/authService.d.ts +0 -30
- package/lib/src/utils/authService.d.ts.map +1 -1
- package/lib/src/utils/authService.js +2 -39
- package/lib/src/utils/authService.js.map +1 -1
- package/lib/src/utils/authService.spec.js.map +1 -1
- package/lib/src/utils/processData.d.ts +0 -12
- package/lib/src/utils/processData.d.ts.map +1 -1
- package/lib/src/utils/processData.js +5 -33
- package/lib/src/utils/processData.js.map +1 -1
- package/lib/src/utils/processData.spec.js.map +1 -1
- package/lib/src/utils/processTrigger.d.ts +0 -7
- package/lib/src/utils/processTrigger.d.ts.map +1 -1
- package/lib/src/utils/processTrigger.js +3 -17
- package/lib/src/utils/processTrigger.js.map +1 -1
- package/lib/src/utils/processTrigger.spec.js.map +1 -1
- package/lib/src/utils.d.ts +0 -12
- package/lib/src/utils.d.ts.map +1 -1
- package/lib/src/utils.js +19 -24
- package/lib/src/utils.js.map +1 -1
- package/lib/src/utils.spec.js.map +1 -1
- package/lib/src/visual-embed-sdk.d.ts +102 -406
- package/package.json +8 -3
- package/src/auth.spec.ts +150 -68
- package/src/auth.ts +108 -102
- package/src/config.spec.ts +4 -2
- package/src/config.ts +3 -5
- package/src/embed/app.spec.ts +14 -25
- package/src/embed/app.ts +35 -47
- package/src/embed/base.spec.ts +9 -3
- package/src/embed/base.ts +53 -51
- package/src/embed/embed.spec.ts +6 -5
- package/src/embed/liveboard.spec.ts +37 -56
- package/src/embed/liveboard.ts +64 -66
- package/src/embed/pinboard.spec.ts +29 -26
- package/src/embed/search-bar.tsx +8 -10
- package/src/embed/search.spec.ts +21 -31
- package/src/embed/search.ts +25 -26
- package/src/embed/searchEmbed-basic-auth.spec.ts +28 -22
- package/src/embed/ts-embed.spec.ts +148 -70
- package/src/embed/ts-embed.ts +157 -147
- package/src/errors.ts +6 -3
- package/src/index.ts +10 -4
- package/src/mixpanel-service.spec.ts +3 -1
- package/src/mixpanel-service.ts +1 -13
- package/src/react/index.spec.tsx +13 -37
- package/src/react/index.tsx +57 -38
- package/src/react/util.ts +4 -8
- package/src/test/test-utils.ts +39 -43
- package/src/types.ts +78 -270
- package/src/utils/answerService.spec.ts +5 -3
- package/src/utils/answerService.ts +17 -21
- package/src/utils/authService.spec.ts +41 -26
- package/src/utils/authService.ts +21 -47
- package/src/utils/processData.spec.ts +59 -26
- package/src/utils/processData.ts +14 -36
- package/src/utils/processTrigger.spec.ts +6 -1
- package/src/utils/processTrigger.ts +9 -18
- package/src/utils.spec.ts +12 -8
- package/src/utils.ts +26 -25
package/src/auth.ts
CHANGED
|
@@ -1,8 +1,6 @@
|
|
|
1
1
|
import EventEmitter from 'eventemitter3';
|
|
2
2
|
import { initMixpanel } from './mixpanel-service';
|
|
3
|
-
import {
|
|
4
|
-
AuthType, DOMSelector, EmbedConfig, EmbedEvent, Param,
|
|
5
|
-
} from './types';
|
|
3
|
+
import { AuthType, DOMSelector, EmbedConfig, EmbedEvent, Param } from './types';
|
|
6
4
|
import { getDOMNode, getRedirectUrl } from './utils';
|
|
7
5
|
// eslint-disable-next-line import/no-cycle
|
|
8
6
|
import {
|
|
@@ -27,12 +25,15 @@ const sessionInfoPromise = new Promise((resolve) => {
|
|
|
27
25
|
});
|
|
28
26
|
let releaseVersion = '';
|
|
29
27
|
|
|
30
|
-
export const SSO_REDIRECTION_MARKER_GUID =
|
|
28
|
+
export const SSO_REDIRECTION_MARKER_GUID =
|
|
29
|
+
'5e16222e-ef02-43e9-9fbd-24226bf3ce5b';
|
|
31
30
|
|
|
32
31
|
export const EndPoints = {
|
|
33
32
|
AUTH_VERIFICATION: '/callosum/v1/session/info',
|
|
34
|
-
SAML_LOGIN_TEMPLATE: (targetUrl: string) =>
|
|
35
|
-
|
|
33
|
+
SAML_LOGIN_TEMPLATE: (targetUrl: string) =>
|
|
34
|
+
`/callosum/v1/saml/login?targetURLPath=${targetUrl}`,
|
|
35
|
+
OIDC_LOGIN_TEMPLATE: (targetUrl: string) =>
|
|
36
|
+
`/callosum/v1/oidc/login?targetURLPath=${targetUrl}`,
|
|
36
37
|
TOKEN_LOGIN: '/callosum/v1/session/login/token',
|
|
37
38
|
BASIC_LOGIN: '/callosum/v1/session/login',
|
|
38
39
|
LOGOUT: '/callosum/v1/session/logout',
|
|
@@ -41,7 +42,6 @@ export const EndPoints = {
|
|
|
41
42
|
/**
|
|
42
43
|
* Enum for auth failure types. This is the parameter passed to the listner
|
|
43
44
|
* of {@link AuthStatus.FAILURE}.
|
|
44
|
-
*
|
|
45
45
|
* @group Authentication / Init
|
|
46
46
|
*/
|
|
47
47
|
export enum AuthFailureType {
|
|
@@ -53,7 +53,6 @@ export enum AuthFailureType {
|
|
|
53
53
|
|
|
54
54
|
/**
|
|
55
55
|
* Enum for auth status emitted by the emitter returned from {@link init}.
|
|
56
|
-
*
|
|
57
56
|
* @group Authentication / Init
|
|
58
57
|
*/
|
|
59
58
|
export enum AuthStatus {
|
|
@@ -77,7 +76,6 @@ export enum AuthStatus {
|
|
|
77
76
|
* Emitted when inPopup: true in the SAMLRedirect flow.
|
|
78
77
|
* And, we are waiting for popup to be triggered either programatically
|
|
79
78
|
* or by the trigger button.
|
|
80
|
-
*
|
|
81
79
|
* @version SDK: 1.19.0
|
|
82
80
|
*/
|
|
83
81
|
WAITING_FOR_POPUP = 'WAITING_FOR_POPUP',
|
|
@@ -85,25 +83,28 @@ export enum AuthStatus {
|
|
|
85
83
|
|
|
86
84
|
/**
|
|
87
85
|
* Event emitter returned from {@link init}.
|
|
88
|
-
*
|
|
89
86
|
* @group Authentication / Init
|
|
90
87
|
*/
|
|
91
88
|
export interface AuthEventEmitter {
|
|
92
89
|
/**
|
|
93
90
|
* Registed a listener on Auth failure.
|
|
94
|
-
*
|
|
95
91
|
* @param event
|
|
96
92
|
* @param listener
|
|
97
93
|
*/
|
|
98
|
-
on(event: AuthStatus.FAILURE, listener: (failureType: AuthFailureType) => void): this;
|
|
99
94
|
on(
|
|
100
|
-
event: AuthStatus.
|
|
95
|
+
event: AuthStatus.FAILURE,
|
|
96
|
+
listener: (failureType: AuthFailureType) => void,
|
|
97
|
+
): this;
|
|
98
|
+
on(
|
|
99
|
+
event:
|
|
100
|
+
| AuthStatus.SDK_SUCCESS
|
|
101
|
+
| AuthStatus.LOGOUT
|
|
102
|
+
| AuthStatus.WAITING_FOR_POPUP,
|
|
101
103
|
listener: () => void,
|
|
102
104
|
): this;
|
|
103
105
|
on(event: AuthStatus.SUCCESS, listener: (sessionInfo: any) => void): this;
|
|
104
106
|
/**
|
|
105
107
|
* Trigger an event on the emitter returned from init.
|
|
106
|
-
*
|
|
107
108
|
* @param {@link AuthEvent}
|
|
108
109
|
*/
|
|
109
110
|
emit(event: AuthEvent): void;
|
|
@@ -111,7 +112,6 @@ export interface AuthEventEmitter {
|
|
|
111
112
|
|
|
112
113
|
/**
|
|
113
114
|
* Events which can be triggered on the emitter returned from {@link init}.
|
|
114
|
-
*
|
|
115
115
|
* @group Authentication / Init
|
|
116
116
|
*/
|
|
117
117
|
export enum AuthEvent {
|
|
@@ -124,24 +124,16 @@ export enum AuthEvent {
|
|
|
124
124
|
|
|
125
125
|
let authEE: EventEmitter<AuthStatus | AuthEvent>;
|
|
126
126
|
|
|
127
|
-
/**
|
|
128
|
-
*
|
|
129
|
-
*/
|
|
130
127
|
export function getAuthEE(): EventEmitter<AuthStatus | AuthEvent> {
|
|
131
128
|
return authEE;
|
|
132
129
|
}
|
|
133
130
|
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
*/
|
|
138
|
-
export function setAuthEE(eventEmitter: EventEmitter<AuthStatus | AuthEvent>): void {
|
|
131
|
+
export function setAuthEE(
|
|
132
|
+
eventEmitter: EventEmitter<AuthStatus | AuthEvent>,
|
|
133
|
+
): void {
|
|
139
134
|
authEE = eventEmitter;
|
|
140
135
|
}
|
|
141
136
|
|
|
142
|
-
/**
|
|
143
|
-
*
|
|
144
|
-
*/
|
|
145
137
|
export function notifyAuthSDKSuccess(): void {
|
|
146
138
|
if (!authEE) {
|
|
147
139
|
console.error('SDK not initialized');
|
|
@@ -150,9 +142,6 @@ export function notifyAuthSDKSuccess(): void {
|
|
|
150
142
|
authEE.emit(AuthStatus.SDK_SUCCESS);
|
|
151
143
|
}
|
|
152
144
|
|
|
153
|
-
/**
|
|
154
|
-
*
|
|
155
|
-
*/
|
|
156
145
|
export function notifyAuthSuccess(): void {
|
|
157
146
|
if (!authEE) {
|
|
158
147
|
console.error('SDK not initialized');
|
|
@@ -161,10 +150,6 @@ export function notifyAuthSuccess(): void {
|
|
|
161
150
|
authEE.emit(AuthStatus.SUCCESS, sessionInfo);
|
|
162
151
|
}
|
|
163
152
|
|
|
164
|
-
/**
|
|
165
|
-
*
|
|
166
|
-
* @param failureType
|
|
167
|
-
*/
|
|
168
153
|
export function notifyAuthFailure(failureType: AuthFailureType): void {
|
|
169
154
|
if (!authEE) {
|
|
170
155
|
console.error('SDK not initialized');
|
|
@@ -173,9 +158,6 @@ export function notifyAuthFailure(failureType: AuthFailureType): void {
|
|
|
173
158
|
authEE.emit(AuthStatus.FAILURE, failureType);
|
|
174
159
|
}
|
|
175
160
|
|
|
176
|
-
/**
|
|
177
|
-
*
|
|
178
|
-
*/
|
|
179
161
|
export function notifyLogout(): void {
|
|
180
162
|
if (!authEE) {
|
|
181
163
|
console.error('SDK not initialized');
|
|
@@ -186,7 +168,6 @@ export function notifyLogout(): void {
|
|
|
186
168
|
|
|
187
169
|
/**
|
|
188
170
|
* Check if we are logged into the ThoughtSpot cluster
|
|
189
|
-
*
|
|
190
171
|
* @param thoughtSpotHost The ThoughtSpot cluster hostname or IP
|
|
191
172
|
*/
|
|
192
173
|
async function isLoggedIn(thoughtSpotHost: string): Promise<boolean> {
|
|
@@ -210,32 +191,24 @@ export function getReleaseVersion() {
|
|
|
210
191
|
}
|
|
211
192
|
|
|
212
193
|
/**
|
|
213
|
-
* Return a promise that resolves with the session information when
|
|
214
|
-
*
|
|
215
|
-
*
|
|
194
|
+
* Return a promise that resolves with the session information when authentication is
|
|
195
|
+
* successful. And info is available.
|
|
216
196
|
* @group Global methods
|
|
217
197
|
*/
|
|
218
198
|
export function getSessionInfo(): Promise<any> {
|
|
219
199
|
return sessionInfoPromise;
|
|
220
200
|
}
|
|
221
201
|
|
|
222
|
-
/**
|
|
223
|
-
*
|
|
224
|
-
* @param sessionDetails
|
|
225
|
-
*/
|
|
226
202
|
export function initSession(sessionDetails: any) {
|
|
227
203
|
sessionInfo = sessionDetails;
|
|
228
204
|
initMixpanel(sessionInfo);
|
|
229
205
|
sessionInfoResolver(sessionInfo);
|
|
230
206
|
}
|
|
231
207
|
|
|
232
|
-
const DUPLICATE_TOKEN_ERR =
|
|
233
|
-
|
|
208
|
+
const DUPLICATE_TOKEN_ERR =
|
|
209
|
+
'Duplicate token, please issue a new token every time getAuthToken callback is called.' +
|
|
210
|
+
'See https://developers.thoughtspot.com/docs/?pageid=embed-auth#trusted-auth-embed for more details.';
|
|
234
211
|
let prevAuthToken: string = null;
|
|
235
|
-
/**
|
|
236
|
-
*
|
|
237
|
-
* @param authtoken
|
|
238
|
-
*/
|
|
239
212
|
function alertForDuplicateToken(authtoken: string) {
|
|
240
213
|
if (prevAuthToken === authtoken) {
|
|
241
214
|
// eslint-disable-next-line no-alert
|
|
@@ -257,14 +230,18 @@ function isAtSSORedirectUrl(): boolean {
|
|
|
257
230
|
*/
|
|
258
231
|
function removeSSORedirectUrlMarker(): void {
|
|
259
232
|
// Note (sunny): This will leave a # around even if it was not in the URL
|
|
260
|
-
// to begin with. Trying to remove the hash by changing window.location will
|
|
261
|
-
//
|
|
262
|
-
//
|
|
263
|
-
|
|
264
|
-
|
|
233
|
+
// to begin with. Trying to remove the hash by changing window.location will reload
|
|
234
|
+
// the page which we don't want. We'll live with adding an unnecessary hash to the
|
|
235
|
+
// parent page URL until we find any use case where that creates an issue.
|
|
236
|
+
window.location.hash = window.location.hash.replace(
|
|
237
|
+
SSO_REDIRECTION_MARKER_GUID,
|
|
238
|
+
'',
|
|
239
|
+
);
|
|
265
240
|
}
|
|
266
241
|
|
|
267
|
-
export const getAuthenticaionToken = async (
|
|
242
|
+
export const getAuthenticaionToken = async (
|
|
243
|
+
embedConfig: EmbedConfig,
|
|
244
|
+
): Promise<any> => {
|
|
268
245
|
const { authEndpoint, getAuthToken } = embedConfig;
|
|
269
246
|
let authToken = null;
|
|
270
247
|
if (getAuthToken) {
|
|
@@ -279,30 +256,40 @@ export const getAuthenticaionToken = async (embedConfig: EmbedConfig): Promise<a
|
|
|
279
256
|
|
|
280
257
|
/**
|
|
281
258
|
* Perform token based authentication
|
|
282
|
-
*
|
|
283
259
|
* @param embedConfig The embed configuration
|
|
284
260
|
*/
|
|
285
|
-
export const doTokenAuth = async (
|
|
261
|
+
export const doTokenAuth = async (
|
|
262
|
+
embedConfig: EmbedConfig,
|
|
263
|
+
): Promise<boolean> => {
|
|
286
264
|
const {
|
|
287
|
-
thoughtSpotHost,
|
|
265
|
+
thoughtSpotHost,
|
|
266
|
+
username,
|
|
267
|
+
authEndpoint,
|
|
268
|
+
getAuthToken,
|
|
288
269
|
} = embedConfig;
|
|
289
270
|
if (!authEndpoint && !getAuthToken) {
|
|
290
|
-
throw new Error(
|
|
271
|
+
throw new Error(
|
|
272
|
+
'Either auth endpoint or getAuthToken function must be provided',
|
|
273
|
+
);
|
|
291
274
|
}
|
|
292
275
|
loggedInStatus = await isLoggedIn(thoughtSpotHost);
|
|
293
276
|
if (!loggedInStatus) {
|
|
294
277
|
const authToken = await getAuthenticaionToken(embedConfig);
|
|
295
278
|
let resp;
|
|
296
279
|
try {
|
|
297
|
-
resp = await fetchAuthPostService(
|
|
280
|
+
resp = await fetchAuthPostService(
|
|
281
|
+
thoughtSpotHost,
|
|
282
|
+
username,
|
|
283
|
+
authToken,
|
|
284
|
+
);
|
|
298
285
|
} catch (e) {
|
|
299
286
|
resp = await fetchAuthService(thoughtSpotHost, username, authToken);
|
|
300
287
|
}
|
|
301
288
|
// token login issues a 302 when successful
|
|
302
289
|
loggedInStatus = resp.ok || resp.type === 'opaqueredirect';
|
|
303
290
|
if (loggedInStatus && embedConfig.detectCookieAccessSlow) {
|
|
304
|
-
// When 3rd party cookie access is blocked, this will fail because
|
|
305
|
-
//
|
|
291
|
+
// When 3rd party cookie access is blocked, this will fail because cookies will
|
|
292
|
+
// not be sent with the call.
|
|
306
293
|
loggedInStatus = await isLoggedIn(thoughtSpotHost);
|
|
307
294
|
}
|
|
308
295
|
}
|
|
@@ -311,13 +298,16 @@ export const doTokenAuth = async (embedConfig: EmbedConfig): Promise<boolean> =>
|
|
|
311
298
|
|
|
312
299
|
/**
|
|
313
300
|
* Validate embedConfig parameters required for cookielessTokenAuth
|
|
314
|
-
*
|
|
315
301
|
* @param embedConfig The embed configuration
|
|
316
302
|
*/
|
|
317
|
-
export const doCookielessTokenAuth = async (
|
|
303
|
+
export const doCookielessTokenAuth = async (
|
|
304
|
+
embedConfig: EmbedConfig,
|
|
305
|
+
): Promise<boolean> => {
|
|
318
306
|
const { authEndpoint, getAuthToken } = embedConfig;
|
|
319
307
|
if (!authEndpoint && !getAuthToken) {
|
|
320
|
-
throw new Error(
|
|
308
|
+
throw new Error(
|
|
309
|
+
'Either auth endpoint or getAuthToken function must be provided',
|
|
310
|
+
);
|
|
321
311
|
}
|
|
322
312
|
return Promise.resolve(true);
|
|
323
313
|
};
|
|
@@ -328,14 +318,19 @@ export const doCookielessTokenAuth = async (embedConfig: EmbedConfig): Promise<b
|
|
|
328
318
|
*
|
|
329
319
|
* Warning: This feature is primarily intended for developer testing. It is
|
|
330
320
|
* strongly advised not to use this authentication method in production.
|
|
331
|
-
*
|
|
332
321
|
* @param embedConfig The embed configuration
|
|
333
322
|
*/
|
|
334
|
-
export const doBasicAuth = async (
|
|
323
|
+
export const doBasicAuth = async (
|
|
324
|
+
embedConfig: EmbedConfig,
|
|
325
|
+
): Promise<boolean> => {
|
|
335
326
|
const { thoughtSpotHost, username, password } = embedConfig;
|
|
336
327
|
const loggedIn = await isLoggedIn(thoughtSpotHost);
|
|
337
328
|
if (!loggedIn) {
|
|
338
|
-
const response = await fetchBasicAuthService(
|
|
329
|
+
const response = await fetchBasicAuthService(
|
|
330
|
+
thoughtSpotHost,
|
|
331
|
+
username,
|
|
332
|
+
password,
|
|
333
|
+
);
|
|
339
334
|
loggedInStatus = response.ok;
|
|
340
335
|
if (embedConfig.detectCookieAccessSlow) {
|
|
341
336
|
loggedInStatus = await isLoggedIn(thoughtSpotHost);
|
|
@@ -346,13 +341,11 @@ export const doBasicAuth = async (embedConfig: EmbedConfig): Promise<boolean> =>
|
|
|
346
341
|
return loggedInStatus;
|
|
347
342
|
};
|
|
348
343
|
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
*/
|
|
355
|
-
async function samlPopupFlow(ssoURL: string, triggerContainer: DOMSelector, triggerText: string) {
|
|
344
|
+
async function samlPopupFlow(
|
|
345
|
+
ssoURL: string,
|
|
346
|
+
triggerContainer: DOMSelector,
|
|
347
|
+
triggerText: string,
|
|
348
|
+
) {
|
|
356
349
|
const openPopup = () => {
|
|
357
350
|
if (samlAuthWindow === null || samlAuthWindow.closed) {
|
|
358
351
|
samlAuthWindow = window.open(
|
|
@@ -367,13 +360,15 @@ async function samlPopupFlow(ssoURL: string, triggerContainer: DOMSelector, trig
|
|
|
367
360
|
authEE?.emit(AuthStatus.WAITING_FOR_POPUP);
|
|
368
361
|
const containerEl = getDOMNode(triggerContainer);
|
|
369
362
|
if (containerEl) {
|
|
370
|
-
containerEl.innerHTML =
|
|
363
|
+
containerEl.innerHTML =
|
|
364
|
+
'<button id="ts-auth-btn" class="ts-auth-btn" style="margin: auto;"></button>';
|
|
371
365
|
const authElem = document.getElementById('ts-auth-btn');
|
|
372
366
|
authElem.textContent = triggerText;
|
|
373
367
|
authElem.addEventListener('click', openPopup, { once: true });
|
|
374
368
|
}
|
|
375
|
-
samlCompletionPromise =
|
|
376
|
-
||
|
|
369
|
+
samlCompletionPromise =
|
|
370
|
+
samlCompletionPromise ||
|
|
371
|
+
new Promise<void>((resolve, reject) => {
|
|
377
372
|
window.addEventListener('message', (e) => {
|
|
378
373
|
if (e.data.type === EmbedEvent.SAMLComplete) {
|
|
379
374
|
(e.source as Window).close();
|
|
@@ -388,11 +383,12 @@ async function samlPopupFlow(ssoURL: string, triggerContainer: DOMSelector, trig
|
|
|
388
383
|
|
|
389
384
|
/**
|
|
390
385
|
* Perform SAML authentication
|
|
391
|
-
*
|
|
392
386
|
* @param embedConfig The embed configuration
|
|
393
|
-
* @param ssoEndPoint
|
|
394
387
|
*/
|
|
395
|
-
const doSSOAuth = async (
|
|
388
|
+
const doSSOAuth = async (
|
|
389
|
+
embedConfig: EmbedConfig,
|
|
390
|
+
ssoEndPoint: string,
|
|
391
|
+
): Promise<void> => {
|
|
396
392
|
const { thoughtSpotHost } = embedConfig;
|
|
397
393
|
const loggedIn = await isLoggedIn(thoughtSpotHost);
|
|
398
394
|
if (loggedIn) {
|
|
@@ -413,7 +409,11 @@ const doSSOAuth = async (embedConfig: EmbedConfig, ssoEndPoint: string): Promise
|
|
|
413
409
|
|
|
414
410
|
const ssoURL = `${thoughtSpotHost}${ssoEndPoint}`;
|
|
415
411
|
if (embedConfig.inPopup) {
|
|
416
|
-
await samlPopupFlow(
|
|
412
|
+
await samlPopupFlow(
|
|
413
|
+
ssoURL,
|
|
414
|
+
embedConfig.authTriggerContainer,
|
|
415
|
+
embedConfig.authTriggerText,
|
|
416
|
+
);
|
|
417
417
|
loggedInStatus = true;
|
|
418
418
|
return;
|
|
419
419
|
}
|
|
@@ -423,18 +423,20 @@ const doSSOAuth = async (embedConfig: EmbedConfig, ssoEndPoint: string): Promise
|
|
|
423
423
|
|
|
424
424
|
export const doSamlAuth = async (embedConfig: EmbedConfig) => {
|
|
425
425
|
const { thoughtSpotHost } = embedConfig;
|
|
426
|
-
// redirect for SSO, when the SSO authentication is done, this page will be
|
|
427
|
-
//
|
|
426
|
+
// redirect for SSO, when the SSO authentication is done, this page will be loaded
|
|
427
|
+
// again and the same JS will execute again.
|
|
428
428
|
const ssoRedirectUrl = embedConfig.inPopup
|
|
429
429
|
? `${thoughtSpotHost}/v2/#/embed/saml-complete`
|
|
430
430
|
: getRedirectUrl(
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
431
|
+
window.location.href,
|
|
432
|
+
SSO_REDIRECTION_MARKER_GUID,
|
|
433
|
+
embedConfig.redirectPath,
|
|
434
|
+
);
|
|
435
435
|
|
|
436
436
|
// bring back the page to the same URL
|
|
437
|
-
const ssoEndPoint = `${EndPoints.SAML_LOGIN_TEMPLATE(
|
|
437
|
+
const ssoEndPoint = `${EndPoints.SAML_LOGIN_TEMPLATE(
|
|
438
|
+
encodeURIComponent(ssoRedirectUrl),
|
|
439
|
+
)}`;
|
|
438
440
|
|
|
439
441
|
await doSSOAuth(embedConfig, ssoEndPoint);
|
|
440
442
|
return loggedInStatus;
|
|
@@ -442,18 +444,21 @@ export const doSamlAuth = async (embedConfig: EmbedConfig) => {
|
|
|
442
444
|
|
|
443
445
|
export const doOIDCAuth = async (embedConfig: EmbedConfig) => {
|
|
444
446
|
const { thoughtSpotHost } = embedConfig;
|
|
445
|
-
// redirect for SSO, when the SSO authentication is done, this page will be
|
|
446
|
-
//
|
|
447
|
-
const ssoRedirectUrl =
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
447
|
+
// redirect for SSO, when the SSO authentication is done, this page will be loaded
|
|
448
|
+
// again and the same JS will execute again.
|
|
449
|
+
const ssoRedirectUrl =
|
|
450
|
+
embedConfig.noRedirect || embedConfig.inPopup
|
|
451
|
+
? `${thoughtSpotHost}/v2/#/embed/saml-complete`
|
|
452
|
+
: getRedirectUrl(
|
|
453
|
+
window.location.href,
|
|
454
|
+
SSO_REDIRECTION_MARKER_GUID,
|
|
455
|
+
embedConfig.redirectPath,
|
|
456
|
+
);
|
|
454
457
|
|
|
455
458
|
// bring back the page to the same URL
|
|
456
|
-
const ssoEndPoint = `${EndPoints.OIDC_LOGIN_TEMPLATE(
|
|
459
|
+
const ssoEndPoint = `${EndPoints.OIDC_LOGIN_TEMPLATE(
|
|
460
|
+
encodeURIComponent(ssoRedirectUrl),
|
|
461
|
+
)}`;
|
|
457
462
|
|
|
458
463
|
await doSSOAuth(embedConfig, ssoEndPoint);
|
|
459
464
|
return loggedInStatus;
|
|
@@ -468,10 +473,11 @@ export const logout = async (embedConfig: EmbedConfig): Promise<boolean> => {
|
|
|
468
473
|
|
|
469
474
|
/**
|
|
470
475
|
* Perform authentication on the ThoughtSpot cluster
|
|
471
|
-
*
|
|
472
476
|
* @param embedConfig The embed configuration
|
|
473
477
|
*/
|
|
474
|
-
export const authenticate = async (
|
|
478
|
+
export const authenticate = async (
|
|
479
|
+
embedConfig: EmbedConfig,
|
|
480
|
+
): Promise<boolean> => {
|
|
475
481
|
const { authType } = embedConfig;
|
|
476
482
|
switch (authType) {
|
|
477
483
|
case AuthType.SSO:
|
package/src/config.spec.ts
CHANGED
|
@@ -59,7 +59,8 @@ describe('getThoughtSpotHost', () => {
|
|
|
59
59
|
expect(
|
|
60
60
|
getThoughtSpotHost({
|
|
61
61
|
...embedConfig,
|
|
62
|
-
thoughtSpotHost:
|
|
62
|
+
thoughtSpotHost:
|
|
63
|
+
'http://1.2.3.4:8088/v2/?foo=bar&baz=42#myhash',
|
|
63
64
|
}),
|
|
64
65
|
).toBe('http://1.2.3.4:8088/v2');
|
|
65
66
|
});
|
|
@@ -69,7 +70,8 @@ describe('getThoughtSpotHost', () => {
|
|
|
69
70
|
getThoughtSpotHost({
|
|
70
71
|
...embedConfig,
|
|
71
72
|
authType: AuthType.SAML,
|
|
72
|
-
thoughtSpotHost:
|
|
73
|
+
thoughtSpotHost:
|
|
74
|
+
'http://1.2.3.4:8088/v2/?foo=bar&baz=42#myhash',
|
|
73
75
|
}),
|
|
74
76
|
).toBe('http://1.2.3.4:8088/v2');
|
|
75
77
|
});
|
package/src/config.ts
CHANGED
|
@@ -23,7 +23,6 @@ const urlRegex = new RegExp(
|
|
|
23
23
|
/**
|
|
24
24
|
* Parse and construct the ThoughtSpot hostname or IP address
|
|
25
25
|
* from the embed configuration object.
|
|
26
|
-
*
|
|
27
26
|
* @param config
|
|
28
27
|
*/
|
|
29
28
|
export const getThoughtSpotHost = (config: EmbedConfig): string => {
|
|
@@ -52,10 +51,9 @@ export const getV2BasePath = (config: EmbedConfig): string => {
|
|
|
52
51
|
|
|
53
52
|
const tsHost = getThoughtSpotHost(config);
|
|
54
53
|
|
|
55
|
-
// This is to handle when e2e's. Search is run on pods for
|
|
56
|
-
//
|
|
57
|
-
// This is to handle when the developer is developing in their local
|
|
58
|
-
// environment.
|
|
54
|
+
// This is to handle when e2e's. Search is run on pods for comp-blink-test-pipeline
|
|
55
|
+
// with baseUrl=https://localhost:8443.
|
|
56
|
+
// This is to handle when the developer is developing in their local environment.
|
|
59
57
|
if (tsHost.includes('://localhost') && !tsHost.includes(':8443')) {
|
|
60
58
|
return '';
|
|
61
59
|
}
|
package/src/embed/app.spec.ts
CHANGED
|
@@ -1,8 +1,6 @@
|
|
|
1
1
|
import { AppEmbed, AppViewConfig, Page } from './app';
|
|
2
2
|
import { init } from '../index';
|
|
3
|
-
import {
|
|
4
|
-
Action, AuthType, HostEvent, RuntimeFilterOp,
|
|
5
|
-
} from '../types';
|
|
3
|
+
import { Action, AuthType, HostEvent, RuntimeFilterOp } from '../types';
|
|
6
4
|
import {
|
|
7
5
|
executeAfterWait,
|
|
8
6
|
getDocumentBody,
|
|
@@ -13,7 +11,6 @@ import {
|
|
|
13
11
|
defaultParams,
|
|
14
12
|
defaultParamsForPinboardEmbed,
|
|
15
13
|
defaultParamsWithoutHiddenActions,
|
|
16
|
-
expectUrlMatchesWithParams,
|
|
17
14
|
} from '../test/test-utils';
|
|
18
15
|
import { version } from '../../package.json';
|
|
19
16
|
import * as config from '../config';
|
|
@@ -47,8 +44,7 @@ describe('App embed tests', () => {
|
|
|
47
44
|
const appEmbed = new AppEmbed(getRootEl(), defaultViewConfig);
|
|
48
45
|
appEmbed.render();
|
|
49
46
|
await executeAfterWait(() => {
|
|
50
|
-
|
|
51
|
-
getIFrameSrc(),
|
|
47
|
+
expect(getIFrameSrc()).toBe(
|
|
52
48
|
`http://${thoughtSpotHost}/?embedApp=true&primaryNavHidden=true&profileAndHelpInNavBarHidden=false${defaultParams}${defaultParamsPost}#/home`,
|
|
53
49
|
);
|
|
54
50
|
});
|
|
@@ -61,8 +57,7 @@ describe('App embed tests', () => {
|
|
|
61
57
|
} as AppViewConfig);
|
|
62
58
|
appEmbed.render();
|
|
63
59
|
await executeAfterWait(() => {
|
|
64
|
-
|
|
65
|
-
getIFrameSrc(),
|
|
60
|
+
expect(getIFrameSrc()).toBe(
|
|
66
61
|
`http://${thoughtSpotHost}/?embedApp=true&primaryNavHidden=false&profileAndHelpInNavBarHidden=false${defaultParams}${defaultParamsPost}#/home`,
|
|
67
62
|
);
|
|
68
63
|
});
|
|
@@ -75,8 +70,7 @@ describe('App embed tests', () => {
|
|
|
75
70
|
} as AppViewConfig);
|
|
76
71
|
appEmbed.render();
|
|
77
72
|
await executeAfterWait(() => {
|
|
78
|
-
|
|
79
|
-
getIFrameSrc(),
|
|
73
|
+
expect(getIFrameSrc()).toBe(
|
|
80
74
|
`http://${thoughtSpotHost}/?embedApp=true&primaryNavHidden=true&profileAndHelpInNavBarHidden=true${defaultParams}${defaultParamsPost}#/home`,
|
|
81
75
|
);
|
|
82
76
|
});
|
|
@@ -107,8 +101,7 @@ describe('App embed tests', () => {
|
|
|
107
101
|
appEmbed.render();
|
|
108
102
|
|
|
109
103
|
await executeAfterWait(() => {
|
|
110
|
-
|
|
111
|
-
getIFrameSrc(),
|
|
104
|
+
expect(getIFrameSrc()).toBe(
|
|
112
105
|
`http://${thoughtSpotHost}/?embedApp=true&primaryNavHidden=true&profileAndHelpInNavBarHidden=false${defaultParams}${defaultParamsPost}#/${route}`,
|
|
113
106
|
);
|
|
114
107
|
cleanUp();
|
|
@@ -124,8 +117,7 @@ describe('App embed tests', () => {
|
|
|
124
117
|
} as AppViewConfig);
|
|
125
118
|
appEmbed.render();
|
|
126
119
|
await executeAfterWait(() => {
|
|
127
|
-
|
|
128
|
-
getIFrameSrc(),
|
|
120
|
+
expect(getIFrameSrc()).toBe(
|
|
129
121
|
`http://${thoughtSpotHost}/?embedApp=true&primaryNavHidden=true&profileAndHelpInNavBarHidden=false${defaultParams}${defaultParamsPost}#/foo/bar`,
|
|
130
122
|
);
|
|
131
123
|
});
|
|
@@ -146,8 +138,7 @@ describe('App embed tests', () => {
|
|
|
146
138
|
|
|
147
139
|
appEmbed.render();
|
|
148
140
|
await executeAfterWait(() => {
|
|
149
|
-
|
|
150
|
-
getIFrameSrc(),
|
|
141
|
+
expect(getIFrameSrc()).toBe(
|
|
151
142
|
`http://${thoughtSpotHost}/?embedApp=true&primaryNavHidden=false&profileAndHelpInNavBarHidden=false&col1=sales&op1=EQ&val1=1000${defaultParams}${defaultParamsPost}#/home`,
|
|
152
143
|
);
|
|
153
144
|
});
|
|
@@ -164,8 +155,7 @@ describe('App embed tests', () => {
|
|
|
164
155
|
|
|
165
156
|
appEmbed.render();
|
|
166
157
|
await executeAfterWait(() => {
|
|
167
|
-
|
|
168
|
-
getIFrameSrc(),
|
|
158
|
+
expect(getIFrameSrc()).toBe(
|
|
169
159
|
`http://${thoughtSpotHost}/?embedApp=true&primaryNavHidden=false&profileAndHelpInNavBarHidden=false&${defaultParamsWithoutHiddenActions}&disableAction=[%22save%22,%22update%22]&disableHint=Access%20denied&hideAction=[%22${Action.ReportError}%22,%22download%22]${defaultParamsPost}#/home`,
|
|
170
160
|
);
|
|
171
161
|
});
|
|
@@ -180,8 +170,7 @@ describe('App embed tests', () => {
|
|
|
180
170
|
|
|
181
171
|
appEmbed.render();
|
|
182
172
|
await executeAfterWait(() => {
|
|
183
|
-
|
|
184
|
-
getIFrameSrc(),
|
|
173
|
+
expect(getIFrameSrc()).toBe(
|
|
185
174
|
`http://${thoughtSpotHost}/?embedApp=true&primaryNavHidden=true&profileAndHelpInNavBarHidden=false${defaultParams}&tag=Finance${defaultParamsPost}#/home`,
|
|
186
175
|
);
|
|
187
176
|
});
|
|
@@ -195,8 +184,7 @@ describe('App embed tests', () => {
|
|
|
195
184
|
|
|
196
185
|
appEmbed.render();
|
|
197
186
|
await executeAfterWait(() => {
|
|
198
|
-
|
|
199
|
-
getIFrameSrc(),
|
|
187
|
+
expect(getIFrameSrc()).toBe(
|
|
200
188
|
`http://${thoughtSpotHost}/?embedApp=true&primaryNavHidden=true&profileAndHelpInNavBarHidden=false&enableSearchAssist=true${defaultParams}${defaultParamsPost}#/home`,
|
|
201
189
|
);
|
|
202
190
|
});
|
|
@@ -205,7 +193,9 @@ describe('App embed tests', () => {
|
|
|
205
193
|
describe('Navigate to Page API', () => {
|
|
206
194
|
const path = 'pinboard/e0836cad-4fdf-42d4-bd97-567a6b2a6058';
|
|
207
195
|
beforeEach(() => {
|
|
208
|
-
jest.spyOn(config, 'getThoughtSpotHost').mockImplementation(
|
|
196
|
+
jest.spyOn(config, 'getThoughtSpotHost').mockImplementation(
|
|
197
|
+
() => 'http://tshost',
|
|
198
|
+
);
|
|
209
199
|
});
|
|
210
200
|
|
|
211
201
|
test('when app is AppEmbed after navigateToPage function call, new path should be set to iframe', async () => {
|
|
@@ -217,8 +207,7 @@ describe('App embed tests', () => {
|
|
|
217
207
|
});
|
|
218
208
|
await appEmbed.render();
|
|
219
209
|
appEmbed.navigateToPage(path);
|
|
220
|
-
|
|
221
|
-
getIFrameSrc(),
|
|
210
|
+
expect(getIFrameSrc()).toBe(
|
|
222
211
|
`http://${thoughtSpotHost}/?embedApp=true&primaryNavHidden=true&profileAndHelpInNavBarHidden=false&${defaultParamsForPinboardEmbed}${defaultParamsPost}#/${path}`,
|
|
223
212
|
);
|
|
224
213
|
});
|