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