Search code examples
javaappletusbjavapos

Do signed java applets have access to USB peripherals when run in the browser sandbox?


I've implemented a Java package with functionality to operate a POS printer and cash drawer connected to the workstation via USB. I've also implemented an applet to utilize the functionality of this package with the hopes of having it invoked by a POS website.

When the applet is run from within Eclipse, all goes well. When the applet is run from within a browser it seems that my package is unable to access the peripherals connected via USB. I get an error from the third party (JavaPOS) code stating:

jpos.JposException: The device communications channel could not be opened, check the device and retry.

The applet is signed with a self-cert. I'd post some code but the error is thrown from somewhere buried in manufacturer-specific drivers for the POS printer in use.

I'm assuming the issue is that, from within the browser sandbox, the applet does not have access to the peripherals connected via USB.
Could this be the case? If so, is there anyway to access USB peripherals from within a signed Applet?
If an applet can't access USB peripherals, how could a web site invoke code that can?


Solution

  • Do signed java applets have access to USB peripherals when run in the browser sandbox?

    To address this specific question (and avoid the specific technologies involved in the comments following), yes Signed Java Applets have access to USB Peripherals. The "sandbox" is what you have capability to "break out of" when you run a signed applet.

    But for security reasons, simply signing the applet does not automatically give access to items outside of the sandbox.

    PrivelegedAction seems to be the preferred method for accessing privileged system components, such as the printer. More about these privileged actions is provided by Oracle here: http://docs.oracle.com/javase/7/docs/api/java/security/AccessController.html

    In addition, there are several consideration when doing something like this from a web browser as Java cares where the action originates from.

    public function writeFile() {
        ...
        FileWriter fw = new FileWriter(...);
        ...
    }
    
    
    public void init() {
        writeFile();
    }
    

    For example, if you were to write a file to the filesystem (i.e. $HOME/Desktop/text.txt) using the FileWriter class in the applet init() method, a Signed Applet would generally allow it. Wrapping this into a PrivilegedAction would be better, and checking permission first using AccessController.checkPermission(...) would be ideal.

    However, FileWriter gets blocked when it's called directly from JavaScript (instead of from init()):

    var myapplet = document.getElementById('myapplet');
    myapplet.writeFile(); // Blocked by Security Framework
    

    To circumvent this issue, some chose to use PrivelegedAction, however if the action takes a long time, you'll notice it blocks the UI, which is very bad practice in a web page (and can deadlock the browser).

    public void init() {
       ...
       AccessController.doPrivileged(new PrivilegedAction() {
          public Object run() {
             writeFile();
             return null;
          }
       });
       ...
    }
    

    Furthermore, your question asks specifically about accessing a USB peripheral, which is generally done by iterating through the Human Interface Devices. HID is not something Java directly supports natively (yet, as of writing this/JRE7). So yes, a signed applet CAN talk to your USB peripherals, but you would need to use some form of Java Native Interfacing (JNI) to properly "access" them. JNI can be a mess to support cross-platform (i.e. distributing DLLs and SOs with your JAR) so...

    What most Java Applets do is access the locally installed printers and use the standard Java Printing libraries. This is how we do it over at the qz-print project and you're free to review our source code here: https://github.com/qzindustries/qz-print/tree/master/qz-print/src/qz which uses threads fired by init() and boolean flags to fire all privileged functions.