Skip to content

Commit 74199b8

Browse files
authored
Merge pull request #38 from Shopify/address-security-issue
Address security concern
2 parents 0dd7437 + a88c6e0 commit 74199b8

11 files changed

+77
-44
lines changed

CHANGELOG.md

+10
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
# Change Log
2+
3+
## v1.0.1 (Jan 27, 2019)
4+
5+
* [#37](https://github.com/Shopify/shopify-theme-inspector/pull/37) Fix custom domain redirect
6+
* [#38](https://github.com/Shopify/shopify-theme-inspector/pull/38) Address security concern
7+
8+
## v1.0.0 (Jan. 14, 2019)
9+
10+
* First release of the extension

src/components/liquid-flamegraph.ts

+13-15
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,12 @@ import * as d3 from 'd3';
22
import * as flamegraph from 'd3-flame-graph';
33
import 'd3-flame-graph/dist/d3-flamegraph.css';
44
import {debounce} from 'lodash';
5-
import {formatNodeTime, getThemeId} from '../utils';
5+
import {
6+
formatNodeTime,
7+
getThemeId,
8+
emptyHTMLNode,
9+
updateInfoText,
10+
} from '../utils';
611

712
const selectors = {
813
partial: '[data-partial]',
@@ -33,7 +38,7 @@ export default class LiquidFlamegraph {
3338
}
3439

3540
display(): void {
36-
this.element.innerHTML = '';
41+
emptyHTMLNode(this.element);
3742
d3.select(this.element)
3843
.datum(this.profile)
3944
.call(this.flamegraph);
@@ -63,26 +68,19 @@ export default class LiquidFlamegraph {
6368
}
6469

6570
async displayNodeDetails(node: FlamegraphNode) {
66-
document.querySelector(
67-
selectors.partial,
68-
)!.innerHTML = `File: ${node.data.name}`;
69-
70-
document.querySelector(
71-
selectors.nodeTime,
72-
)!.innerHTML = `Total Time: <b>${formatNodeTime(node.value)}ms</b>`;
71+
updateInfoText(selectors.partial, node.data.name);
72+
updateInfoText(selectors.nodeTime, `${formatNodeTime(node.value)}ms`);
7373

7474
const clickableLink = await this.generateClickableLink(
7575
node.data.name,
7676
node.data.line,
7777
);
7878

79-
document.querySelector(
80-
selectors.code,
81-
)!.innerHTML = `Code snippet: <a href="${clickableLink}" target="_blank"><i><span class="code-snippet">${node.data.code}</span></i></a>`;
79+
const codeLink = document.querySelector(selectors.code);
80+
codeLink!.querySelector('a')!.href = clickableLink;
81+
codeLink!.querySelector('.code-snippet')!.textContent = node.data.code;
8282

83-
document.querySelector(
84-
selectors.line,
85-
)!.innerHTML = `Line: ${node.data.line}`;
83+
updateInfoText(selectors.line, `${node.data.line}`);
8684
}
8785

8886
async generateClickableLink(

src/devtools.html

+8-6
Original file line numberDiff line numberDiff line change
@@ -43,15 +43,17 @@ <h2>This page cannot be profiled</h2>
4343
<p>Click <a href="https://github.com/Shopify/shopify-devtools#extension-usage" target="_blank">here</a> to read more about this.</p>
4444
</div>
4545

46-
<div data-flamegraph-wrapper>
46+
<div data-flamegraph-wrapper class="hide">
4747
<div data-flamegraph-container class="chart"></div>
48-
<p data-total-time class="total-time"></p>
48+
<p data-total-time class="total-time">Total time to render liquid: <b>-</b></p>
4949

5050
<div data-detailed-info class="detailed-info">
51-
<p data-partial></p>
52-
<p data-node-time></p>
53-
<p data-code></p>
54-
<p data-line></p>
51+
<p data-partial>File: <b>-</b></p>
52+
<p data-node-time>Total Time: <b>-</b></p>
53+
<p data-code>
54+
Code snippet: <a href="" target="_blank"><i><span class="code-snippet"></span></i></a>
55+
</p>
56+
<p data-line>Line: <b>-</b></p>
5557
</div>
5658
</div>
5759
</body>

src/devtools.ts

+7-2
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,11 @@
11
import Toolbar from './components/toolbar';
22
import LiquidFlamegraph from './components/liquid-flamegraph';
3-
import {getProfileData, setTotalTime, getBrowserTheme} from './utils';
3+
import {
4+
getProfileData,
5+
setTotalTime,
6+
getBrowserTheme,
7+
emptyHTMLNode,
8+
} from './utils';
49

510
import './styles/devtools.css';
611

@@ -43,7 +48,7 @@ function getInspectedWindowURL(): Promise<URL> {
4348
}
4449

4550
async function refreshPanel() {
46-
document.querySelector(selectors.initialMessage)!.innerHTML = '';
51+
emptyHTMLNode(document.querySelector(selectors.initialMessage));
4752
document
4853
.querySelector(selectors.flamegraphWrapper)!
4954
.classList.add('loading-fade');

src/popup.ts

+6-7
Original file line numberDiff line numberDiff line change
@@ -14,15 +14,14 @@ const signOutButton = document.querySelector(`[data-sign-out]`);
1414

1515
async function setSignedInPopup() {
1616
const popupSignedInPrompt = document.querySelector(
17-
selectors.popupSignedInPrompt,
17+
`${selectors.popupSignedInPrompt} b`,
1818
);
1919

2020
if (popupSignedIn) popupSignedIn.classList.remove('hide');
2121
if (popupSignIn) popupSignIn.classList.add('hide');
2222

2323
const name = await getUserName();
24-
if (popupSignedInPrompt)
25-
popupSignedInPrompt.innerHTML = `You are logged in as <b>${name}</b>`;
24+
popupSignedInPrompt!.textContent = `${name}`;
2625
}
2726

2827
function setSignInPopup() {
@@ -70,8 +69,8 @@ if (signInButton) {
7069
}
7170
},
7271
);
73-
signInButton.innerHTML =
74-
'<div data-loading-animation class="loader" style="display: inline-block"></div>';
72+
signInButton.querySelector('span')?.classList.add('hide');
73+
signInButton.querySelector('.loader')?.classList.remove('hide');
7574
});
7675
}
7776

@@ -85,8 +84,8 @@ if (signOutButton) {
8584
setSignInPopup();
8685
}
8786
});
88-
signOutButton.innerHTML =
89-
'<div data-loading-animation class="loader" style="display: inline-block"></div>';
87+
signOutButton.querySelector('span')?.classList.add('hide');
88+
signOutButton.querySelector('.loader')?.classList.remove('hide');
9089
});
9190
}
9291

src/popupAuthFlow.html

+9-3
Original file line numberDiff line numberDiff line change
@@ -7,15 +7,21 @@
77
<img class="shopify-logo" src="./images/shopify_logo_black.png" alt="Shopify Logo">
88
<hr class="faded-hr">
99
<p class="login-prompt">Sign in to your Shopify account</p>
10-
<button class="popup-button" id="signInButton" data-sign-in>Sign In</button>
10+
<button class="popup-button" id="signInButton" data-sign-in>
11+
<span>Sign In</span>
12+
<div data-loading-animation class="loader hide" style="display: inline-block"></div>
13+
</button>
1114
</div>
1215

1316
<div class="popup hide" data-popup-signed-in>
1417
<img class="shopify-logo" src="./images/shopify_logo_black.png" alt="Shopify Logo">
1518
<hr class="faded-hr">
16-
<p class="login-prompt" data-signed-in-prompt>&nbsp;</p>
19+
<p class="login-prompt" data-signed-in-prompt>You are logged in as <b>-</b></p>
1720
<p class="login-prompt"><a href="https://developers.google.com/web/tools/chrome-devtools/open" target="_blank">Open Chrome DevTools</a> and select the <b>Shopify</b> tab</p>
18-
<button class="popup-button" id="signOutButton" data-sign-out>Sign Out</button>
21+
<button class="popup-button" id="signOutButton" data-sign-out>
22+
<span>Sign Out</span>
23+
<div data-loading-animation class="loader hide" style="display: inline-block"></div>
24+
</button>
1925
</div>
2026
</body>
2127
</html>

src/styles/popup.css

+1-1
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@
3333
}
3434

3535
.hide {
36-
display: none;
36+
display: none !important;
3737
}
3838

3939
.loader {

src/utils/domHelpers.ts

+13-5
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,5 @@
11
export function setTotalTime(totalTime: number) {
2-
document.querySelector(
3-
'[data-total-time]',
4-
)!.innerHTML = `Total time to render liquid: <b>${Math.trunc(
5-
totalTime * 1000,
6-
)}ms</b>`;
2+
updateInfoText('[data-total-time]', `${Math.trunc(totalTime * 1000)}ms`);
73
}
84

95
export function formatNodeTime(nodeTime: number) {
@@ -14,3 +10,15 @@ export function formatNodeTime(nodeTime: number) {
1410
return '< 1';
1511
}
1612
}
13+
14+
export function emptyHTMLNode(node: any) {
15+
if (!node) return;
16+
17+
while (node.firstChild) {
18+
node.removeChild(node.firstChild);
19+
}
20+
}
21+
22+
export function updateInfoText(selector: string, updateText: string) {
23+
document.querySelector(`${selector} b`)!.textContent = updateText;
24+
}

src/utils/getProfileData.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ export async function getProfileData(
2727
}
2828

2929
const profileData = JSON.parse(
30-
nullthrows(document.querySelector('#liquidProfileData')).innerHTML,
30+
nullthrows(document.querySelector('#liquidProfileData')).textContent || '',
3131
);
3232

3333
return cleanProfileData(profileData);

src/utils/index.ts

+6-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,11 @@
11
export {getProfileData} from './getProfileData';
22
export {isDev, getThemeId, getBrowserTheme} from './helpers';
3-
export {setTotalTime, formatNodeTime} from './domHelpers';
3+
export {
4+
setTotalTime,
5+
formatNodeTime,
6+
emptyHTMLNode,
7+
updateInfoText,
8+
} from './domHelpers';
49
export {Oauth2} from './oauth2';
510
export {
611
saveToLocalStorage,

test/devtools.test.ts

+3-3
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ describe('Devtools', () => {
1515
});
1616

1717
it('test initial message for devtools window is displayed', async () => {
18-
const elementText = await page.$eval('.initial', elem => elem.innerHTML);
18+
const elementText = await page.$eval('.initial', elem => elem.textContent);
1919
expect(elementText).toStrictEqual('No profiling recorded yet');
2020
});
2121

@@ -24,7 +24,7 @@ describe('Devtools', () => {
2424
await page.$eval('[data-refresh-button]', elem => elem.click());
2525
const flamegraphElement = await page.$eval(
2626
'.d3-flame-graph',
27-
elem => elem.innerHTML,
27+
elem => elem.textContent,
2828
);
2929
expect(flamegraphElement).not.toBeNull();
3030
});
@@ -50,7 +50,7 @@ describe('Devtools', () => {
5050
await page.$eval('.d3-flame-graph-label', elem => elem.click());
5151
const elementHtml = await page.$eval(
5252
'[data-detailed-info]',
53-
elem => elem.innerHTML,
53+
elem => elem.textContent,
5454
);
5555
expect(elementHtml).not.toBeNull();
5656
});

0 commit comments

Comments
 (0)