3

I want to be able to assign a unique name to each PC in a WAN (either in the hostname or in a local file) and somehow allow the browser to pick this information up. The rationale is that I can later trace that "transaction X was carried out on terminal A", which I then know that it is on building B, floor C, room D and so on. Why we need this, it's another topic. Just say we do need this kind of identification for good reason.

So far we've used a custom plugin (.dll + .xpi) that would read a local config file and also allow us to talk to the LPT port (again, don't ask :) ), but that has left us stuck with Firefox 3.6.17. The LPT stuff won't be needed in the newer version, so we're left with identifying our workstations and preferably storing some other read-only config info in there. Something that an admin will only be able to change.

While I didn't write that plugin, I understand that in the later versions of Firefox all these are impossible. So we went out and:

  • tried writing a Firefox extension that will only read a local file. After FF26 (or was it 28?) the API changed once again and we simply can't get this functionality to work (although we contacted Mozilla devs and we followed their guidelines meticulously)
  • tried writing a Java Applet, but I don't know if that is the way to go in 2015. It certainly was back in the early 2000s, when I was writing Java. The applet works, but I'm concerned about the performance/stability of the JRE (I know that for deployment I'll have to buy a code-signing certificate)
  • thought about writing a Flash plugin instead of a Java Applet. But then, I'm not really fond of Flash and I wish it to whither away into oblivion, because it so deserves it. But if it'll do my work better, I'll use it anytime

So, how would you go about solving this task? What is the "recommended way" to do this in 2015?

Noitidart
  • 35,443
  • 37
  • 154
  • 323
TrianK
  • 31
  • 1
  • 2
  • Question : how your user will execute your "secret operation" ? Via a HTML page on the browser, or via a browser plugin or what exactly ? – akmozo Jan 29 '15 at 22:04
  • It's doable, tell me how you would get the ID in C and Ill show you how to get it in firefox. – Noitidart Jan 30 '15 at 01:01
  • "I'm not really fond of Flash and I wish it to whither away into oblivion, because it so deserves it. " +1 :thumbsUp: – Noitidart Jan 30 '15 at 01:12
  • akmozo, what we've been doing so far is install a plugin on the browser, which provides a JS api for our webpages to use. Noitidart, I didn't write the plugin. I know it reads a KEY=VALUE file and makes its contents available via a JS api, provided from our plugin. – TrianK Feb 02 '15 at 16:09
  • @TrianK use @ symbols before user names, otherwise they dont get notified. You should accept nmaiers answer below its very thorough. – Noitidart Feb 05 '15 at 23:37

1 Answers1

8

Creating a Firefox add-on compatible with the recent Firefox versions wouldn't be that hard, and can be done without involving custom DLLs and the like.

I'll be using a simple Add-on SDK add-on I just created as a demonstration.

Content Script

First, one needs a PageMod aka. content-script that will inject whatever information you like into whatever website you want.

In the following example I will be injecting a new global hostInformation variable into all pages matching *.example.org. Consult the docs on how to refine that for your use case.

main.js

const {PageMod} = require("sdk/page-mod");

function contentScript() {
    // Usually, you'd but this function body into a new file ;)

    // Just makes all of contentScriptOptions available to the real website,
    // as the |hostInformation| objects.
    unsafeWindow.hostInformation = cloneInto(self.options, unsafeWindow);
}

PageMod({
    include: "*.example.org",
    contentScript: "(" + contentScript.toSource() + ")()",
    contentScriptOptions: require("./hostname"),
    contentScriptWhen: "start",
});

Of course, ./hostname isn't a standard SDK module, so we'll have to write that in the next step.

Getting the host name

Whatever information you want to pass, you have to figure out for yourself. You mentioned reading that information from a file, so io/file or OS.File might be viable options for that, and have tons of questions and answers already going into more detail.

I opted, however, for getting the hostname from the OS directly by means of calling the gethostname function. It isn't available as a mozilla API AFAIK, but js-ctypes let's us interact with any dynamically-loadable, exported function incl. gethostname.

Now it is just a matter of loading the right library for a OS (libc.so.6 on Linux, libc.{so,dylib} on *nix incl. OSX and some embedded Linux and ws2_32.dll on Windows). Since Firefox was nice enough to already have initialized WinSock (WSAStartup) for us, we don't need to care about it.

So here is the final hostname.js module.

hostname.js

const {Ci, Cc, Cu} = require("chrome"); // for js-ctypes
Cu.import("resource://gre/modules/ctypes.jsm");

function getHostName() {
    function loadLibrary() {
        const candidates = ["libc.so.6", ctypes.libraryName('c'), ctypes.libraryName('ws2_32')];
        for (var cand of candidates) {
            try {
                return ctypes.open(cand);
            }
            catch (ex) {}
        }
    }
    const library = loadLibrary();
    if (!library) {
        return null;
    }
    try {
        const gethostname = library.declare(
            "gethostname",
            ctypes.default_abi,
            ctypes.int, // return value
            ctypes.char.ptr, // [out] name,
            ctypes.int // [in] namelen
            );
        let addrbuf = (ctypes.char.array(1024))();
        if (gethostname(addrbuf, 1024)) {
            throw Error("ctypes call failed");
        }
        let rv = addrbuf.readString();
        console.log("got hostname", rv);
        return rv;
    }
    catch (ex) {
        console.error("Failed to get host name", ex);
        return null;
    }
    finally {
        library.close();
    }
}

exports.hostName = getHostName();

Conclusion

I tested the resulting add-on (cfx xpi) on OSX Mavericks, Windows 7, Linux Arch, and verified it works by navigating to example.org, opening the web console and checking that there is a new global accessible by the website named hostInformation which contains the actual hostname in the hostName property.

Have a github repo with the whole, working project.

nmaier
  • 32,336
  • 5
  • 63
  • 78
  • Tested on Win8.1, Ubuntu 14.04 (64bit), OSX 10.10.1, Mint 17.1 Cinnamon (64bit), and this Linux OS that uses KDE/Qt called KaOS (KDELibs version 4.1.4.3, Qt version 4.8.6, 64bit) works in all. I didn't navigate to a site, i just copied pasted this code into scratchpad and it returned a string with "noit" in it as thats what I name all my computers. – Noitidart Jan 31 '15 at 23:23
  • 1
    Since Firefox team are standerizing WEB extension instead of ADD Ons, is there a way to achive same from the webextension. I tried this http://stackoverflow.com/a/9613346/5898849 this as web extension.But it raises error as Component class not defined and such. Also i am not sure if i did it correctly or its the correct way to do it.Any help would mean a lot. – Yugesh Gyawali Mar 29 '17 at 07:22