This is my first time building a Google Chrome Extension, so I am still learning and possibly doing something silly. Thank you for any help in advance.
Some background context:
Google Cloud Console IAM Admin page (https://console.cloud.google.com/iam-admin/) lists principles based on their project number. For example, a principle may be listed as [email protected], where 123456789012 is a project id. Obviously, 123456789012 isn’t very human readable, so I wanted to build a chrome extension that would create tooltips over strings containing the project id where the tooltip text would be the project name.
I created a background.js
script. This script is used to toggle the chrome extension on / off.
let extensionEnabled = false; // Variable to track extension state
chrome.action.onClicked.addListener((tab) => {
extensionEnabled = !extensionEnabled; // Toggle extension state
// Save the state of extensionEnabled to storage
chrome.storage.local.set({ isEnabled: extensionEnabled });
// Update the extension icon to indicate the current state
const iconPath = extensionEnabled
? { '16': 'images/icon_enabled16.png', '48': 'images/icon_enabled48.png', '128': 'images/icon_enabled128.png' }
: { '16': 'images/icon16.png', '48': 'images/icon48.png', '128': 'images/icon128.png' };
chrome.action.setIcon({ path: iconPath });
});
I also created a contentScript.js
file that contains the script logic.
const wordMap = {
// At present I am just hard-coding the project id number and project name
"123456789012": "project-name",
};
let extensionEnabled = false;
// Load the state from storage
chrome.storage.local.get('isEnabled', (result) => {
extensionEnabled = result.isEnabled || false;
if (extensionEnabled) processPage();
});
function processPage() {
// Create a new style element
const style = document.createElement('style');
// Set the CSS for tooltips
style.textContent = `
...
`;
// Append the style element to the head of the document
document.head.appendChild(style);
// Find occurrences of keys in wordMap in the text nodes of the document and put them in the textNodes array
const textNodes = [];
findTextNodes(document.body, textNodes);
// This creates tooltips for all nodes in the textNodes array
createTooltips(textNodes);
}
I’ve tested the logic on a test HTML document and processPage()
works correctly on a simple static HTML document.
However, the extension wasn’t working properly when using it in Google cloud console. The textNodes
array was never being populated with any nodes. I suspect it’s because in the Google console IAM page, they are populated / hydrated by the page’s JS scripts.
Upon googling, I found some tips online that this is because the extension runs in an isolated environment. I tried changing the world
key in my Manifest to MAIN
. However this causes an error in the extension: Uncaught TypeError: Cannot read properties of undefined (reading 'local')
for the line chrome.storage.local.get('isEnabled', (result)
Here’s my manifest file:
{
"manifest_version": 3,
"name": "GCP Project ID Tooltip Chrome Extension",
"version": "0.1",
"description": "Chrome Extension that adds a tooltip with project names over project ID's in GCP console webpages.",
"action": {},
"permissions": [
"cookies",
"activeTab",
"storage",
"scripting"
],
"host_permissions": [
"https://console.cloud.google.com/*"
],
"optional_host_permissions":[
"https://*/*",
"http://*/*"
],
"background": {
"service_worker": "background.js",
"type": "module"
},
"content_scripts": [
{
"matches": [
"<all_urls>"
],
"js": [
"contentScript.js"
],
"all_frames": true,
"world": "MAIN"
}
],
"icons": {
"16": "images/icon16.png",
"48": "images/icon48.png",
"128": "images/icon128.png"
}
}
My few questions are:
- Do I need
"world": "MAIN"
set for my use case? or isISOLATED
good enough?- If I don’t, I think that would resolve my
Cannot read properties of undefined (reading 'local')
, but then I am left with thetextNodes
array not being populated?
- If I don’t, I think that would resolve my
- What permissions do I need for my use-case? I’m still unclear on the various permissions requirements for google chrome extensions.
- Do I need
host_permissions
oroptional_host_permissions
- What should I put for
content_scripts.matches
? I suspect it’shttps://console.cloud.google.com/
, but I want to confirm. - Am I doing anything stupid here? Maybe there is a better/simpler way to accomplish this?
Thank you again for any insight!