Update chrome extension manifest permissions from options page - javascript

I am trying to update the permissions in the chrome extension manifest file from the options page.
Basically the user should be able to input the url for the extension to run on and that url will update in the extensions manifest file.
I am currently storing all my options using chrome.storage.sync for use in multiple files.
I am looking for a secure solution to give only the chosen url access. Any suggestions?

That's not possible (to update the manifest).
However, the particular use case you explain is:
Have a list of "allowed" websites.
When the extension is invoked by pressing the button, if the website is allowed - inject a content script that does something.
In this case "activeTab" permission and Programmatic Injection should solve your problem.
You do not declare any content scripts in the manifest. This ensures code runs only when you want to.
You do not declare any host permissions in the manifest. Your extension will ONLY work on the current tab at the moment of Browser Action press.
You ask the user for allowed URLs and store them in chrome.storage.
When your extension is invoked using the Browser Action, you can query the currently active tab and you will get its URL (because of the "activeTab" permission).
Your logic then compares it to stored whitelisted URLs.
If there's a match - you use chrome.tabs.executeScript to inject your content script.
If there's no match - do nothing, or somehow ask user to confirm whitelisting the new domain.
Here's some sample code:
chrome.tabs.query({active: true, currentWindow: true}, function(tabs) {
var currentTab = tabs[0];
// Pseudocode
if (whitelisted(currentTab.url)) {
chrome.tabs.executeScript(currentTab.id, {file: "content.js"});
} else {
// Do nothing or show some warning
}
});
Alternatively, you can look at Optional Permissions API.

Related

Unable to "captureVisibleTab" on a chrome-created tab, even though all permissions are set properly

I've been working on an extension that takes a screenshot of your active tab and allows you to annotate it.
In my background script, I'm able to successfully use "captureVisibleTab" and send a dataURI to my content script and render it in a new chrome tab.
But when I need to take a second screenshot within the newly created chrome tab, I send a message to the background script to take a screenshot, and then I'm getting this error:
Unchecked runtime.lastError while running tabs.executeScript: Cannot access contents of url "chrome-extension://pgcahhckfdfpkjbbnblmabcbobbnmfie/comment.html". Extension manifest must request permission to access this host.
I've done many, many searches on each part of this error, and all of them told me to do things (all of which I've tried) such as:
Add to my manifest.json
Add "activeTab" and "tabCapture" and "tabs" to my manifest permissions
Tried using chrome.tabCapture instead
But in all cases, it doesn't seem to like that I'm trying to capture a visible tab, even though the tab is a chrome extension tab (formatted like chrome-extension://pgcahhckfdfpkjbbnblmabcbobbnmfie/comment.html)
I've also tried adding that chrome-extension URL to my permissions and to web-accessible resources, but neither of those things work either.
Any help would be greatly appreciated, I've been debugging this for hours and I really don't know what else to try or what else I could be missing.

Determine if active tab contains an editable Google Doc

Suppose my extension has obtained the URL for the current active tab using the method suggested in How can I get the current tab URL for chrome extension?, e.g.
chrome.tabs.query({
active: true,
lastFocusedWindow: true
}, function (tabs) {
// use first tab to obtain url
var tab = tabs[0];
var url = tab.url
});
How can I determine if the URL refers to a Google Doc to which I have editing rights? The distinction between ownership and being an invited collaborator is not important for this application. I'm interested only in Docs as opposed to Spreadsheets or Forms.
For context on what I'm trying to develop, see: How to manually generate notifications to a Google Doc collaborator?
Alternate answer, based on the Google Drive API rather than the Google Docs UI.
Before doing any of this, make sure to declare permissions in the manifest (to only match URLs that look like docs.google.com/document/*).
Here is a broad overview of the steps you could follow:
GET a
file,
which will return some metadata. You can use the URL you have to extract the relevant ID which is used in the GET request.
Use this metadata file resource to retrieve a permissions resource
In the permissions resource, look at the role attribute: it will be either owner, reader, or writer. You will not have editing rights if you are a reader, but should have editing rights otherwise.
Here is a side by side view of a google doc, where I created a doc, generated a sharing link, and opened it in a browser where I was not signed in to google. I would suggest using a content script to insert a "find" function which would return either true or false if it can locate the "view only" button in the DOM ("view only" meaning you do not have edit permissions). You could make the content script match URLs that look like docs.google.com/document/* only.
Caution: google changes UI pretty frequently so this may not be future-proof. Try inspecting the source of google docs in both situations to look for more clues.
Side by side view:
Source code in the chrome devtools:

Chrome extension - Write to local storage of a different domain

How can I write to a local storage of a different domain. The idea is that I need my chrome extension to write something in the local storage and when the user visits the associated website, site site can read the contents of the local storage. I am trying to do a sync between the user's personal data without having to store them in the server.
Content scripts have direct acccess to a page's localStorage.
If you want to store a value for a specific domain, just open a window or frame, then write to the window/page's local storage.
Pick your favorite option to activate the page:
chrome.tabs.create to create an inactive tab, perhaps in the non-active window found by using chrome.tabs.query.
The experimental offscreenTabs API (experimental, so not ready for use in production). See some of the examples I posted on SO.
Create an IFrame and insert it in the current page.
window.open (not recommended...)
When you decide to open a page, pick one which is light-weight. /robots.txt is usually a good choice: It exists on most sites, and it is a plain text file.
Activate the content script for the page. You can either use the manifest file and make use of the messaging APIs, or add a callback to the chrome.tabs.create method which programatically inserts a content script (chrome.tabs.executeScript).
Here's a simple example. It requires the tabs API because I'm using chrome.tabs.executeScript. Furthermore, the origin you want to access should also be added to the permissions list.
chrome.tabs.create({
active: false,
url: 'http://stackoveflow.com/robots.txt'
}, function(tab) {
chrome.tabs.executeScript(tab.id, {
code: 'localStorage.setItem("key", "value");'
}, function() {
chrome.tabs.remove(tab.id);
});
});
Update (2022)
Since Manifest version 3 the chrome.tabs.executeScript API was replaced with the chrome.scripting.executeScript API, hence the code above can be changed to be like this:
function saveToLocalStorage() {
localStorage.setItem("key", "value");
}
chrome.tabs.create({
active: false,
url: 'http://stackoveflow.com/robots.txt'
}, function(tab) {
chrome.scripting.executeScript({
target: {tabId: tab.id},
func: saveToLocalStorage,
}, function() {
chrome.tabs.remove(tab.id);
});
});
And please note, you need to add the "scripting" permission to your manifest.json file in order to use this API.
I think the only solution to do this is via script injection due to cross domain restrictions.
var s = document.createElement('script');
s.src = chrome.extension.getURL("script.js");
s.onload = function() {
this.parentNode.removeChild(this);
};
(document.head||document.documentElement).appendChild(s);
Add a file script.js to your extension accessing the other sites localStorage, you have to add script.js to "web_accessible_resources" in your manifest file.
Note that the script is automatically removed after the script was completely loaded, so make sure that the code you want to execute is contained in a self executable function.

How to open email by x-gm-msgid in Gmail with Javascript

I'm writing an extension which surfaces links to gmail messages. As the UI loads right in Gmail, I should be able to click on one of these links and have Gmail load it (without refreshing). I have "x-gm-msgid" available and theoretically, I should just be able to navigate to "https://mail.google.com/mail/u/0/#inbox/[x-gm-msgid]".
I've tried using
location.hash = "#inbox/[x-gm-msgid]"
I've tried using
history.pushState(null, null, "/mail/u/0/#inbox/[x-gm-msgid]")
Neither of which works. Gmail just thwarts any attempt to change the URL (unless it is done via user interaction)
Any thoughts on how to get around this restriction?
chrome.tabs.update should work.
Modifies the properties of a tab. Properties that are not specified in updateProperties are not modified. Note: This function can be used without requesting the 'tabs' permission in the manifest.

How do I refresh/reload a Chrome Extension?

I'm developing an extension in Chrome 4 (currently 4.0.249.0) that will show the user's StackOverflow/SuperUser/ServerFault reputation in the status bar. I've designed an options page to get the user's profile IDs and I save them to localStorage and read them well in the extension. It all works great.
The problem is I cannot find a (programmatic) way to refresh the extension upon options saving. I tried calling location.reload(); from the extension page itself upon right clicking it - to no avail. I pursued it further and tried looking at what Chrome's chrome://extensions/ page does to reload an extension, and found this code:
/**
* Handles a 'reload' button getting clicked.
*/
function handleReloadExtension(node) {
// Tell the C++ ExtensionDOMHandler to reload the extension.
chrome.send('reload', [node.extensionId]);
}
Copying this code to my event handler did not help (and yes, I tried replacing [node.extensionId] with the actual code). Can someone please assist me in doing this the right way, or pointing me at a code of an extension that does this correctly? Once done, I'll put the extension and its source up on my blog.
Now the simplest way to make extension to reload itself is to call chrome.runtime.reload(). This feature doesn't need any permissions in manifest.
To reload another extension use chrome.management.setEnabled(). It requires "permissions": [ "management" ] in manifest.
window.location.reload() works for me
I am using chromium 6.x so it might be fixed in newer version
The chrome.send function is not accessible by your extension's javascript code, pages like the newtab page, history and the extensions page use it to communicate with the C++ controller code for those pages.
You can push updates of your extension to users who have it installed, this is described here. The user's application will be updated once the autoupdate interval is hit or when they restart the browser. You cannot however reload a user's extension programmatically. I think that would be a security risk.
I just had this same problem with an extension.
Turns out you can listen for storage changes within background.js using chrome.storage.onChanged and have that perform the refresh logic.
For example:
// Perform a reload any time the user clicks "Save"
chrome.storage.onChanged.addListener(function(changes, namespace) {
chrome.storage.sync.get({
profileId: 0
}, function(items) {
// Update status bar text here
});
});
You could also reload parts of your extension this way by taking the changes parameter into account. chrome.runtime.reload() might be easier, but this has less overhead.
For all future Googlers - the Browser Extension spec now includes runtime.reload() - https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/API/runtime/reload
For Chrome, you might need to use chrome.runtime.reload() (but I'd handle such cases via Mozilla's awesome webextension-polyfill).

Categories

Resources