Skip to content

Commit 0ef7bb7

Browse files
committed
Implement a popup for pages that we are not allowed to profile
1 parent 1c53c1e commit 0ef7bb7

File tree

4 files changed

+172
-20
lines changed

4 files changed

+172
-20
lines changed

src/background.js

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,31 @@ chrome.commands.onCommand.addListener(async (command) => {
9393
}
9494
});
9595

96+
// Listener for tab updates, like navigation.
97+
chrome.tabs.onUpdated.addListener((tabId, _changeInfo, tab) => {
98+
console.log("canova tab update", tab.url);
99+
state.updatePopupForTab(tabId, tab.url);
100+
});
101+
102+
// Listener for tab activation (e.g., switching tabs)
103+
chrome.tabs.onActivated.addListener(async (activeInfo) => {
104+
console.log("canova tab activation");
105+
const tab = await chrome.tabs.get(activeInfo.tabId);
106+
state.updatePopupForTab(activeInfo.tabId, tab.url);
107+
});
108+
109+
// Listener for when the extension is installed or updated
110+
chrome.runtime.onInstalled.addListener(async () => {
111+
console.log("canova on installed");
112+
const tab = await getCurrentTab();
113+
if (!tab || !tab.id) {
114+
console.error("Failed to find the current tab");
115+
return;
116+
}
117+
118+
state.updatePopupForTab(tab.id, tab.url);
119+
});
120+
96121
(() => {
97122
// Reset the state on the initial extension load.
98123
state.reset();

src/disabled_popup.html

Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
<!doctype html>
2+
<html lang="en">
3+
<head>
4+
<meta charset="UTF-8" />
5+
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
6+
<title>Firefox Profiler - Profiling Not Available</title>
7+
<style>
8+
:root {
9+
--bg-color: #ffffff;
10+
--text-color: #333;
11+
--heading-color: #d32f2f;
12+
--note-color: #666;
13+
}
14+
15+
@media (prefers-color-scheme: dark) {
16+
:root {
17+
--bg-color: #2a2a2a;
18+
--text-color: #f0f0f0;
19+
--heading-color: #ff6b6b;
20+
--note-color: #aaa;
21+
}
22+
}
23+
24+
body {
25+
font-family: Arial, sans-serif;
26+
margin: 0;
27+
padding: 20px;
28+
background-color: var(--bg-color);
29+
color: var(--text-color);
30+
width: 370px;
31+
box-sizing: border-box;
32+
padding: 20px;
33+
}
34+
35+
h1 {
36+
color: var(--heading-color);
37+
font-size: 20px;
38+
margin-top: 0;
39+
display: flex;
40+
align-items: center;
41+
}
42+
43+
h1 svg {
44+
margin-right: 10px;
45+
}
46+
47+
p {
48+
font-size: 14px;
49+
line-height: 1.5;
50+
margin-bottom: 15px;
51+
}
52+
53+
.note {
54+
font-style: italic;
55+
color: var(--note-color);
56+
}
57+
</style>
58+
</head>
59+
<body>
60+
<h1>
61+
<svg
62+
width="24"
63+
height="24"
64+
fill="currentColor"
65+
xmlns="http://www.w3.org/2000/svg"
66+
>
67+
<path d="M12.875 15.625h-1.75v1.75h1.75v-1.75z" />
68+
<path
69+
fill-rule="evenodd"
70+
clip-rule="evenodd"
71+
d="M11.125 14V9h1.75v5h-1.75z"
72+
/>
73+
<path
74+
d="M11.956 4.92c.165 0 .47.05.655.385l7.04 12.66a.729.729 0 0 1-.009.745.726.726 0 0 1-.646.37H5.004a.727.727 0 0 1-.645-.368.728.728 0 0 1-.012-.743L11.3 5.309a.725.725 0 0 1 .657-.389zm0-1.75c-.859 0-1.717.433-2.19 1.297l-6.953 12.66c-.915 1.666.29 3.703 2.191 3.703h13.993c1.907 0 3.112-2.049 2.185-3.715l-7.04-12.66a2.478 2.478 0 0 0-2.186-1.285z"
75+
/>
76+
</svg>
77+
Profiling Not Possible
78+
</h1>
79+
<p>Profiling is not available on this page.</p>
80+
<p>
81+
This is a privileged or restricted page (e.g., <code>chrome://</code>,
82+
<code>about://</code>, or the Chrome Web Store).
83+
</p>
84+
<p class="note">
85+
Please navigate to a non-privileged page to use the Firefox Profiler.
86+
</p>
87+
</body>
88+
</html>

src/state.js

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,9 @@
44

55
// @ts-check
66

7+
import { isPrivilegedUrl } from "./tabs.js";
8+
import { assertExhaustiveCheck } from "./ts.js";
9+
710
/**
811
* @typedef {"idle" | "starting" | "recording" | "stopping"} RecordingState
912
*/
@@ -35,6 +38,43 @@ export const state = {
3538
setIcons("off");
3639
chrome.action.setTitle({ title: "Click to start tracing" });
3740
},
41+
42+
/**
43+
*
44+
* Update the popup state depending on the recording state as well as whether
45+
* we are in a privileged page.
46+
* @param {number} tabId
47+
* @param {string | undefined} url
48+
*/
49+
updatePopupForTab(tabId, url) {
50+
if (!url) {
51+
// For some reason we don't know the url, return without doing anything.
52+
return;
53+
}
54+
55+
// Update the popup state depending on the recording state that we are in.
56+
switch (this.recordingState) {
57+
case "recording":
58+
case "starting":
59+
case "stopping":
60+
// Make sure that we don't have a popup set while recording.
61+
chrome.action.setPopup({
62+
tabId,
63+
// Empty string means no popup.
64+
popup: "",
65+
});
66+
break;
67+
case "idle": {
68+
// We want to update the popup now.
69+
// Empty string means no popup will be shown.
70+
const popup = isPrivilegedUrl(url) ? "src/disabled_popup.html" : "";
71+
chrome.action.setPopup({ tabId, popup });
72+
break;
73+
}
74+
default:
75+
assertExhaustiveCheck(this.recordingState);
76+
}
77+
},
3878
};
3979

4080
/**

src/tabs.js

Lines changed: 19 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -17,33 +17,32 @@ export async function getCurrentTab() {
1717
return tab;
1818
}
1919

20+
/**
21+
* Return whether the url is privileged or not.
22+
*
23+
* @param {string | undefined} url
24+
*/
25+
export function isPrivilegedUrl(url) {
26+
return (
27+
!url ||
28+
url.startsWith("chrome://") ||
29+
url.startsWith("about://") ||
30+
url.startsWith("https://chromewebstore.google.com/")
31+
);
32+
}
33+
2034
/**
2135
* Check if the tab is allowed to be attached and show a notification if not.
2236
* Chrome privileged pages are not allowed.
2337
*
2438
* @param {chrome.tabs.Tab} tab
2539
*/
2640
export function isTabAllowedToAttach(tab) {
27-
if (
28-
!tab.url?.startsWith("chrome://") &&
29-
!tab.url?.startsWith("chrome-extension://") &&
30-
!tab.url?.startsWith("https://chromewebstore.google.com/")
31-
) {
32-
// It's not a privileged page.
33-
return true;
41+
if (isPrivilegedUrl(tab.url)) {
42+
// We are not allowed in a privileged page, warn the user and return false.
43+
console.warn("Tab is not allowed to trace");
44+
return false;
3445
}
3546

36-
// We are not allowed in a privileged page, warn the user and return false.
37-
console.warn("Tab is not allowed to trace");
38-
const notificationId = "firefox-profiler-not-allowed" + Math.random();
39-
const options = {
40-
/** @type {chrome.notifications.TemplateType} */
41-
type: "basic",
42-
iconUrl: chrome.runtime.getURL("icons/off/icon128.png"),
43-
title: "Firefox Profiler Error",
44-
message: "Tracing a privileged page is not allowed.",
45-
};
46-
47-
chrome.notifications.create(notificationId, options, () => {});
48-
return false;
47+
return true;
4948
}

0 commit comments

Comments
 (0)