User Tools

Site Tools


Paranoid formfiller


This script can replace the one that comes with uzbl. It uses gpg to encrypt password files. As a bonus, it is able to submit few more forms than the original one.

Main script

This is the script that does the filling.


# a slightly more advanced form filler
# uses settings file like: $keydir/<domain>
#TODO: fallback to $HOME/.local/share
# user arg 1:
# edit: force editing of the file (fetches if file is missing)
# load: fill forms from file (fetches if file is missing)
# new:  fetch new file

# usage example:
# bind LL = spawn /usr/share/uzbl/examples/data/scripts/ load
# bind LN = spawn /usr/share/uzbl/examples/data/scripts/ new
# bind LE = spawn /usr/share/uzbl/examples/data/scripts/ edit

use strict;
use warnings;

my $keydir = $ENV{XDG_CONFIG_HOME} . "/uzbl/forms";
my ($fifoname, $url) = @ENV{qw(UZBL_FIFO UZBL_URI)};
my $cmd = $ARGV[0];
if (!defined $fifoname || $fifoname eq "") { die "No fifo"; }

sub domain {
  my ($url) = @_;
  $url =~ s#http(s)?://([A-Za-z0-9\.-]+)(/.*)?#$2#;
  return $url;

my @editor = ('xterm', '-e', $ENV{XDG_CONFIG_HOME}.'/uzbl/scripts/enc-vim');

# ideally, there would be some way to ask uzbl for the html content instead of having to redownload it with
#	Also, you may need to fake the user-agent on some sites (like facebook)
 my $downloader = "curl -k -A 'Mozilla/5.0 (X11; U; Linux i686; en-US; rv: Gecko/2009042810 GranParadiso/3.0.10' ";
#my $downloader = "curl -s";

my @fields = ("type","name","value");

my %command;

$command{load} = sub {
  my ($domain) = @_;
  my $filename = "$keydir/$domain";
  if (-e $filename){
    open(my $file, '-|', 'gpg', '--batch', '--no-tty', '-d', $filename) or die "Failed to open $filename: $!";
    my (@lines) = <$file>;
    my $active = 1;
    open(my $fifo, ">>", $fifoname) or die "Failed to open $fifoname: $!";
    foreach my $line (@lines) {
      next if ($line =~ m/^#/);
      if ($line =~ /^\s*>(.*\S)\s*$/) {
        $active = $url =~ /$1/;
      next unless $active;
      $line =~ s/@/\\@/g;
      my ($type,$name,$value) = ($line =~ /^\s*(\w*)\s*\|\s*(.*?)\s*\|\s*(.*?)\s*$/);
      if ($type eq "checkbox")
        printf $fifo 'js document.getElementsByName("%s")[0].checked = %s;'."\n", $name, $value;
      } elsif ($type eq "submit") {
        printf $fifo 'js try { document.getElementsByName("%s")[0].click(); } catch(err) { document.getElementById("%s").click(); }'."\n", $name, $name;
      } elsif ($type eq "form") {
        printf $fifo 'js try { document.getElementsByName("%s")[0].submit(); } catch(err) { document.getElementById("%s").submit(); }'."\n", $name, $name;
      } else {
        printf $fifo 'js document.getElementsByName("%s")[0].value = "%s";'."\n", $name, $value;
      print $fifo "\n";
$command{edit} = sub {
  my ($domain) = @_;
  my $file = "$keydir/$domain";
  if(-e $file){
    system (@editor, $file);
  } else {
$command{new} = sub {
  my ($domain) = @_;
  my $filename = "$keydir/$domain";
  open (my $file, '|-', 'gpg', '--batch', '--no-tty', '-aer', 'email@address', '--output', $filename) or die "Failed to open $filename: $!";
  print $file "# Make sure that there are no extra submits, since it may trigger the wrong one.\n";
  printf $file "#%-10s | %-10s | %s\n", @fields;
  print $file "#------------------------------\n";
  my @data = `$downloader $url`;
  foreach my $line (@data){
    if($line =~ m/<input ([^>].*?)>/i){
      $line =~ s/.*(<input ([^>].*?)>).*/$1/;
      printf $file " %-10s | %-10s | %s\n", map { my ($r) = $line =~ /.*$_=["'](.*?)["']/;$r } @fields;


Editation auxiliary script

This script is called from the main script to open the encrypted file in editor. Beware that it creates a temporary file with unencrypted content. Better have /tmp in a ramdisk.


set -ex

gpg -d <"$1" >"$FILE"
gpg -aer your@email "$FILE"
mv "$FILE.asc" "$1"
rm "$FILE"


First, make sure you gpg and gpg-agent are working, you have a key you can use for encryption.

Then, place both scripts somewhere. Then, edit the scripts. You need to set:

  • Your email address ‒ it is the address to encrypt to, it identifies gpg key to use (replace your@email in both scripts).
  • Check that you like the way the file is edited – eg. you like it to run in xterm (@editor variable in main script) and you like $EDITOR (the auxiliary script).
  • The auxiliary script is where the main script expects it (again, @editor variable).

After that, edit your config and replace the with this main script.


It acts almost the same as the original one, with few exceptions. First, it does not create files when first fill or edit is requested – you need to press LN beforehead. Second, it knows one more element type – form.

The usual work is like this:

  • Enter a page you were never before.
  • Press LN and LE. It creates a file with all the input elements it can find (which might be less or more than you can) and opens it for editation.
  • Delete all the elements you do not want to fill in, add values to the ones you want.
  • If you want the form to be auto-submitted, leave a submit or form element. The submit one is clicked, the form one submitted. They are matched by name, if it fails, then by id.
  • If you miss an element in the list, right-click it and inspect, enter its type, name and value.
  • Save
  • Press LL whenever you want to fill in the form.

GPG agent should do its work to ask for passphrase whenever needed.

Autologin on start

You can make uzbl fill in on the first visited page. It is useful if you call it with url of the login form (it looks really cool with some kind of bookmark app or launch shortcut, when you press something on keyboard, uzbl starts, loads the login page, auto-fills it and submits):

set ff_once = '@{formfiller} load' @on_event LOAD_FINISH chain \@ff_once 'set ff_once = '

(You could call it on each LOAD_FINISH, but I find it annoying, when uzbl fills in everything it comes across, I have it in separate wrapper config and call it only on the bookmarked ones)

paranoid-formfiller.txt · Last modified: 2016/08/31 14:10 (external edit)