How to prevent chrome extension from executing on chrome-urls - google-chrome-extension

My plugin is working great. I just get an error in the plugin error log if it runs on Chrome Urls like chrome://extensions/
//
// Inject the payload.js script into the current tab after the popout has loaded
//
window.addEventListener('load', function (evt) {
chrome.extension.getBackgroundPage().chrome.tabs.executeScript(null, {
file: 'payload.js'
});
});
Generates "Unchecked runtime.lastError while running tabs.executeScript: Cannot access a chrome:// URL
Context
_generated_background_page.html"
I tried having it only run if windows.location.hostname does not equal extensions, which makes it not run when it is on the page but I still get the error message.
I read here that it can be ignored and that there is a missing check but no example of said check. https://groups.google.com/a/chromium.org/d/msg/chromium-extensions/qC1o39YkN28/WEOAFv6xNWYJ

I'm not aware on scenario when you need to inject script on background page through this way. Anyway you could add a callback and handle the error
window.addEventListener('load', function (evt) {
chrome.extension.getBackgroundPage().chrome.tabs.executeScript(null, {
file: 'payload.js'
}, ()=>{
if(chrome.runtime.lastError) {
//handle error here
}
});});

Related

Redirect from React to an Express route from my API server on the same domain

I have both a React APP and a Express API server on the same server/domain. Nginx is serving the React APP and proxying the express server to /api.
Nginx configuration
https://gist.github.com/dvriv/f4cff6e07fe6f0f241a9f57febd922bb
(Right now I am using the IP directly instead of a domain)
From the React APP, when the user does something I want him to download a file. I used a express route on my API server that serve the file. This works fine when the user put the URL.
This is my express route:
donwloadFile.route('/')
.get((req, res) => {
const file = '/tmp/PASOP180901.txt';
res.download(file);
});
This is my react redirect:
if (this.state.downloadFile === true) {
this.setState({ downloadFile: false });
setTimeout(() => {
window.location.href = '/api/downloadFile';
}, 100);
}
The address changes but the download don't start. If I press F5 then the download starts just fine. If I use a external URL to host my file, the download start just fine too.
Thanks
First things first. Don't use setTimeout, but rather use the callback function of setState to execute code after the state is set ensuring it has been modified. Calling the callback function will guarantee the state is changed before that code in the callback is executed.
from the official docs:
setState() enqueues changes to the component state and tells React
that this component and its children need to be re-rendered with the
updated state. This is the primary method you use to update the user
interface in response to event handlers and server responses.
setState() does not always immediately update the component. It may
batch or defer the update until later. This makes reading this.state
right after calling setState() a potential pitfall. Instead, use
componentDidUpdate or a setState callback (setState(updater,
callback)), either of which are guaranteed to fire after the update
has been applied.
setState(stateChange[, callback])
The second parameter to setState() is an optional callback function
that will be executed once setState is completed and the component is
re-rendered. Generally we recommend using componentDidUpdate() for
such logic instead.
So, instead of:
if (this.state.downloadFile === true) {
this.setState({ downloadFile: false });
setTimeout(() => {
// execute code, or redirect, or whatever
}, 100);
}
you should do:
if (this.state.downloadFile === true) {
this.setState({ downloadFile: false }, () => {
// execute code, or redirect, or whatever
});
}
Now, for your specific problem
Set headers in your server side
You can set the Content-Disposition header to tell the browser to download the attachment:
from here:
In a regular HTTP response, the Content-Disposition response header is
a header indicating if the content is expected to be displayed inline
in the browser, that is, as a Web page or as part of a Web page, or as
an attachment, that is downloaded and saved locally.
Set it like this:
('Content-Disposition: attachment; filename="/tmp/PASOP180901.txt"');
Force download from the client
There are multiple ways to force the download from the client, but this is the only one I've tried.
For this to work, you have to have the content of text somehow in the client (your express route can return it for example) and create a filename for the file that will be downloaded.
let element = document.createElement('a');
element.setAttribute('href', 'data:text/plain;charset=utf-8,' + encodeURIComponent(text));
element.setAttribute('download', filename);
document.body.appendChild(element);
element.click();
document.body.removeChild(element);
Basically you are creating an empty link component, setting the data attribute to it with the text's content, attaching the link to the body, clicking the link and then removing the link from the body.
Open the link in a new tab
Opening the link in a new tab will trigger the download as well:
window.open('/api/downloadFile');
Redirect programatically
Have a look at this question in SO
You can do this:
this.props.history.push("/api/downloadFile")?
If cannot access this.props.history you can import { withRouter } from 'react-router-dom'; and export default withRouter(yourComponent); to access it.

Catching dialog name before being routed - middleware

I have a bot built with MS bot framework, using a library structure.
I'm trying to catch the dialog name + library of a message, before it is being routed to the dialog. (for analytics purposes)
Is there a middleware that can help me do that?
I tried the routing middleware of the UniversalBot, but it seems be running just before a dialog was choosen.
One possible option here could be using the ISessionMiddleware.
botbuilder: function (session, next) {
console.log(session.message.text);
next();
}
This will allow you to have access to the session. This will execute once a message is bound to a particular session and gives the option of looking at a message and the state of the session (where user is in available dialogs, etc) then making a decision of how to proceed.
It seems like bot.onDisambiguateRoute is the solution.
The var route contains the route name/library in that case, and has also the dialog arguments besides that. see the docs for more info
example code:
bot.onDisambiguateRoute(function (session, routes) {
// Route message as normal
var route = builder.Library.bestRouteResult(routes, session.dialogStack(), bot.name);
// *** log route
if (route) {
bot.library(route.libraryName).selectRoute(session, route);
} else {
// Just let the active dialog process the message
session.routeToActiveDialog();
}
}
});

JSOM calls forbidden in apps in anonymous mode on the first load of the page (a reload solves it)

I have an app part on a page on a publishing site.
In that app, the JSOM calls work well when the user is authenticated.
In anonymous mode, it will work only after a reload of the page containing the app part. During the first loading, I will get this error:
Failed to load resource: the server responded with a status of 403 (FORBIDDEN)
http://app-4e3210d8daa297.abc.com/MyList/_vti_bin/client.svc/ProcessQuery
The error handlers for the JSOM calls return an "undefined" error message.
But if I reload the page, or the app-part itself (with a javascript code), then it works.
Why the JSOM calls are forbidden only for the first loading of the page? How do I solve this?
This is a quick fix to solve temporarily this problem, but I am sure there is a better way.
//error handler of the jsom call that fails
function onErrorLoadList(data, error, errorMessage) {
console.log("Could not complete cross-domain call: " + errorMessage);
// in anonymous mode, for the first load of the app
// the JSOM calls fail and errorMessage is undefined
if (typeof errorMessage == 'undefined') {
// we will reload the app by adding reload=true in the url
// if it fails again, we won't do it to avoid a loop
if (!location.href.match(/reload=true/)) {
console.log("The app reloads.");
location.href = location.href + "&reload=true";
}
}
}

Can a Chrome Extension content script trigger a keyboard event received by the origin site?

The following code words if run in the console itself:
var $inputbox = $('input#inputfield');
var SPACE_KEYCODE = 32;
var space_down = $.Event( 'keyup', { which: SPACE_KEYCODE } );
$inputbox.trigger(space_down)
I can see the event being triggered and the page responding.
However when running the same code in a content script via a Chrome extension, it fails silently. Logging the results of '$inputbox.trigger(space_down)' shows it correctly returning the element.
The intention here is to have the existing page JS respond to the keyboard event from the extension. Is this possible?
Although I haven't been able to find documentation about whether events are distinct between the content script JS 'world' and the origin site's world, I made the following in the content script to load some JS into window.location, making it run in the content of the origin site.
// In order to send keyboard events, we'll need to send them from the page's JS
var load_into_page_context = function(file) {
var file_url = chrome.extension.getURL(file);
$.get(file_url, function(script_contents) {
window.location = 'javascript:'+script_contents
})
}
load_into_page_context("injectme.js");
This will load injectme.js (bundled with the extension) into the window.location, and make the generated keyboard events activate the origin site's event handlers.

how to check if my javascript browser extension works

I am trying to create a simple javascript based extension for Google Chrome that takes data from one specific iframe and sends it as part of a POST request to a webpage.
The web page that sends the data submitted by POST request, to my email address.
I tried running the extension, it looks to be running fine, but I am not getting any email.
The servlet which receives form data is very simple, I dont think there is any error in it.
What I want is some way to check if the javascript based extension works or not.
The javascript code is given below-
var mypostrequest=new ajaxRequest()
mypostrequest.onreadystatechange=function(){
if (mypostrequest.readyState==4){
if (mypostrequest.status==200 || window.location.href.indexOf("http")==-1){
document.getElementById("result").innerHTML=mypostrequest.responseText
}
else{
alert("An error has occured making the request")
}
}
}
var namevalue=encodeURIComponent("Arvind")
var descvalue=encodeURIComponent(window.frames['test_iframe'].document.body.innerHTML)
var emailvalue=encodeURIComponent("arvindikchari#yahoo.com")
var parameters="name="+namevalue+"&description="+descvalue &email="+emailvalue
mypostrequest.open("POST", "http://taurusarticlesubmitter.appspot.com/sampleform", true)
mypostrequest.setRequestHeader("Content-type", "application/x-www-form-urlencoded")
mypostrequest.send(parameters)
UPDATE
I made changes so that the content in js file is invoked by background page, but even now the extension is not working.
I put the following code in background.html:
<script>
// Called when the user clicks on the browser action.
chrome.browserAction.onClicked.addListener(function(tab) {
chrome.tabs.executeScript( null, {file: "content.js"});
});
chrome.browserAction.setBadgeBackgroundColor({color:[0, 200, 0, 100]});
</script>
Looking at your code looks like you are trying to send cross domain ajax request from a content script. This is not allowed, you can do that only from background pages and after corresponding domains are declared in the manifest. More info here.
To check if your extension works, you can open dev tools and check if there any errors in the console. Open "Network" tab and see if request was sent to your URL. Place console.log in various places in your code for debugging, or use full featured built in javascript debugger for step-by-step debugging.

Resources