Download a File Based From Add-On - javascript

I'm building an add-on which launches an executable to enable advanced and intelligent proxy. I've been able to launch the executable perfectly but the exe is of decent size and I need a different one for each OS.
I don't want to package them all into the add-on because that would result in a unnecessarily large file size. I would like the add-on to download the correct file for the client's OS after it's installed.
I found nsIDownloader but the only method it has is init() which takes an observer and a download location. I have no idea how I would give it the web server location. It seems like a significant amount of documentation on it is missing.

nsIDownloader may sound like it is a good place to start, but it really is just a low-level helper API, and discouraged these days because it does synchronous I/O on the main/UI thread.
I'd instead use the relatively new, and asynchronous Downloads.fetch() high-level helper.
E.g. the following will work in a Scratchpad. It would work in any add-on as well, if the execution environment has console (e.g. overlays, or Console.jsm), or the debug console.log calls where removed.
Cu.import("resource://gre/modules/Task.jsm");
Cu.import("resource://gre/modules/Downloads.jsm");
Task.spawn(function() {
var file = Services.dirsvc.get("TmpD", Ci.nsIFile);
file.append("test.download");
try {
yield Downloads.fetch("http://example.org/", file);
console.log(file.path);
console.log(file.exists());
console.log(file.fileSize);
}
catch (ex) {
console.log("Download Failed", ex);
}
});

Related

How to write file in Google Chrome App without prompting?

I am fumbling around with the free Chrome Dev Editor on my Chromebook. I am trying to use the fileSystem to read and write .txt files. It is all very wrapped up, not at all like in C. I can no more tell if I am even allowed to do something, let alone where the proper place is to find out how.
I think the files I can see using the Files thingy are in the sandbox that I am allowed to play in (meaning, folders that are accessible by the app?) The root is called Downloads. Sure enough, if I use all the dot calls and callback arguments for the read, as in the examples at developer.chrome.com/apps/filesystem, it works. But I have to have a prompt
every time for both reads and writes.
A little more Googling came up with this trick: (I think it was here in stackoverflow, in fact) a chrome.runtime call, getPackagedDirectoryEntry, that seems to give me a handle to the folder of my app. Great! That's all I need to not have to go through the prompting. For the readfile, anyway.
But then trying to apply the same trick to the writefile did not work. In fact, it did nothing discernible. No errors, no complaints. Nothing. Even though the write file with prompting works fine (so presumably I have the permissions and Blob construction right.) What to do?
Here is my code:
function test(){
// Samsung 303C Chromebook - Chrome Dev Editor - /Downloads/Daily/main.js
// prompted write
chrome.fileSystem.chooseEntry({type:'saveFile'},function(a){
a.createWriter(function(b){
b.write(new Blob(["Programming fun"],{type:'text/plain'}));
},function(e){trace.innerText = 'error is ' + e;});
});
// unprompted read
chrome.runtime.getPackageDirectoryEntry(function(a){
a.getFile('text.txt',{},function(b){
b.file(function(c){
var d = new FileReader();
d.onloadend = function(){trace.innerText = this.result;};
d.readAsText(c);
});
});
});
// unprompted write - why not?
chrome.runtime.getPackageDirectoryEntry(function(a){
a.getFile('new.txt',{create:true},function(b){
b.createWriter(function(c){
c.write(new Blob(["Miss Manners fan"],{type:'text/plain'}));
},function(e){trace.innerText = 'error is ' + e;});
});
});
}
To be fair, Filesystem API is a big mess of callbacks and it's not unreasonable to get drowned in it.
It's not currently documented, but chrome.runtime.getPackageDirectoryEntry returns a read-only DirectoryEntry, and there is no way to make it writable (it's specifically blacklisted).
You probably don't see an error, because it fails at the getFile stage, for which you don't have an error handler.
Unfortunately, for a Chrome App the only option to write out to a real filesystem is to prompt the user. However, you can retain the entry and ask only once.
If you don't need to write out to the real filesystem but need only internal storage, HTML Filesystem API can help you (yes, it's marked as abandoned, but Chrome maintains it since chrome.fileSystem is built on it).
Extensions additionally have access to chrome.downloads API that enables writing to (but not reading) the Downloads folder.
P.S. What you see in Files app is your "real" local filesystem in ChromeOS + mounted cloud filesystems (e.g. Google Drive)
You can use the basic web Filesystem API. First, add the "unlimitedStorage" permission. Then, copy the packaged files to the sandboxed filesystem, like this:
chrome.runtime.getPackageDirectoryEntry(function(package) {
package.getMetadata(function(metadata) {
webkitRequestFileSystem(PERSISTENT, metadata.size, function(filesystem) {
package.copyTo(filesystem.root)
})
})
})

Chrome extensions for silent print?

I have made a silent print web application that prints a PDF file. The key was to add JavaScript to the PDF file that silently print itself.
To do this I open the PDF with acrobat reader in chrome, that allow me to execute the script (with the proper permissions).
But as it was announced this solution won't work after chrome 45 because the npapi issue.
I guess a possible solution could be to use the recently release printProvider of chrome extensions.
Nevertheless I can't imagine how to fire any of the printProvider events.
So the question is: Is ok to think in chrome extensions to make a silent print web application, and how can I fire and handle a print job for an embedded PDF of a HTML Page.
Finally I reached an acceptable solution for this problem, as I couldn't find it out there, but read to many post with the same issue I will leave my solution here.
So first you need to add your printer to the Google Cloud Print and then you will need to add a proyect to the Google Developers Console
Then add this script and any time you need to print something execute the print() function. This method will print the document indicated in the content
The application will ask for your permission once to manage your printers.
function auth() {
gapi.auth.authorize({
'client_id': 'YOUR_GOOGLE_API_CLIENT_ID',
'scope': 'https://www.googleapis.com/auth/cloudprint',
'immediate': true
});
}
function print() {
var xhr = new XMLHttpRequest();
var q = new FormData()
q.append('xsrf', gapi.auth.getToken().access_token);
q.append('printerid', 'YOUR_GOOGLE_CLOUD_PRINTER_ID');
q.append('jobid', '');
q.append('title', 'silentPrintTest');
q.append('contentType', 'url');
q.append('content',"http://www.pdf995.com/samples/pdf.pdf");
q.append('ticket', '{ "version": "1.0", "print": {}}');
xhr.open('POST', 'https://www.google.com/cloudprint/submit');
xhr.setRequestHeader('Authorization', 'Bearer ' + gapi.auth.getToken().access_token);
xhr.onload = function () {
try {
var r = JSON.parse(xhr.responseText);
console.log(r.message)
} catch (e) {
console.log(xhr.responseText)
}
}
xhr.send(q)
}
window.addEventListener('load', auth);
<script src="https://apis.google.com/js/client.js"></script>
Anyway this script throw a 'Access-Control-Allow-Origin' error, even though this appears in the documentation... I couldn't make it work :(
Google APIs support requests and responses using Cross-origin Resource Sharing (CORS). You do not need to load the complete JavaScript client library to use CORS. If you want your application to access a user's personal information, however, it must still work with Google's OAuth 2.0 mechanism. To make this possible, Google provides the standalone auth client — a subset of the JavaScript client.
So to go throw this I had to install this chrome extension CORS. I'm sure that some one will improve this script to avoid this chrome extension.
You can register an Application to a URI Scheme to trigger the local application to print silently. The setting is pretty easy and straightforward. It's a seamless experience. I have posted the solution here with full example:
https://stackoverflow.com/a/37601807/409319
After the removal of npapi, I don't believe this is possible solely programmatically. The only current way I know to get chrome to print silently is using chrome kiosk mode, which is a flag (mode) you have to set when starting chrome.
Take a look at these SO posts:
Silent printing (direct) using KIOSK mode in Google Chrome
Running Chrome with extension in kiosk mode
This used to be possible using browser plugins (e.g. Java + NPAPI, ActiveX) but has been blacklisted by most browsers for several years.
If interested in modern solutions that use similar techniques, the architecture usually requires the following:
WebSocket, HTTP or Custom URI connection back to localhost
API that talks through web transport (JavaScript or custom URI scheme) to an app running locally.
A detail of projects (several of them are open source) that leverage these technologies are available here:
https://stackoverflow.com/a/28783269/3196753
Since the source code of these projects can vary (hundreds of lines to tens-of-thousands of lines), a code snippet would be too large unless a inquiring about a specific project's API.
Side note: Some technologies offer dedicated cloud resources, which add convenience at the expense of potential latency and privacy. At the time of writing this, the most popular "free" cloud solution -- Google Cloud Print -- is slated to be retired in December 2020.

How to force client reload after deployment?

I'm using the MEAN stack (mongo, express, angular and node). I'm deploying relatively frequently to production...every couple of days. My concern is that I'm changing the client side code and the API at times and I would rather not have to ensure backwards compatibility of the API with previous versions of the client code.
In such a scenario, what is the most effective way of ensuring that all clients reload when I push to production? I have seen that Evernote for example has a pop-up that says something along the lines of please reload your browser for the latest version of Evernote. I would like to do something similiar...do I need to go down the path of socket.io or sock.js or am I missing something simple and there is a simpler way to achieve this?
Update:
AppCache was deprecated summer 2015 so the below is no longer the best solution. The new recommendation is to use Service Workers instead. However, Service Workers are currently still experimental with sketchy (read: probably no) support in IE and Safari.
Alternatively, many build tools now seamlessly incorporate cache-busting and file "versioning" techniques to address OPs question. WebPack is arguably the current leader in this space.
This might be a good use case for using HTML5's AppCache
You'd probably want to automate some of these steps into your deployment scripts, but here is some code you might find useful to get you started.
First, create your appcache manifest file. This will also allow you to cache resources in the client's browser until you explicitly modify the appcache manifest file's date.
/app.appcache:
CACHE MANIFEST
#v20150327.114142
CACHE:
/appcache.js
/an/image.jpg
/a/javascript/file.js
http://some.resource.com/a/css/file.css
NETWORK:
*
/
In app.appcache, the comment on line #v20150327.114142 is how we indicate to the browser that the manifest has changed and resources should be reloaded. It can be anything, really, as long as the file will look different to the browser from the previous version. During deployment of new code in your application, this line should be modified. Could also use a build ID instead.
Second, on any pages you want to use the appcache, modify the header tag as such:
<html manifest="/app.appcache"></html>
Finally, you'll need to add some Javascript to check the appcache for any changes, and if there are, do something about it. Here's an Angular module. For this answer, here's a vanilla example:
appcache.js:
window.applicationCache.addEventListener('updateready', function(e) {
if (window.applicationCache.status == window.applicationCache.UPDATEREADY) {
// Browser downloaded a new app cache.
// Swap it in and reload the page to get the latest hotness.
window.applicationCache.swapCache();
if (confirm('A new version of the application is available. Would you like to load it?')) {
window.location.reload();
}
}
else {
// Manifest didn't changed. Don't do anything.
}
}, false);
Alternatively, if AppCache won't work for your situation, a more ghetto solution would be to create a simple API endpoint that returns the current build ID or last deployment date-time. Your Angular application occasionally hits this endpoint and compares the result to it's internal version, and if different, reloads itself.
Or, you may consider a live-reload script (example), but, while very helpful in development, I'm not sure how good of an idea it is to use live/in-place-reloading of assets in production.
I will tell you my problem first then I will recommend a tentative solution. I wanted to force my user to log out and then log in when a production build is been deployed. At any point in time, there will be two versions of software deployed on production. A version which software which FE knows and a version which Backend knows. Most of the time they would be the same. At any point in time if they go out of sync then we need to reload the client to let the client know that a new production build has been pushed.
I am assuming 99.99% of the time the backend would have the knowledge of the latest version of the deployed software on production.
following are the two approaches which I would love to recommend:-
The backend API should always return the latest version of the software in the response header. On the frontend, we should have a common piece of code that would check if the versions returned by the API and that present on the FE are the same. if not then reload.
Whenever a user logs in. the BE should encode the latest software version in the JWT. And the FE should keep sending this as a bearer token along with every API request. The BE should also write a common interceptor for every API request. which would compare the software version in the JWT received from the API request and the
Maybe you can add hash to your client code file name. eg app-abcd23.js.
So the browser will reload the file instead of get it from cache. or you can just add the hash to url.eg app.js?hash=abcd23 but some browser may still use the cached version.
i know rails has assets-pipline to handle it, but i am not familiar with MEAN stack. there should be some package in npm for that purpose.
And i dont think it is really necessary to use socket.io if you want to notify the user their client code is out of date. you can define your version in both html meta tag and js file,if mismatch, show a popup and tell the user to refresh.
Try to limit your js/files to expire within smaller periodic time, ie: 1 days.
But in case you want something that pop-out and tell your user to reload (ctrl+f5) their browser, then simply make a script that popup that news if you just changed some of your files, mark the ip/session who have just reload/told to reload, so they will not be annoyed with multiple popup.
I was facing the same problem recently. I fixed this by appending my app's build number with my js/css files. All my script and style tags were included by a script in a common include files so it was trivial to add a 'build number' at the end of the js/css file path like this
/foo/bar/main.js?123
This 123 is a number that I keep track of in my same header file. I increment it whenever I want the client to force download all the js files of the app. This gives me control over when new versions are downloaded but still allows the browser to leverage cache for every request after the first one. That is until I push another update by increment the build number.
This also means I can have a cache expiry header of however long I want.
Set a unique key to local storage during the build process
I am using react static and loading up my own data file, in there i set the ID each time my content changes
Then the frontend client reads the key with from local storage
(if the key does not exist it must be the first visit of the browser)
if the key from local storage does not match it means the content has changed
fire line below to force reload
window.replace(window.location.href + '?' + key)
in my case i had to run this same line again a second latter
like
setTimeout( (window.replace(window.location.href + '?' + key))=> {} , 1000)
full code below:
const reloadIfFilesChanged = (cnt: number = 0, manifest: IManifest) => {
try {
// will fail if window does not exist
if (cnt > 10) {
return;
}
const id = localStorage.getItem('id');
if (!id) {
localStorage.setItem('id', manifest.id);
} else {
if (id !== manifest.id) {
// manifest has changed fire reload
// and set new id
localStorage.setItem('id', manifest.id);
location.replace(window.location.href + '?' + manifest.id);
setTimeout(() => {
location.replace(window.location.href + '?' + manifest.id + '1');
}, 1000);
}
}
} catch (e) {
// tslint:disable-next-line:no-parameter-reassignment
cnt++;
setTimeout(() => reloadIfFilesChanged(cnt, manifest), 1000);
}
};

Write a variable to a file in Javascript

This may be a copy.. but I'm not getting the thing I want from the answers I saw..
I just want to save a particular variable into a local file using Javascript. I know how to read a file.
I wrote this code..
<script>
var fs = require('fs');
fs.writeFile('http://localhost/online/hello.txt', 'Hello Node', function (err) {
if (err) throw err;
else
{
console.log('It\'s saved!');
}
});
</script>
What is the error here.. or is there a simple and straight-forward way of doing it..??
It seems you're trying to call node-js code from the browser. Although javascript can run in both the browser and on the server (node-js), those are separate systems.
Another thing you can do is google "HTML save file example" and see how this is typically implemented - by opening a save dialog for the user, getting his/her permission, etc. (otherwise any website could just write any file to your computer...).
You are writing NodeJS code for client side application. You must understand the difference between javascript on browser and javascript on NodeJS platform.
Javascript is a language just like C, Java and Python
V8 is a javascript engine to run the javascript application. It is something similar to JRE for Java.
Browser(Only Chrome) uses V8 engine for running javascript application. Other browsers use different javascript engine. Five years ago, there was only one possibility that javascript can only work on browser. You cannot use javascript for application programming like C and Java
NodeJS is a platform which uses V8 to enables developer to write javascript application just like C, Java program. NodeJS also has some inbuilt library for accessing file system,
networks, and much more utilities. One of the internal library in NodeJS is fs. It only works on NodeJS application, not on browser application.
This can be done pretty simply using jrpc-oo. jrpc-oo links the browser and nodejs using the JRPC2 protocol. jrpc-oo abstracts classes over JRPC so that either side (nodejs or the browser) can call eachother.
I have setup an example repo to do exactly this here. Use the writeToFile baranch. I will break out the important parts here.
First in nodejs, we write a class with a method to write input arguments to file. The method looks like so (from the file TestClass.js) :
const fs = require('fs');
class TestClass {
writeToFile(arg){
fs.writeFileSync('/tmp/browser.json',JSON.stringify(arg));
}
}
In the browser we inherit from the jrpc-oo class JRPCClient and call the server class TestClass and method writeToFile like so (from the file src/LitJRPC.js) :
import {JRPCClient} from '#flatmax/jrpc-oo/jrpc-client.js';
export class LitJRPC extends JRPCClient {
writeObjToFile(){
// create the argument we want to save to file
let dat={name:'var',value:10};
// Ask the server to execute TestClass.writeToFile with args dat
this.server['TestClass.writeToFile'](dat);
}
}
Finally we run the nodejs app and the web-dev-server and we look at the browser console and nodejs console to see what happened. You will see the browser variable dat saved to the file /tmp/browser.json
As we are using a secure websocket for jrpc, you will need to generate the certificate and clear the certificate with the browser before the app will work. If you don't want to worry about security then don't use secure websockets. Read the readme in the reference repo for more information on setup and usage.

Log JavaScript console into a log file with Firefox

We have a web application which runs in a kiosk mode Firefox, using the RKiosk extension to achieve this. We suspect that we have a very rare error in the system which yields in a JavaScript error. However because we can't access the JavaScript console we can't examine the log.
I'm searching for an option to make Firefox log all JavaScript console messages into a file regardless of the tab and page opened. I can't seem to find any extension for this. I'm already using log4javascript which sends errors back to the server, but it seems that our application crashes in a way that it skips the logging altogether.
Writing to a file sounds like a tedious task to me. It requires privileges that browser code doesn't normally have and you'd have to negotiate with an add-on you'd have to write in order to access file I/O.
From what I understand your issue is
I'd like to make Firefox log all errors
There are several approaches we can do to tackle this
First approach - log everything to localStorage too:
Now, rather than writing to an actual file, you can write to localStorage or IndexedDB instead.
localStorage["myApplog"] = localStorage["myApplog"] || "";
var oldLog = console.log;
console.log = function(){
oldLog.apply(console,arguments); // use the old console log
var message = "\n "+(new Date).toISOString() + " :: "+
Array.prototype.join.call(arguments," , "); // the arguments
localStorage["myApplog"] += message;
}
This is rather dirty and rather slow, but it should get the job done and you can access the log later in local storage. LocalStorage has a ~5MB limit if I recall correctly which I think is enough if you don't go crazy with logging. You can also run it selectively.
Second approach - log only errors
This is similar to what Pumbaa80 suggested. You can simply override window.onerror and only log errors.
// put an empty string in loggedWinErrors first
var oldError = window.onerror || function(){};
window.onerror = function(err,url,lineNumber){
oldError.call(this,err,url,lineNumber);
var err ="\n Error: (file: " + url+", error: "+err+", lineNumber: "+lineNumber+")");
localStorage["loggedWinErrors"] += err;
}
Third and drastic approach - use a VM.
This is the most powerful version, but it provides the most problematic user experience. You run the kiosk in a virtual machine, you detect an uncaught exception - when you do you freeze the machine and save its state, and run a backup VM instead. I've only had to do this when tackling the most fearsome errors and it's not pretty. Unless you really want the whole captured state - don't do this.
Really, do the extension before this - this is tedious but it gets very solid results.
In conclusion, I think the first approach or even just the second one are more than enough for what you need. localStorage is an abstracted storage that web pages get for saving state without security issues. If that's not big enough we can talk about an IndexedDB solution.
It all really depends on the use case you have.
You can use XULRunner...a Mozilla runtime environment for XUL applications. It uses Gecko like Firefox and:
You can access the file system or using the SQLite database to store logs.
You can render your kiosk in fullscreen mode without using extensions.
Have you tried jserrorcollector? We are using it and it works fine (only in Firefox). It's only for Java.
// Initialize
FirefoxProfile ffProfile = null;
ffProfile = new FirefoxProfile();
JavaScriptError.addExtension(ffProfile);
// Get the errors
List<JavaScriptError> jsErrors = JavaScriptError.readErrors(webDriver);
More information: https://github.com/mguillem/JSErrorCollector
Have you considered remote logging?
I commonly assign window.onerror to do send a request to a webserver storing the details of the error remotely. You could do the same with console.log if you preferred.
Try the following console export. It is a plugin for Firebug of Firefox. It's quite handy.
http://www.softwareishard.com/blog/consoleexport/
If you are able/willing to switch from Firefox to Chrome or Opera you would be able to use the Sandboxed Filesystem API to write a local file. See:
http://www.html5rocks.com/en/tutorials/file/filesystem/
http://caniuse.com/filesystem
Start in kiosk mode using chrome.exe --kiosk <url>
You would then want to disable Alt-F4 and Ctrl-Alt-Del which on Windows can be done with several third-party tools like Auto Hotkey (Disable Ctrl-Alt-Del Script).
You could use a remote logging script like Qbaka. It catches every JS error and sends it to the Qbaka server. There you can login and see all JS errors. Qbaka stores the exact error message, the script, line number, stack trace and the used browser for each error message.

Categories

Resources