Skip to content

Commit 6e911c9

Browse files
author
Shahak Yosef
committed
Merged PR 62071: Block secure embed scenario in JS SDK
Block JS SDK usage whenever autuAuth query parameter present in embed url because secure embed isn’t supported with JS SDK. ![NotAllowed.PNG](https://powerbi.visualstudio.com/4c7b5adb-c2d0-4f18-b23c-edc4ac30f4e1/_apis/git/repositories/1dd63332-e003-46a3-ac6f-70213a1bcc2e/pullRequests/62071/attachments/NotAllowed.PNG) **Note for reviewers:** [This will break some unsuspecting clients](https://stackoverflow.com/a/59311295) ![so.PNG](https://powerbi.visualstudio.com/4c7b5adb-c2d0-4f18-b23c-edc4ac30f4e1/_apis/git/repositories/1dd63332-e003-46a3-ac6f-70213a1bcc2e/pullRequests/62071/attachments/so.PNG )
1 parent 6e6af9b commit 6e911c9

File tree

4 files changed

+301
-257
lines changed

4 files changed

+301
-257
lines changed

src/embed.ts

Lines changed: 39 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import * as service from './service';
33
import * as sdkConfig from './config';
44
import * as models from 'powerbi-models';
55
import { Defaults } from './defaults';
6+
import { EmbedUrlNotSupported } from './errors';
67

78
declare global {
89
interface Document {
@@ -211,6 +212,10 @@ export abstract class Embed {
211212
* @param {IEmbedConfigurationBase} config
212213
*/
213214
constructor(service: service.Service, element: HTMLElement, config: IEmbedConfigurationBase, iframe?: HTMLIFrameElement, phasedRender?: boolean, isBootstrap?: boolean) {
215+
if (utils.autoAuthInEmbedUrl(config.embedUrl)) {
216+
throw new Error(EmbedUrlNotSupported);
217+
}
218+
214219
Array.prototype.push.apply(this.allowedEvents, Embed.allowedEvents);
215220
this.eventHandlers = [];
216221
this.service = service;
@@ -249,9 +254,9 @@ export abstract class Embed {
249254
.then(response => {
250255
return response.body;
251256
},
252-
response => {
253-
throw response.body;
254-
});
257+
response => {
258+
throw response.body;
259+
});
255260
}
256261

257262
/**
@@ -327,9 +332,9 @@ export abstract class Embed {
327332
utils.assign(this.config, config);
328333
return response.body;
329334
},
330-
response => {
331-
throw response.body;
332-
});
335+
response => {
336+
throw response.body;
337+
});
333338
}
334339

335340
/**
@@ -386,7 +391,7 @@ export abstract class Embed {
386391
*/
387392
on<T>(eventName: string, handler: service.IEventHandler<T>): void {
388393
if (this.allowedEvents.indexOf(eventName) === -1) {
389-
throw new Error(`eventName is must be one of ${this.allowedEvents}. You passed: ${eventName}`);
394+
throw new Error(`eventName must be one of ${this.allowedEvents}. You passed: ${eventName}`);
390395
}
391396

392397
this.eventHandlers.push({
@@ -489,16 +494,16 @@ export abstract class Embed {
489494
* @param {IEmbedConfiguration} config
490495
*/
491496
private addLocaleToEmbedUrl(config: IEmbedConfiguration): void {
492-
if (!config.settings) {
493-
return;
494-
}
495-
let localeSettings = config.settings.localeSettings
496-
if (localeSettings && localeSettings.language) {
497-
this.config.embedUrl = utils.addParamToUrl(this.config.embedUrl, 'language', localeSettings.language);
498-
}
499-
if (localeSettings && localeSettings.formatLocale) {
500-
this.config.embedUrl = utils.addParamToUrl(this.config.embedUrl, 'formatLocale', localeSettings.formatLocale);
501-
}
497+
if (!config.settings) {
498+
return;
499+
}
500+
let localeSettings = config.settings.localeSettings
501+
if (localeSettings && localeSettings.language) {
502+
this.config.embedUrl = utils.addParamToUrl(this.config.embedUrl, 'language', localeSettings.language);
503+
}
504+
if (localeSettings && localeSettings.formatLocale) {
505+
this.config.embedUrl = utils.addParamToUrl(this.config.embedUrl, 'formatLocale', localeSettings.formatLocale);
506+
}
502507
}
503508

504509
/**
@@ -640,8 +645,8 @@ export abstract class Embed {
640645
iframeContent.setAttribute("scrolling", "no");
641646
iframeContent.setAttribute("allowfullscreen", "true");
642647
var node = this.element;
643-
while(node.firstChild) {
644-
node.removeChild(node.firstChild);
648+
while (node.firstChild) {
649+
node.removeChild(node.firstChild);
645650
}
646651
node.appendChild(iframeContent);
647652
this.iframe = <HTMLIFrameElement>node.firstChild;
@@ -673,10 +678,10 @@ export abstract class Embed {
673678
* Sets Iframe's title
674679
*/
675680
setComponentTitle(title: string): void {
676-
if(!this.iframe) {
681+
if (!this.iframe) {
677682
return;
678683
}
679-
if(title == null) {
684+
if (title == null) {
680685
this.iframe.removeAttribute("title");
681686
} else {
682687
this.iframe.setAttribute("title", title);
@@ -687,7 +692,7 @@ export abstract class Embed {
687692
* Sets element's tabindex attribute
688693
*/
689694
setComponentTabIndex(tabIndex?: number): void {
690-
if(!this.element) {
695+
if (!this.element) {
691696
return;
692697
}
693698
this.element.setAttribute("tabindex", (tabIndex == null) ? "0" : tabIndex.toString());
@@ -697,7 +702,7 @@ export abstract class Embed {
697702
* Removes element's tabindex attribute
698703
*/
699704
removeComponentTabIndex(tabIndex?: number): void {
700-
if(!this.element) {
705+
if (!this.element) {
701706
return;
702707
}
703708
this.element.removeAttribute("tabindex");
@@ -712,15 +717,15 @@ export abstract class Embed {
712717
* @returns {string}
713718
*/
714719
static findGroupIdFromEmbedUrl(url: string): string {
715-
const groupIdRegEx = /groupId="?([^&]+)"?/
716-
const groupIdMatch = url.match(groupIdRegEx);
720+
const groupIdRegEx = /groupId="?([^&]+)"?/
721+
const groupIdMatch = url.match(groupIdRegEx);
717722

718-
let groupId;
719-
if (groupIdMatch) {
720-
groupId = groupIdMatch[1];
721-
}
723+
let groupId;
724+
if (groupIdMatch) {
725+
groupId = groupIdMatch[1];
726+
}
722727

723-
return groupId;
728+
return groupId;
724729
}
725730

726731
/**
@@ -738,13 +743,13 @@ export abstract class Embed {
738743

739744
// contentWindow must be initialized
740745
if (this.iframe.contentWindow == null)
741-
return;
746+
return;
742747

743748
return this.service.hpm.post<void>("/frontload/config", config, { uid: this.config.uniqueId }, this.iframe.contentWindow).then(response => {
744749
return response.body;
745750
},
746-
response => {
747-
throw response.body;
748-
});
751+
response => {
752+
throw response.body;
753+
});
749754
}
750755
}

src/errors.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
11

22
export let APINotSupportedForRDLError: string = "This API is currently not supported for RDL reports";
3+
export let EmbedUrlNotSupported = "Embed URL is invalid for this scenario. Please use Power BI REST APIs to get the valid URL";
34

src/util.ts

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -166,13 +166,24 @@ export function isSavedInternal(hpm: HttpPostMessage, uid: string, contentWindow
166166
* Checks if the embed url is for RDL report.
167167
*
168168
* @export
169-
* @param {string} embedUrl
170-
* @returns {boolean}
169+
* @param {string} embedUrl
170+
* @returns {boolean}
171171
*/
172172
export function isRDLEmbed(embedUrl: string): boolean {
173173
return embedUrl.toLowerCase().indexOf("/rdlembed?") >= 0;
174174
}
175175

176+
/**
177+
* Checks if the embed url contains autoAuth=true.
178+
*
179+
* @export
180+
* @param {string} embedUrl
181+
* @returns {boolean}
182+
*/
183+
export function autoAuthInEmbedUrl(embedUrl: string): boolean {
184+
return embedUrl && decodeURIComponent(embedUrl).toLowerCase().indexOf("autoauth=true") >= 0;
185+
}
186+
176187
/**
177188
* Returns random number
178189
*/

0 commit comments

Comments
 (0)