Capture screen -- chrome.desktopCapture.chooseDesktopMedia fails -- PNacl extension - javascript

I'm trying to use the desktopCapture API in the following manner.
chrome.desktopCapture.chooseDesktopMedia(
["screen", "window"], onAccessApproved);
chrome.desktopCapture shows as undefined when I set a breakpoint and inspect it. Permissions in my manifest file are as follows:-
"permissions": ["desktopCapture", "notifications" ]
Common causes for failure of this API are listed here as
a permission is missing in the application's manifest.json file
the API is defined on a newer version of Chrome then the current runtime
docs inherited from ChromeApi
And I don't have those problems.
My Chrome version is 43.0.2357.124 m
Pepper version is 43
FYI, I am trying to develop a Chrome extension to capture the screen using PNacl, and have borrowed from the media_stream_video example downloaded from here. But I haven't even gotten to sending a message to the pexe side yet. I'm still stuck at chrome.desktopCapture.chooseDesktopMedia returning undefined.

You need to call chrome.desktopCapture.chooseDesktopMedia from the background script running in the context of the extension. This Sample shows a simple method to use the extension to get screen media.
Keep in mind that this is callback based, so you get access to the stream id from the callback.
This runs in the context of your page (see full example here):
// check that the extension is installed
if (sessionStorage.getScreenMediaJSExtensionId) {
// send a message to your extension requesting media
chrome.runtime.sendMessage(sessionStorage.getScreenMediaJSExtensionId,
{type:'getScreen', id: 1}, null,
function (data) {
if (data.sourceId === '') { // user canceled
// handle error
} else {
constraints.video.mandatory.chromeMediaSourceId = data.sourceId;
getUserMedia(constraints, callback);
}
}
);
}
And this run in the context of your extension (see full example here):
chrome.runtime.onMessageExternal.addListener(function (message, sender, callback) {
switch(message.type) {
case 'getScreen':
var pending = chrome.desktopCapture.chooseDesktopMedia(message.options || ['screen', 'window'],
sender.tab, function (streamid) {
// communicate this string to the app so it can call getUserMedia with it
message.type = 'gotScreen';
message.sourceId = streamid;
callback(message);
return false;
});
return true; // retain callback for chooseDesktopMedia result
}
});

Related

Google Tag Manager - injectScript API never runs callbacks

I'm using the injectScript API in Google Tag Manager in a tag template, but I just cannot get it to fire any callback functions for when the external script loads (or fails to load). Any ideas please?
My template is thus, with an inject script permission defined for: https://www.google-analytics.com/analytics.js
Code:
// load APIs
const logToConsole = require('logToConsole');
const injectScript = require('injectScript');
const queryPermission = require('queryPermission');
// script url
const url = 'https://www.google-analytics.com/analytics.js';
// Callback to note if script load succeeded
const onSuccess = () => {
logToConsole('Script LOADED');
data.gtmOnSuccess();
};
// Callback to note if script load failed
const onFail = () => {
logToConsole('Script load FAILED.');
data.gtmOnFailure();
};
// Check permission and load script
logToConsole('Checking permission to load script:' + url);
if (queryPermission('inject_script', url)) {
logToConsole('Permission check: OK');
injectScript(url, onSuccess, onFail, url);
} else {
logToConsole('Permission check: FAIL');
data.gtmOnFailure();
}
The log in GTM shows this. Nothing logged from the callback functions for success/fail.
Template preview refreshed at 25/06/2020, 13:15:45
Test started
Checking permission to load script:https://www.google-analytics.com/analytics.js
Permission check: OK
Executed 1 test (SUCCESS)
Any ideas why the callbacks are not happening? I do see analytics.js loading in my chrome console network tab.
I've tried a bunch of variations and sample code of similar examples, and they don't work. I'm running Chrome (Version 83.0.4103.116 (Official Build) (64-bit)). I have Ghostery plugin but its disabled. I also repeated the test in Microsoft Edge and got the same result.
Thanks!
The callback functions supplied to injectScript DO run, but the logToConsole does not produce logging output when executed within those functions.
So if you are relying on seeing logging to know if your functions are being called successfully and what they are doing, you will not know whats going on.
The workaround I used was that instead of logging to console within those functions I would use sendPixel to call a fake URL with my logged message as a GET parameter. E.g. www.testabcd12345.com/index.html?msg=my-logged-message
Then I could observe those within my Chrome console Network tab. This is horrible but it worked enough.
Also gtmOnSuccess seemed to have similar limitations.

ng-webworker - IE 11 errors

So I'm using a library called ng-webworker and attempting to run a very simple long running task.
$scope.onParallelDownload = function() {
function doubler(num) {
return num * 2;
}
var myWorker = webWorker.create(doubler);
myWorker.run(3).then(function(result) {
alert("Answer: " + result);
}, function(error) {
var err = error;
});
}
This works perfectly in Chrome and shows the alert, but when run in Internet Explorer 11, where I am debugging it the error function is hit, which was still promising, however, there is no data given in the error payload which is problematic because I've absolutely no idea what is causing the web worker to fail on that particular browser.
Most likely you did not set the path to the file worker_wrapper.min.js (or worker_wrapper.js). This file is required for IE (see below). Adjust your app config to the following:
angular.module('myApp', [
// your dependencies
'ngWebworker'
])
.config(['WebworkerProvider', function (WebworkerProvider) {
WebworkerProvider.setHelperPath("./bower_components/ng-webworker/src/worker_wrapper.min.js"); // adjust path
}]);
This code assumes you installed ngWebworker with bower. You might still have to adjust the path, depending on the path you are in.
If you've already set the helper path but it still does not work, check if helper file is being loaded in the developer tools (you might have set a wrong path and get a 404).
Details
When passing a function to Webworker, it transforms this function into a blob which is then executed by the web worker as if it were an independent file. However, Internet Explorer treats these blobs as cross-domain, so this does not work. The workaround that ngWebworker uses is to run an independent JavaScript file (the worker_wrapper.min.js we set above). The web worker then runs that file and ngWebworker passes your stringified function to the worker where it is evaluated.
Note that if you're not on IE, this file will not be used.

How to check if a certain extension is installed in browser using webpage? [duplicate]

I am in the process of building a Chrome extension, and for the whole thing to work the way I would like it to, I need an external JavaScript script to be able to detect if a user has my extension installed.
For example: A user installs my plugin, then goes to a website with my script on it. The website detects that my extension is installed and updates the page accordingly.
Is this possible?
Chrome now has the ability to send messages from the website to the extension.
So in the extension background.js (content.js will not work) add something like:
chrome.runtime.onMessageExternal.addListener(
function(request, sender, sendResponse) {
if (request) {
if (request.message) {
if (request.message == "version") {
sendResponse({version: 1.0});
}
}
}
return true;
});
This will then let you make a call from the website:
var hasExtension = false;
chrome.runtime.sendMessage(extensionId, { message: "version" },
function (reply) {
if (reply) {
if (reply.version) {
if (reply.version >= requiredVersion) {
hasExtension = true;
}
}
}
else {
hasExtension = false;
}
});
You can then check the hasExtension variable. The only drawback is the call is asynchronous, so you have to work around that somehow.
Edit:
As mentioned below, you'll need to add an entry to the manifest.json listing the domains that can message your addon. Eg:
"externally_connectable": {
"matches": ["*://localhost/*", "*://your.domain.com/*"]
},
2021 Update:
chrome.runtime.sendMessage will throw the following exception in console if the extension isn't installed or it's disabled.
Unchecked runtime.lastError: Could not establish connection. Receiving end does not exist
To fix this, add this validation inside the sendMessage callback
if (chrome.runtime.lastError) {
// handle error
}
I am sure there is a direct way (calling functions on your extension directly, or by using the JS classes for extensions), but an indirect method (until something better comes along):
Have your Chrome extension look for a specific DIV or other element on your page, with a very specific ID.
For example:
<div id="ExtensionCheck_JamesEggersAwesomeExtension"></div>
Do a getElementById and set the innerHTML to the version number of your extension or something. You can then read the contents of that client-side.
Again though, you should use a direct method if there is one available.
EDIT: Direct method found!!
Use the connection methods found here: https://developer.chrome.com/extensions/extension#global-events
Untested, but you should be able to do...
var myPort=chrome.extension.connect('yourextensionid_qwerqweroijwefoijwef', some_object_to_send_on_connect);
Another method is to expose a web-accessible resource, though this will allow any website to test if your extension is installed.
Suppose your extension's ID is aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa, and you add a file (say, a transparent pixel image) as test.png in your extension's files.
Then, you expose this file to the web pages with web_accessible_resources manifest key:
"web_accessible_resources": [
"test.png"
],
In your web page, you can try to load this file by its full URL (in an <img> tag, via XHR, or in any other way):
chrome-extension://aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/test.png
If the file loads, then the extension is installed. If there's an error while loading this file, then the extension is not installed.
// Code from https://groups.google.com/a/chromium.org/d/msg/chromium-extensions/8ArcsWMBaM4/2GKwVOZm1qMJ
function detectExtension(extensionId, callback) {
var img;
img = new Image();
img.src = "chrome-extension://" + extensionId + "/test.png";
img.onload = function() {
callback(true);
};
img.onerror = function() {
callback(false);
};
}
Of note: if there is an error while loading this file, said network stack error will appear in the console with no possibility to silence it. When Chromecast used this method, it caused quite a bit of controversy because of this; with the eventual very ugly solution of simply blacklisting very specific errors from Dev Tools altogether by the Chrome team.
Important note: this method will not work in Firefox WebExtensions. Web-accessible resources inherently expose the extension to fingerprinting, since the URL is predictable by knowing the ID. Firefox decided to close that hole by assigning an instance-specific random URL to web accessible resources:
The files will then be available using a URL like:
moz-extension://<random-UUID>/<path/to/resource>
This UUID is randomly generated for every browser instance and is not your extension's ID. This prevents websites from fingerprinting the extensions a user has installed.
However, while the extension can use runtime.getURL() to obtain this address, you can't hard-code it in your website.
I thought I would share my research on this.
I needed to be able to detect if a specific extension was installed for some file:/// links to work.
I came across this article here
This explained a method of getting the manifest.json of an extension.
I adjusted the code a bit and came up with:
function Ext_Detect_NotInstalled(ExtName, ExtID) {
console.log(ExtName + ' Not Installed');
if (divAnnounce.innerHTML != '')
divAnnounce.innerHTML = divAnnounce.innerHTML + "<BR>"
divAnnounce.innerHTML = divAnnounce.innerHTML + 'Page needs ' + ExtName + ' Extension -- to intall the LocalLinks extension click here';
}
function Ext_Detect_Installed(ExtName, ExtID) {
console.log(ExtName + ' Installed');
}
var Ext_Detect = function (ExtName, ExtID) {
var s = document.createElement('script');
s.onload = function () { Ext_Detect_Installed(ExtName, ExtID); };
s.onerror = function () { Ext_Detect_NotInstalled(ExtName, ExtID); };
s.src = 'chrome-extension://' + ExtID + '/manifest.json';
document.body.appendChild(s);
}
var is_chrome = navigator.userAgent.toLowerCase().indexOf('chrome') > -1;
if (is_chrome == true) {
window.onload = function () { Ext_Detect('LocalLinks', 'jllpkdkcdjndhggodimiphkghogcpida'); };
}
With this you should be able to use Ext_Detect(ExtensionName,ExtensionID) to detect the installation of any number of extensions.
Another possible solution if you own the website is to use inline installation.
if (chrome.app.isInstalled) {
// extension is installed.
}
I know this an old question but this way was introduced in Chrome 15 and so I thought Id list it for anyone only now looking for an answer.
Here is an other modern approach:
const checkExtension = (id, src, callback) => {
let e = new Image()
e.src = 'chrome-extension://'+ id +'/'+ src
e.onload = () => callback(1), e.onerror = () => callback(0)
}
// "src" must be included to "web_accessible_resources" in manifest.json
checkExtension('gighmmpiobklfepjocnamgkkbiglidom', 'icons/icon24.png', (ok) => {
console.log('AdBlock: %s', ok ? 'installed' : 'not installed')
})
checkExtension('bhlhnicpbhignbdhedgjhgdocnmhomnp', 'images/checkmark-icon.png', (ok) => {
console.log('ColorZilla: %s', ok ? 'installed' : 'not installed')
})
I used the cookie method:
In my manifest.js file I included a content script that only runs on my site:
"content_scripts": [
{
"matches": [
"*://*.mysite.co/*"
],
"js": ["js/mysite.js"],
"run_at": "document_idle"
}
],
in my js/mysite.js I have one line:
document.cookie = "extension_downloaded=True";
and in my index.html page I look for that cookie.
if (document.cookie.indexOf('extension_downloaded') != -1){
document.getElementById('install-btn').style.display = 'none';
}
You could have the extension set a cookie and have your websites JavaScript check if that cookie is present and update accordingly. This and probably most other methods mentioned here could of course be cirvumvented by the user, unless you try and have the extension create custom cookies depending on timestamps etc, and have your application analyze them server side to see if it really is a user with the extension or someone pretending to have it by modifying his cookies.
There's another method shown at this Google Groups post. In short, you could try detecting whether the extension icon loads successfully. This may be helpful if the extension you're checking for isn't your own.
Webpage interacts with extension through background script.
manifest.json:
"background": {
"scripts": ["background.js"],
"persistent": true
},
"externally_connectable": {
"matches": ["*://(domain.ext)/*"]
},
background.js:
chrome.runtime.onMessageExternal.addListener(function(msg, sender, sendResponse) {
if ((msg.action == "id") && (msg.value == id))
{
sendResponse({id : id});
}
});
page.html:
<script>
var id = "some_ext_id";
chrome.runtime.sendMessage(id, {action: "id", value : id}, function(response) {
if(response && (response.id == id)) //extension installed
{
console.log(response);
}
else //extension not installed
{
console.log("Please consider installig extension");
}
});
</script>
Your extension could interact with the website (e.g. changing variables) and your website could detect this.
But there should be a better way to do this. I wonder how Google is doing it on their extension gallery (already installed applications are marked).
Edit:
The gallery use the chrome.management.get function. Example:
chrome.management.get("mblbciejcodpealifnhfjbdlkedplodp", function(a){console.log(a);});
But you can only access the method from pages with the right permissions.
A lot of the answers here so far are Chrome only or incur an HTTP overhead penalty. The solution that we are using is a little different:
1. Add a new object to the manifest content_scripts list like so:
{
"matches": ["https://www.yoursite.com/*"],
"js": [
"install_notifier.js"
],
"run_at": "document_idle"
}
This will allow the code in install_notifier.js to run on that site (if you didn't already have permissions there).
2. Send a message to every site in the manifest key above.
Add something like this to install_notifier.js (note that this is using a closure to keep the variables from being global, but that's not strictly necessary):
// Dispatch a message to every URL that's in the manifest to say that the extension is
// installed. This allows webpages to take action based on the presence of the
// extension and its version. This is only allowed for a small whitelist of
// domains defined in the manifest.
(function () {
let currentVersion = chrome.runtime.getManifest().version;
window.postMessage({
sender: "my-extension",
message_name: "version",
message: currentVersion
}, "*");
})();
Your message could say anything, but it's useful to send the version so you know what you're dealing with. Then...
3. On your website, listen for that message.
Add this to your website somewhere:
window.addEventListener("message", function (event) {
if (event.source == window &&
event.data.sender &&
event.data.sender === "my-extension" &&
event.data.message_name &&
event.data.message_name === "version") {
console.log("Got the message");
}
});
This works in Firefox and Chrome, and doesn't incur HTTP overhead or manipulate the page.
You could also use a cross-browser method what I have used.
Uses the concept of adding a div.
in your content script (whenever the script loads, it should do this)
if ((window.location.href).includes('*myurl/urlregex*')) {
$('html').addClass('ifextension');
}
in your website you assert something like,
if (!($('html').hasClass('ifextension')){}
And throw appropriate message.
If you have control over the Chrome extension, you can try what I did:
// Inside Chrome extension
var div = document.createElement('div');
div.setAttribute('id', 'myapp-extension-installed-div');
document.getElementsByTagName('body')[0].appendChild(div);
And then:
// On web page that needs to detect extension
if ($('#myapp-extension-installed-div').length) {
}
It feels a little hacky, but I couldn't get the other methods to work, and I worry about Chrome changing its API here. It's doubtful this method will stop working any time soon.
If you're trying to detect any extension from any website,
This post helped: https://ide.hey.network/post/5c3b6c7aa7af38479accc0c7
Basically, the solution would be to simply try to get a specific file (manifest.json or an image) from the extension by specifying its path. Here's what I used. Definitely working:
const imgExists = function(_f, _cb) {
const __i = new Image();
__i.onload = function() {
if (typeof _cb === 'function') {
_cb(true);
}
}
__i.onerror = function() {
if (typeof _cb === 'function') {
_cb(false);
}
}
__i.src = _f;
__i = null;
});
try {
imgExists("chrome-extension://${CHROME_XT_ID}/xt_content/assets/logo.png", function(_test) {
console.log(_test ? 'chrome extension installed !' : 'chrome extension not installed..');
ifrm.xt_chrome = _test;
// use that information
});
} catch (e) {
console.log('ERROR', e)
}
Here is how you can detect a specific Extension installed and show a warning message.
First you need to open the manifest file of the extension by going to chrome-extension://extension_id_here_hkdppipefbchgpohn/manifest.json and look for any file name within "web_accessible_resources" section.
<div class="chromewarning" style="display:none">
<script type="text/javascript">
$.get("chrome-extension://extension_id_here_hkdppipefbchgpohn/filename_found_in_ web_accessible_resources.png").done(function () {
$(".chromewarning").show();
}).fail(function () {
// alert("failed.");
});
</script>
<p>We have detected a browser extension that conflicts with learning modules in this course.</p>
</div>
Chrome Extension Manifest v3:
const isFirefox = chrome.runtime.OnInstalledReason.CHROME_UPDATE != "chrome_update";
For FireFox, I believe chrome.runtime.OnInstalledReason.BROWSER_UPDATE will be "browser_update": https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/API/runtime/OnInstalledReason

Open chrome://newtab from a Chrome extension

I try to write a Google Chrome extension that simply opens a new tab when I click left-right in a short interval. The JavaScript is no problem but I implemented this as a "content_scripts" script.
In some other threads I read that I can't access the chrome.* APIs from content_scripts (except the chrome.extension API).
Even if it's not necessary to access the chrome.tabs API to open a new window (window.open should do the job) it seems I need it though for opening a new tab with the new tab page which obviously isn't possible via window.open.
So I can't really figure out what is the best way to do that. I could use a background page which I could call from the content_script but I think there should be a much more simple way to do that, I just don't get it.
Anyone have an idea?
I think your content script will have to send a message to your background page to invoke chrome.tabs.create - content scripts cannot use the chrome api, nor can they directly communicate with the background page.
Here's a reference about message passing inside Chrome extensions for further detail, but here's the example code ( modified from the example in said reference )
// in background
chrome.extension.onMessage.addListener(
function(request, sender, sendResponse) {
switch ( request.action) {
case 'newTab' : {
//note: passing an empty object opens a new blank tab,
//but an object must be passed
chrome.tabs.create({/*options*/});
// run callback / send response
} break;
}
return true; //required if you want your callback to run, IIRC
});
// in content script:
chrome.extension.sendMessage({action: "newTab"}, function(response) {
//optional callback code here.
});
simple and easy
document.body.onclick = function openNewWindow( ) {
window.location.href = 'javascript:void window.open( "chrome://newtab" )';
}
manifest:
,"permissions":[
"http://*/*"
,"https://*/*"
]
,"manifest_version": 2
,"content_scripts":[{
"matches":[
"http://*/*"
,"https://*/*"
]
,"js":[
"js/openWindow.js"
]
}]
alright i miss understanding the question... modified

Can javascript access a filesystem? [duplicate]

This question already has answers here:
Local file access with JavaScript
(14 answers)
Closed 8 years ago.
I was pretty sure the answer was NO, and hence google gears, adobe AIR, etc.
If I was right, then how does http://tiddlywiki.com work? It is persistent and written in javascript. It is also just a single HTML file that has no external (serverside) dependencies. WTF? Where/how does it store its state?
Tiddlywiki has several methods of saving data, depending on which browser is used. As you could see in the source.
If ActiveX is enabled, it uses Scripting.FileSystemObject.
On Gecko-based browsers, it tries to use UniversalXPConnect.
If Java is enabled, it uses the TiddlySaver Java applet.
If Java LiveConnect is enabled, it tries to use Java's file classes.
HTML5's File[1], FileWriter[2], and FileSystem[3] APIs are available in the latest Developer channel of Google Chrome. The FileSystem API lets you read/write to a sandbox filesystem within a space the browser knows about. You cannot, for example, open 'My Pictures' folder on the user's local FS and read/write to that. That's something in the works, but it won't be ready for a while. Example of writing a file:
window.requestFileSystem(
TEMPORARY, // persistent vs. temporary storage
1024 * 1024, // 1MB. Size (bytes) of needed space
initFs, // success callback
opt_errorHandler // opt. error callback, denial of access
);
function initFs(fs) {
fs.root.getFile('logFile.txt', {create: true}, function(fileEntry) {
fileEntry.createWriter(function(writer) { // FileWriter
writer.onwrite = function(e) {
console.log('Write completed.');
};
writer.onerror = function(e) {
console.log('Write failed: ' + e.toString());
};
var bb = new BlobBuilder();
bb.append('Lorem ipsum');
writer.write(bb.getBlob('text/plain'));
}, errorHandler);
}
}
Check out this HTML5 Storage slide deck for more code snippets.
It uses a java file references like this:
drivers.tiddlySaver = {
name: "tiddlySaver",
deferredInit: function() {
if(!document.applets["TiddlySaver"] && !$.browser.mozilla && !$.browser.msie && document.location.toString().substr(0,5) == "file:") {
$(document.body).append("<applet style='position:absolute;left:-1px' name='TiddlySaver' code='TiddlySaver.class' archive='TiddlySaver.jar' width='1'height='1'></applet>");
}
},
isAvailable: function() {
return !!document.applets["TiddlySaver"];
},
loadFile: function(filePath) {
var r;
try {
if(document.applets["TiddlySaver"]) {
r = document.applets["TiddlySaver"].loadFile(javaUrlToFilename(filePath),"UTF-8");
return (r === undefined || r === null) ? null : String(r);
}
} catch(ex) {
}
return null;
},
saveFile: function(filePath,content) {
try {
if(document.applets["TiddlySaver"])
return document.applets["TiddlySaver"].saveFile(javaUrlToFilename(filePath),"UTF-8",content);
} catch(ex) {
}
return null;
}
}
Technically you can do
netscape.security.PrivilegeManager.enablePrivilege('UniversalBrowserWrite');
in a netscape-compatible browser (Firefox, Mozilla, Netscape), and it will ask the user* whether or not to allow filesystem access, but this is not portable.
*once per browser process
Can javascript access a filesystem?
Not outside of the sandbox area mentioned above, to the best of my knowledge. However, it can access a signed java applet that has callable public methods which can get to all files. I have done it and it works fine and is cross browser.
The signing part is somewhat involved and for professional use you might need to pay for a code signing certificate which authorises your identity. Get it from some place like Verisign. That way users at least know who the applet is written by (if that helps). You can sign it yourself for free but one of those "possible security risk" popups will occur at first use for authorisation by the user.
You would think that such signed applets for file writing would exist already for download but I couldn't find any via searching. If they did, you could just plug it in your page, learn the API and off you go.
The answer is indeed NO. Java applets, and the dreaded ActiveX plugins are usually used if this is required

Categories