I am new to Firefox extension (add-on) development. I'm injecting a content script through my sidebar code-behind using the browser.tabs.executeScript() API. And I run my extension using web-ext run command.
The problem is, my log doesn't appear in developer console and when I go to tools console, I can see the following error:
Error: Missing host permission for the tab
Mozilla defines a host permission as given through pattern matching of page URL. And of course adding the following to my manifest.json file fixes the issue:
"content_scripts": [
{
"matches": ["<all_urls>"],
"js": ["content-script.js"]
}
]
But I'd like to inject the content script on demand, not based on the page URL.
Another way is to send messages through API to my sidebar code-behind and then log it there in my extension console. But this requires a bit of implementation. On the other hand, It makes me wondering why shouldn't I be able to simply log a message to developer console through an injected script?
This is my code:
manifest.json:
{
"manifest_version": 2,
"name":"My Extension",
"version":"1.0",
"sidebar_action":{
"default_title": "My sidebar",
"default_panel": "sidebar/panel.html"
},
"permissions":[]
}
panel.js:
browser.tabs.executeScript({ file: "content-script.js" });
content-script.js:
console.log('first line of content script');
I found it. The term <all_urls> can be used as a permission:
"permissions":["<all_urls>"]
Then console.log() works within content script.
However, it is not recommended to include this permission: Avoid host permission "<all_urls>" if you can
Related
As of January 17, Firefox now supports Manifest v3 in Firefox 109.0.
I have an add-on I am testing with Manifest v3 and it requires access to a variable on reddit.com.
I want to make the "Access your data for sites in the *://reddit.com domain" permission required, since the extension does not work without it.
What needs to be done to make it so it does not show as optional since I want the user to not have to explicitly turn on the permission from the Permissions tab?
I want it show as required similar to this image (source):
Here's a trimmed down version of an example Manifest file that shows the permission as optional.
{
"manifest_version": 3,
"name": "Example",
"description": "Example",
"version": "3.16.1",
"content_scripts": [
{
"run_at": "document_idle",
"matches": ["*://*.reddit.com/"],
"js": ["script.js"]
}
]
}
I have tried adding "permissions": ["https://*.reddit.com/*"], but it still shows as optional.
I also tried "permissions": ["*://reddit.com"] and "host_permissions": ["*://reddit.com"] but nothing is causing it to be required.
I have a Chrome extension which is working with the same manifest v3 file.
The only solution I have found is to set optional permissions.
https://developer.chrome.com/docs/extensions/reference/permissions/
I added the permission setting itself to the listener. Of course, I check beforehand that such permissions do not already exist.
browser.action.onClicked.addListener((tab: Tab) => {
browser.permissions.request({
origins: ['*://*.reddit.com/']
})
});
Is there a way to extend the supported languages/grammars in Visual Studio Code?
I'd like to add a custom language syntax, but I've not been able to find any information on how language services are provided.
Can anybody point to any references or even examples of existing language implementations?
It's possible with the new version 0.9.0. There's an official documentation on how to add a custom language: https://github.com/microsoft/vscode-docs/blob/main/release-notes/v0_9_0.md
You need a .tmLanguage file for the language you want to add. You can find existing files e.g. on GitHub or you can define your own language file. Look here to get an idea of how to create one: http://manual.macromates.com/en/language_grammars
After finding a .tmLanguage file you have two ways to create an extension based on it.
Option 1: Using a Yeoman generator
Install node.js (if you haven't already done)
Install yo (if you haven't already done) by executing npm install -g yo
Install the Yo generator for code: npm install -g generator-code
Run yo code and select New language support
Follow the instructions (define the .tmLangauge file, define the plugin name, file extensions etc.)
The generator creates a directory for your extension with the name of the plugin in your current working directory.
Option 2: Create the directory on your own
Create a directory with the name of your plugin (only lowercase letters). Let's say we call it mylang.
Add a subfolder syntaxes and place the .tmlanguage file inside of it
Create a file package.json inside the root of the extension folder with content like this
{
"name": "mylang",
"version": "0.0.1",
"engines": {
"vscode": ">=0.9.0-pre.1"
},
"publisher": "me",
"contributes": {
"languages": [{
"id": "mylang",
"aliases": ["MyLang", "mylang"],
"extensions": [".mylang",".myl"]
}],
"grammars": [{
"language": "mylang",
"scopeName": "source.mylang",
"path": "./syntaxes/mylang.tmLanguage"
}]
}
}
Finally add your extension to Visual Studio Code
Copy the extension folder to the extension directory. This is:
on Windows %USERPROFILE%\.vscode\extensions
on Mac/Linux $HOME/.vscode/extensions
Restart Code. Now your extension will run automatically everytime you open a file with the specified file extension. You can see the name of the used plugin in the down right corner. You can change it by clicking on the name of the extension. If your extension is not the only one registered for a specific file extension then Code may chooses the wrong one.
To extend Wosi's .tmLanguage answer, using a .tmLanguage file is optional. Using a regular .json is a perfectly valid and—in my opinion—better readable alternative.
For an example, see VSCode_SQF: sqf.json
Inside the package.json, you would only need to change the path from ./syntaxes/mylang.tmLanguage to ./syntaxes/mylang.json.
Using reverse engineering you can add a new language to VSCode. You can take a look on how typescript is implemented as a JavaScript plugin and how it communicates with node.exe via pipe. But it's a hard thing since it's coming all without documentation
I'll provide a really short documentation here:
You can define a new plugin in the plugins folder C:\Users\USER\AppData\Local\Code\app-0.3.0\resources\app\plugins.
Copy the typescript plugin folder and rename mentioned file extensions and language names in all files to your new language, so that your new plugin is going to be used when a .mylang file is opened.
In typescriptServiceClient.js you see that a child process is being forked and that its stdout is coupled to a new WireProtocol.Reader. Bind your own mylanguage.exe (you'll probably need to write that exe on your own). VSCode asks that binary to get more language specific information.
In typescriptMain.js you find the feature registration for the language. Delete every call to monaco.Modes.XXXXXXSupport.register except monaco.Modes.DeclarationSupport.register.
Now open a directory in VSCode that contains .mylang files and open one of them via CTRL+P + FileName. Right click on an identifier and select Go to Definition. VSCode sends now a request like this via StdIn to your exe
{"seq":1,"type":"request","command":"definition","arguments":{"file":"d:/Projects/MyProj/Source/MyFile.mylang","line":45,"offset":9}}
VSCode expects an answer like this:
Content-Length: 251
[LINE BREAK]
{ "seq" : 1, "type" : "response", "command" : "definition", "request_seq" : 1, "success" : true, "body" : [{ "file" : "d:/Projects/MyProj/Source/MyOtherFile.mylang", "start" : { "line" : 125, "offset" : 3 }, "end" : { "line" : 145, "offset" : 11} }] }
If everything works VSCode will open MyOtherFile.mylang and set the cursor to line 124 in column 3.
Try it on your own ;-)
Simplest recipe IMHO as of 2021 Q2:
Follow Option 2 in Wosi's answer. You only need two files to get started. Just create the folder structure directly in your extensions directory.
Set "path": "./syntaxes/your_language.plist" in package.json
Use IRO to build your regexes.
Make sure that in the "Scope Information" screen, anything to do with Textmate is green. Don't worry about the other editors.
Save the contents of the "Textmate" tab into the path above, i.e., .syntaxes/your_language.plist
Reload VSCode
That's it. I also save the IRO (left pane) text into my own project.
You can read the source code of the built-in language extensions online:
https://github.com/microsoft/vscode/tree/main/extensions
You can pick an extension that is close to your language's syntax and change it as you wish. (e.g. you can do some modifications to the JavaScript extension and rebrand it for use with jQuery!)
It is important to note that this would be too much work if you choose a language that is so different from your desired language! If you didn't manage to find a language that is similar to your desired language, you may want to create a whole new extension from the ground up - https://stackoverflow.com/a/32996211/14467698 -.
I am following this tutorial
https://hyperledger.github.io/composer/integrating/deploying-the-rest-server.html
I have done all the steps. But when I run rest-server through github, it prints following stack trace.
Error
404 Cannot GET /auth/github
status: 404
Error: Cannot GET /auth/github
at raiseUrlNotFoundError (/home/praval/.nvm/versions/node/v6.11.1/lib/node_modules/composer-rest-server/node_modules/loopback/server/middleware/url-not-found.js:21:17)
I presume you installed the Github strategy via npm install -g passport-github?
If so did it create a folder /auth/github?
You are required to go to this Folder per documentation: "Authenticate to the REST server by navigating to the value of the authPath property specified in the environment variable COMPOSER_PROVIDERS. In the example above, this is http://localhost:3000/auth/github"
In my case that folder was not created. I read on Github website: https://github.com/cfsghost/passport-github
"The author of Passport-Github has not maintained the original module for a long time. Features in his module don't work since Github upgraded their API to version 3.0. We forked it and re-published it to NPM with a new name passport-github2"
I'm looking for guidance on this.
Before create private api just execute this command in your terminal.
export COMPOSER_PROVIDERS='{
"github": {
"provider": "github",
"module": "passport-github",
"clientID": "<your id>",
"clientSecret": "<your secret>",
"authPath": "/auth/github",
"callbackURL": "/auth/github/callback",
"successRedirect": "http://localhost(domain of angular app):4200(port)/home(page to redirect)",
"failureRedirect": "http://localhost(domain of angular app):4200(port)/login-github(page to redirect)""
}
}'
To check if all is fine - run command
echo $COMPOSER_PROVIDERS
After this you will see your COMPOSER_PROVIDERS value.
And after in github profile app (https://github.com/settings/applications/) you must configure "Homepage URL" (ex. http://APIdomain:3000/) and "Authorization callback URL" (ex. http://APIdomain:3000/auth/github/callback)
I'm unable to upload my firefox extension using the form provided by mozilla. I'm constantly getting the error Your add-on failed validation with 2 errors.
No install.rdf or manifest.json foundAdd-on missing manifest, which is very misleading because my application has a manifest.json.
The manifest.json looks like this:
{
"manifest_version": 2,
"version": 1.0,
"name": "my-extension-name",
"description": "Lorem ipsum dolor sit amet",
"background": {
"scripts": ["js/background.js"]
},
"main": "popup.js",
"browser_action": {
"default_icon": "img/icon_grey.png",
"default_popup": "popup.html",
"default_title": "loremipsum"
},
"engines": {
"firefox": ">=38.0a1"
},
"permissions": [
"activeTab",
"tabs",
"background",
"http://*/*",
"https://*/*",
"notifications",
"alarms",
"storage",
"webRequest",
"webRequestBlocking",
"clipboardRead"
]
}
What is missing for this to work?
I was running into the same problem but all of these instructions didn't solve it.
What i always did was to pack the whole folder, hence the manifest.json was not on the first level, when unpacked.
SOLUTION FOR ME
Select all files, instead of the folder, and then pack them as one .zip file and it should work. At least it did for me.
Here is a link to the MDN Documentation.
The very simple answer to this is that its unable to find the manifest in your zip file. This is caused because when you take a file and zip it using the default compressor in windows it takes the file and throws it into a sub folder of the zip file you created...
before compressing
folderYouWantCompressed
-FileInFolder.html
-Manifest.json
after compressing it will look like this
nameOfZip.zip
-folderYouWantCompressed
-FileInFolder.html
-Manifest.json
but what you want is
nameOfZip.zip
-FileInFolder.html
-Manifest.json
the reason Oliver Sauter answer works is because when you select all the files within the "folderYouWantCompressed" it compresses without the sub folder meaning you dont run into this problem and it has no problem finding the manifest file.
for what I can tell the "correct answer" seems to be signing the add-on itself and is able to get the manifest file properly, so it does work but just seems like a 3rd party way of doing it (I did not look into it too deeply)
Note: that I originally had my issue solved by looking at Oliver Sauter post I just wanted to make it clear for future people looking at this post.
When you open your addon package zip file, the manifest.json file should be visible to you in order to upload it on AMO.
In your case, it looks like when you open your package zip, there is a folder and inside that folder manifest.json is located.
As I have found a solution to my problem and would like to share it for future reference I answer my own question:
The issue at hand was that I did not use the web-ext command line tool to create the .zip / .xpi package. I was able to solve the problem by installing web-ext and using web-ext build to build the extension. The result of this operation is a .xpi file that contains the project which I was then able to upload to the AMO service. Note that the manifest.json in the newly created package is identical to the manifest.json I originally provided. However, in addition to the manifest.json a directory META-INF was created which contains a mozilla.mf, mozilla.rsa and mozilla.sf file.
This however, did not entirely solve my problem. After uploading the extension to AMO, it could not be installed and was said to be damaged. Apparently, which is what I read somewhere in the interwebz (and forgot the source), Mozilla opens the .zip / .xpi package that is uploaded to test it and since my package was not signed, Mozilla could not ensure its integrity and marked it as insecure (i.e. damaged).
In order to solve the second problem I had to sign the extension. This can be done using the following command:
web-ext sign --api-secret YOUR_API_SECTER --api-key YOUR_API_KEY
After this, I was able to upload and install the extension.
Got the same problem, the problem was thats the file name is case sensitive:
Manifest.jason -> error, no manifest found
manifest.json -> susscessful
my solution (in mac os):
zip a directory using zip in terminal command zip -r example.zip example instead of right-clicking files and clicking "Compress" in mac os
I've made a local file (log.html) in Firefox profile and tried to open it in an add-on page (add-on folder/data/log.html and it's shown as Resource protocol in URL bar).
self.port && self.port.on('add-log-path', function(payLoad) {
addLogPath(payLoad);
});
function addLogPath(url) {
// url == "file:///Users/usr/Library/Application Support/Firefox/Profiles/05rhodfg.cfxo/log.html"
$('#logpath').attr('href', url);
}
I've also tried changing that to JS method window.open
function addLogPath(url) {
$('#logpath').on("click", function() {
window.open(url);
});
}
But the error is
JavaScript error: , line 0: Error: Access to
'file:///Users/usr/Library/Application%20Support/Firefox/Profiles/05rhodfg.cfxo/log.html'
from script denied
BTW, before Firefox version 41, it has no problem doing this.
Can you suggest other workaround to solve this? Thank you!
edit:
added add-on example to reproduce the problem
download and run the following statement in Terminal:
$ cd fileProtocolExample && cfx run
Do self.data.url('filename_here') to get that path to your file.
It will look something like resource://your-extension-id/data/filename_here, then this should load fine. That resource:// in front is important, make sure you get and use that URL.
The file:// won't work, because your addon is packed in a zip. Its not extracted into the system. How did it work in Firefox 41? Was your addon unpacked at that time? This is an Addon-SDK addon right?