Posts
Search
Contact
Cookies
About
RSS

Creating a simple Firefox add-in to check a Web application

Added 20 Nov 2015, 7:47 a.m. edited 18 Jun 2023, 1:12 a.m.
For a while now I'd promised myself I'd take a look at the newer methods of implementing a Firefox extension (add-on) Having recently installed an aggregator and reader for RSS feeds, knowing that the add-on side of things would likely be the challenge, I decided to just write a php hack to directly spy on the single value I wanted (number of unread feed posts for a user) FreshRSS rather sensibly only exposes a small part of itself to publicly accessible web space, and I decided to use the same technique for my hack. I'm only using FreshRSS as an example - you can use these techniques on whatever web app you want to monitor... From the start I made the decision to expose the information without need for authorisation, basically I don't care who has access to the read only number of feed posts I haven't read... In theory this could be used to brute force guess user account names, but on balance I think this is a fair trade between paranoia and usability - I didn't fancy saving a password in the browsers add-on preferences... Here's the file structure of the php backend for the plug in
/some/folder/not/in/web/space/backend
├── config.php
└── public
 └── index.php
only the 'public' subdirectory is symlinked to the web
/var/www/somefolder -> /some/folder/not/in/web/space/backend/public
so when you browse to www.yourdomain.com/somefolder your web server can only "see" index.php and if it falls off the rails it can never serve config.php as text (that's just one example of why to use this technique) All I'm doing in config.php is setting a "PDO" object I can use to access a specific MySQL database, just to be sure I make sure to clear all other variable at the end of config.php so $PDO is the only variable set. We wouldn't want some PHP error message the spew the contents of some variable like $password (because you never see that in the wild!!!) That leaves index.php where we simply sanitise the GET variable USER and return just a string representation of an integer... job done.... Now for the "good stuff" - first of all you need to install a neat little tool called jpm rather than reiterate their documentation, just pop along to the jpm documentation to learn how to install it... Having initialised your add-in I can walk you through some interesting parts, but first something that took quite a while to dig out of Mozilla's behemoth of a website... Low Level API's High Level API's Add ons SDK Maybe my StartPage FU wasn't so good that day but if those links save someone the pain then so much the better! Using the SDK is usually a case of including part of the sdk and usually setting a variable so you can reuse that part of the SDK easily in different parts of your code Take the code that creates a toolbar button
var buttons = require('sdk/ui/button/action');

var button1 = buttons.ActionButton({
  id: "freshcount-button",
  label: "FreshCount",
  icon: {
    "16": "./icon-16.png",
    "32": "./icon-32.png",
    "64": "./icon-64.png"
  },
  onClick: handleClick,
  badge: 0
});
You can see what's happening fairly easily from the parameter array but it's always as well to check the API doc Preferences are nicely handled, first in package.json just add a new array element
 "preferences": [
 {
 "name": "somePreference",
 "title": "the label",
 "description": "some explanation text.",
 "type": "string",
 "value": "default value"
 },
 {
 "name": "someOtherPreference",
now here's the nice part actually accessing the value, which is done through the name parameter ...
var prefs = require("sdk/simple-prefs").prefs;

// later on

function checkCount() {
  var Request = require("sdk/request").Request;
  
  var countRequest = Request({
    url: prefs.freshCountURL+"/?USER="+prefs.freshrssUser,
    onComplete: function (response) {
      if (!isNormalInteger(response.text)) {
        button1.badge = "ERROR";
      } else {
        button1.badge = response.text;
      }
    }
  });
  countRequest.get(); 
}
here my checkCount timer callback function fetches a value using values straight from the add-ons preferences, you might want to think about what if any sanitation is needed for these values, depending on the scenario the add-on is being used in. Just a quick note about the buttons badge property - basically you'll have seen buttons with tiny labels on them dynamically showing some kind of information - usually just a number... You can even have buttons in your preferences, in my case I decided to have a refresh button so you can test changes to the settings rather than having to wait until the timer next fires... In the end ignoring the thrashing around blindly for documentation, implementing an add-in was far less pain than it could be, and just ends up being a not terribly large, rather simple piece of JavaScript - which really is as it should be...