There are some key parts of the MDN content script documentation I am having trouble understanding regarding variable scope:
There is only one global scope per frame, per extension. This means that variables from one content script can directly be accessed by another content script, regardless of how the content script was loaded.
This paragraph may also be relevant (my italics) given the questions below:
... you can ask the browser to load a content script whenever the browser loads a page whose URL matches a given pattern.
I assume (testing all this has proved difficult, please bear with me) that this means:
The content script code will be run every time a new page is loaded that matches the URLs provided in manifest.json (in my case "matches": [<"all_urls">]
The content script code will run every time a page is refreshed/reloaded.
The content script code will not be run when a user switches between already open tabs (requires listening to window focus or tabs.onActivated events).
The variables initialized on one page via the content script share a global scope with those variables initialized by the same content script on another page.
Given the following code,
background-script.js:
let contentPort = null
async function connectToActiveTab () {
let tab = await browser.tabs.query({ active: true, currentWindow: true })
tab = tab[0]
const tabName = `tab-${tab.id}`
if (contentPort) {
contentPort.disconnect()
}
contentPort = await browser.tabs.connect(tab.id, { name: tabName })
}
// listening to onCreated probably not needed so long as content script reliably sends 'connecToActiveTab' message
browser.tabs.onCreated.addListener(connectToActiveTab)
browser.runtime.onMessage.addListener(connectToActiveTab)
content-script.js
let contentPort = null
function connectionHandler (port, info) {
if (contentPort && contentPort.name !== port.name) {
// if content port doesn't match port we have changed tabs/windows
contentPort.disconnect()
}
if (!contentPort) {
contentPort = port
contentPort.onMessage.addListener(messageHandler)
}
}
async function main () {
// should always be true when a new page opens since content script code is run on each new page, testing has shown inconsistent results
if (!contentPort) {
await browser.runtime.sendMessage({ type: 'connectToActiveTab' })
}
}
browser.runtime.onConnect.addListener(connectionHandler)
main()
And from assumptions 1 and 4, I also assume:
The existing contentPort (if defined) will fire a disconnect event (which I could handle in the background script) and be replaced by a new connection to the currently active tab each time a new tab is opened.
The behaviour I have seen in Firefox while testing has so far been a bit erratic and I think I may be doing some things wrong. So now, here are the specific questions:
Are all of my 5 assumptions true? If not, which ones are not?
Is firing the disconnect() event unnecessary, since I should rely on Firefox to properly clean up and close existing connections without manually firing a disconnect event once the original contentPort variable is overwritten? (the code here would suggest otherwise)
Are the connect() methods synchronous, thus negating the need for await and asynchronous functions given the example code?
The tabs.connect() examples don't use await but neither the MDN runtime or connect docs explicitly say whether the methods are synchronous or not.
Thanks for taking the time to go through these deep dive questions regarding content script behaviour, my hope is that clear and concise answers to these could perhaps be added to the SO extension FAQ pages/knowledge base.
At the present I'm pasting a Javascript into the console of FF and I'm calling the functions from the console:
function fill (i){
if(i==1){
SINGLE_START();
}
else if(i==2){
DUAL_START();
}
else if(i==3){
INTEGRATED_START();
}
else{
alert("=======================\n Tool Filler\n=======================\n\n1 or 2");
}
}
It is used to scrape the content of the website and e.g. create a file or generate an email from certain parts of the website, e.g.:
function SINGLE_START(){
//Focus:
let d = $(document).activeElement.contentDocument.activeElement.contentDocument.activeElement.contentDocument;
etc.
I thougt, there could be a way to use it through an extension and so I installed Tampermonkey and saved the script as userscript within the extension. But than I have a problem that I'm not able to call the desired function from the script as I need it, not just start the script as the website loads.
Does anyone has an idea how to call the functions one by one from within Tampermonkey (or Greasemonkey), or any other extension?
Thanks in advance!
This is because Tampermonkey scripts run in isolated context. There are two kinds:
1. No special privilegies
If you're not using any special GM functions that are unlocked by #grant GM_doThisAndThat and instead you use #grant none, then what internally happens is something like this:
function TheScript() {
// Here is your script that you added to tampermonkey
}
TheScript();
This if you have a function there, it is only available in the script. You need to explicitly expose it to window context:
function fill (i){
... code here ...
}
window.myFill = fill;
Then in console you write myFill(42) and it will execute.
I would recommend that you avoid assigning fill to window since it's a name that could likely conflict with something, but that's up to you.
2. Special privilegies
If you're using some of the GM features, you need to add #grant unsafeWindow and then assign to unsafeWindow variable. Be careful what you expose like this, you don't want to allow the website to access any of the GM_function features as they could access your private data on other websites and your computer!
My question is in response to this article
https://developer.mozilla.org/En/How_to_check_the_security_state_of_an_XMLHTTPRequest_over_SSL
I have downloaded and configured the xulrunner the only problem I'm getting to run javascript given in the link to display it output. Using xulrunner i want to know how can i produce an output as a headerless command-line program not gui.
var httpRequest = Components.classes["#mozilla.org/xmlextr/xmlhttprequest;1"].createInstance();
// Disable alert popups on SSL error
httpRequest.mozBackgroundRequest = true;
httpRequest.open("GET", "https://developer.mozilla.org/", true);
httpRequest.onreadystatechange = function (aEvt) {
if (httpRequest.readyState == 4) {
// Print security state of request
dumpSecurityInfo(httpRequest.channel);
}
};
httpRequest.send(null);
In the above code taken from the same link i want to see the output of function on my command screen or even a writing the information to file would do.
Do i have to change something in *.xul file extension.? I'm new to using xulrunner some help would be very helpful for me.
To print something to the console you use the dump() function. If your code runs in the context of a window you will need to change browser.dom.window.dump.enabled preference to true. XPCOM components can simply call dump() without changing this preference.
I've seen this question asked of other platform/languages - any ideas? I'd like to do something like:
if (detectDebug())
{
require('tty').setRawMode(true);
var stdin = process.openStdin();
stdin.on('keypress', function (chunk, key) {
DoWork();
}
}
else
{
DoWork();
}
I'd like to be able to toggle keyboard input as a start for the script when debugging so that I can have a moment to fire up chrome to listen to my node-inspector port.
***Quick update - I'm guessing I can actually use "process.argv" to detect if --debug was passed in. Is this the best/right way?
NodeJS creates a v8debug global object when running in debug mode: node debug script.js
So, a possible solution would be:
var debug = typeof v8debug === 'object';
For my use case, I use it because I want to avoid passing environment variables. My main node process starts child node processes and I want a node debug mainScript.js to trigger debug mode for children as well (again, without passing env variables to child processes)
I use this
var debug = typeof v8debug === 'object'
|| /--debug|--inspect/.test(process.execArgv.join(' '));
which supports, --debug, --debug-brk, --inspect and --inspect=1234
There is a node.js native support that using inspector.url() to check if there is active inspector, it just shows if process is debug mode or not currently. See doc for more.
The global v8debug variable mentioned in the other answers seem to be removed in Node v7.0.0 (see https://github.com/nodejs/node/issues/9617). Also, checking process arguments (i.e. process.execArgv) seem to be unreliable since Node can enter debug mode at runtime. VS Code, for example, doesn't always starts Node with the --inspect option even when debugging. (depend on your debug config)
The most reliable solution I could find is to use inspector.url() to check if Node is listening for debug connections.
const inspector = require('inspector');
function isInDebugMode() {
return inspector.url() !== undefined;
}
I have tested this method with Node versions v12.22.1, v14.16.1, and v16.1.0 and it worked for all of them.
I think there's a bunch of confusion in this question.
Based on your question, I think what you really want is the node --debug-brk command line flag. That will have node start v8 with a debugger running and automatically stop on a breakpoint before the first line of your .js program. You don't need to reinvent this. I use this for debugging mocha tests, express.js startup issues, etc. This will eliminate your need to detect this manually.
Secondly, NODE_ENV=production is nothing more than a convention that many programs use to indicate "you are running in production" and therefore certain things like really sending emails, using the real payment gateway, etc should be enabled. However what environment you are in when NODE_ENV is NOT production (or is unset) should definitely NOT be assumed to be debugging. The most sane assumption there is that the environment is a development environment, but even then this whole convention is pretty brittle in my opinion.
Thirdly, just FYI check out tty.isatty() which will accurately tell you if your program is being run on an interactive terminal (like from a command shell). This will be false when your program is being run by a process supervisor provided by your OS (upstart, sysvinit, etc). This check is commonly use to toggle command line programs between interactive and scripted modes. It's not entirely perfect or infallible, but it is widely adopted in the posix world.
Fourth, from some quick experimentation, the v8debug global #Gabriel Petrovay indicates seems to only be set when doing node debug script.js and not set when doing node --debug script.js. Not sure why that is. If such a thing was reliable, that would seem like the most correct approach to finding out "is this v8 instance in debug mode".
var detectDebug = function() {
return process.env.NODE_ENV !== 'production';
};
to run in debug mode:
$ node app.js
to run in production mode:
$ NODE_ENV=production node app.js
Some frameworks recognize the production mode this way. See express.js doc.
The global.v8debug object only seems to be created / exposed when the debug or --debug-brk command line option is set. It's strange and annoying it's not created when --debug is set.
A hacky way to do this would be to look at the process.execArgv array (not process.argv) for --debug, --debug-brk or debug.
process.debugPort appears to always be present and defaults to 5858. The only way to detect if the program was started explicitly with --debug is to check the process.execArgv array. --debug-brk is pretty obvious to detect: your program won't do anything and you'll get a message about a debugger listening, so that's trivial to figure out. v8debug appears to be present when the program is started with node debug file.js or when a debugger like node-inspector is currently attached.
Keeping all that in mind, this code will detect whether a debugger (of any kind) is currently attached.
var debug, withDebug;
debug = false;
if (typeof v8debug !== "undefined" && v8debug !== null) {
console.log("v8 debug detected");
debug = true;
}
withDebug = process.execArgv.indexOf('--debug') > -1 || process.execArgv.indexOf('--debug-brk') > -1;
if (withDebug) {
console.log("started with debug flag, port: " + process.debugPort);
debug = true;
}
if ((typeof v8debug === "undefined" || v8debug === null) && !withDebug) {
console.log("neither detected");
}
There is no v8debug in versions of nodejs >=7.
It seems that the most simple way is to check command line parameters. In debug mode there will be a word 'debug' or 'inspect'
const argv = process.execArgv.join();
const isDebug = argv.includes('inspect') || argv.includes('debug');
There simple solution is here.
But in general, detect debug mode is not easy - https://github.com/nodejs/node/issues/9617
Object.defineProperty(global, 'isDebugging', {
get: function () {
return typeof v8debug !== 'undefined';
}
});
This works well for webstorm
I had the same issue, how to check the app to see if it is running on --inspect.
I m on nodejs 14, and the solution with the v8debug that mentioned above, looks that it does not work any more, for clarity i post the message that i get when i try --debug.
node: [DEP0062]: node --debugandnode --debug-brkare invalid. Please usenode --inspectandnode --inspect-brk instead.
Solution
So how i tackle with this, is to query the process.execArgv which is exactly what you need too.
snipet:
const isInspect = process.execArgv.join() === '--inspect'
//or ....process.execArgv.toString() === ...
This execArgv, as the docs state:
The process.execArgv property returns the set of Node.js-specific command-line options passed when the Node.js process was launched. These options do not appear in the array returned by the process.argv property, and do not include the Node.js executable, the name of the script, or any options following the script name. These options are useful in order to spawn child processes with the same execution environment as the parent.
More in the docs: https://nodejs.org/docs/latest-v6.x/api/process.html#process_process_execargv
import flash.desktop.NativeProcess;
import flash.desktop.NativeProcessStartupInfo;
if (NativeProcess.isSupported) {
var npsi:NativeProcessStartupInfo = new NativeProcessStartupInfo();
var processpath:File = File.applicationDirectory.resolvePath("MyApplication.whatever");
var process:NativeProcess = new NativeProcess();
npsi.executable = processpath;
process.start(npsi);
}
The above can only run a sub-application, but how to run an independent application(command) like ipconfig and get the result?
You in fact can scrape STDOUT and STDERR:
process.addEventListener(ProgressEvent.STANDARD_OUTPUT_DATA, onOutputData);
process.addEventListener(ProgressEvent.STANDARD_ERROR_DATA, onError);
process.addEventListener(ProgressEvent.STANDARD_INPUT_PROGRESS, inputProgressListener);
public function onError(event:ProgressEvent):void
{
trace(event);
trace(process.standardError.readUTFBytes(process.standardError.bytesAvailable));
}
public function inputProgressListener(event:ProgressEvent):void
{
process.closeInput();
}
public function onOutputData(event:ProgressEvent):void
{
trace(event);
trace(process.standardOutput.readUTFBytes(process.standardOutput.bytesAvailable));
}
More info at: http://help.adobe.com/en_US/as3/dev/WSb2ba3b1aad8a27b060d22f991220f00ad8a-8000.html
And: http://www.as3offcuts.com/2010/08/air-2-native-process-example-mouse-screen-position/
Edit: realised maybe your question is also how to launch an external application? Here's an example how to run 'top' in OSX:
npsi.executable = new File("/usr/bin/top");
If you need network configuration information, you could use NetworkInfo.networkInfo.findInterfaces(). Will save you the trouble of interacting with another process and it's also portable.
http://help.adobe.com/en_US/air/reference/html/flash/net/NetworkInfo.html
If you want to run ipconfig.exe without knowing where it is located, you can run cmd.exe with arguments "/C" "ipconfig.exe ...". Of course, this requires to know where is cmd.exe. I had just included it with my AIR app (windows version).
I don't think you can, it's a self-impossed limitation of the NativeProcess API. However, you can create a little Windows binary yourself that calls ipconfig and passes the information back to the AIR app.
If creating that binary seems like a big deal, take a look to Haxe and xCross, you can get it done with a fairly similar language to ActionScript.