diff options
Diffstat (limited to 'bin/qutebrowser-cookiecleaner')
-rwxr-xr-x | bin/qutebrowser-cookiecleaner | 212 |
1 files changed, 212 insertions, 0 deletions
diff --git a/bin/qutebrowser-cookiecleaner b/bin/qutebrowser-cookiecleaner new file mode 100755 index 0000000..0aa06c1 --- /dev/null +++ b/bin/qutebrowser-cookiecleaner @@ -0,0 +1,212 @@ +#!/usr/bin/perl +# qutebrowser-cookiecleaner +# Copyright (C) Eskild Hustvedt 2018 +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +use 5.014; +use warnings; +use DBI; +use List::Util 1.33 qw(all); +use File::Basename qw(basename); +use Getopt::Long; +use File::Glob qw(bsd_glob); +use constant { + V_INFO => 1, +}; + +my $VERSION = 0.1; +my $verbosity = 0; +my $XDG_DATA_HOME = $ENV{XDG_DATA_HOME} ? $ENV{XDG_DATA_HOME} : $ENV{HOME}.'/.local/share'; +my $XDG_CONFIG_HOME = $ENV{XDG_CONFIG_HOME} ? $ENV{XDG_CONFIG_HOME} : $ENV{HOME}.'/.config'; + +# Output something in verbose mode +sub sayv +{ + my $level = shift; + if ($verbosity >= $level) + { + say(@_); + } +} + +# Retrieve a database handle +sub DBH +{ + my $dbfile = $XDG_DATA_HOME.'/qutebrowser/webengine/Cookies'; + if (!-e $dbfile) + { + die($dbfile.': does not exist'."\n"); + } + my $dbh = DBI->connect("dbi:SQLite:dbname=$dbfile",'',''); + + return $dbh; +} + +# Expire cookies, local storage, IndexedDB and databases, except those whitelisted +sub expireContent +{ + my $dbh = DBH(); + + my @statements; + my @exceptions; + my @whitelist; + + open(my $i,'<',$XDG_CONFIG_HOME.'/qutebrowser-cookiecleaner.list'); + my $no = 0; + while (my $line = <$i>) + { + $no++; + next if $line =~ /^\s*#/; + chomp($line); + if (index($line,'%') != -1) + { + die('Line '.$no.' contains forbidden character "%"'."\n"); + } + push(@exceptions,'%'.$line); + push(@statements,'host_key NOT LIKE ?'); + push(@whitelist,$line); + } + close($i); + + if(scalar @exceptions == 0) + { + die('Your qutebrowser-cookiecleaner.list file has no exceptions. Refusing to continue.'."\n"); + } + + # -- + # Cookies + # -- + + my $sth; + + my $deleteStatement = 'DELETE FROM cookies WHERE '.join(' AND ',@statements); + my $deletedEntriesStatement = 'SELECT * FROM cookies WHERE '.join(' AND ',@statements); + + # If verbose mode is on, we need more information, so fetch and output the + # entries we will delete. + if ($verbosity > 0) + { + $sth = $dbh->prepare($deletedEntriesStatement); + $sth->execute(@exceptions); + + while(my $entry = $sth->fetchrow_hashref) + { + sayv(V_INFO,'Deleting "'.$entry->{name}.'" for "'.$entry->{host_key}.'"'); + } + } + + $sth = $dbh->prepare($deleteStatement); + $sth->execute(@exceptions); + + $sth = $dbh->prepare('VACUUM;'); + $sth->execute(); + + $dbh->disconnect; + + # -- + # Localstorage + # -- + + my $localstorageDir = $XDG_DATA_HOME.'/qutebrowser/webengine/Local Storage/*.localstorage'; + + foreach my $file (bsd_glob($localstorageDir)) + { + if(all { index(basename($file),$_) == -1 } @whitelist ) + { + sayv(V_INFO,'Deleting Local Storage file '.basename($file)); + unlink($file); + if (-e $file.'-journal') + { + unlink($file.'-journal'); + } + } + } + + foreach my $dirEntry (qw(IndexedDB databases)) + { + my $dirsGlob = $XDG_DATA_HOME.'/qutebrowser/webengine/'.$dirEntry.'/*'; + + foreach my $dir (bsd_glob($dirsGlob)) + { + next if ! -d $dir; + if(all { index(basename($dir),$_) == -1 } @whitelist ) + { + sayv(V_INFO,'Deleting '.$dirEntry.' for '.basename($dir)); + unlink(bsd_glob($dir.'/*')) or die("Unlink error for subtree: $dir: $!\n"); + rmdir($dir) or die("Failed to rmdir $dir: $!\n"); + } + } + } +} + +# Main function. Command-line parsing. +sub main +{ + my $wrap = 0; + + GetOptions( + 'help' => sub { + say 'qutebrowser-cookiecleaner version '.$VERSION; + say ""; + say "Usage: qutebrowser-cookiecleaner [OPTIONS]"; + say ""; + say "Options:"; + say " -v, --verbose Increase verbosity"; + say " --help Show this help screen"; + say " --wrap Wrap another command, cleaning on start and"; + say " exit. See README.md for details."; + exit(0); + }, + 'wrap' => \$wrap, + 'version' => sub + { + print 'qutebrowser-cookiecleaner version '.$VERSION."\n"; + exit(0); + }, + 'v|verbose+' => \$verbosity, + ) or do + { + if ($wrap) + { + warn('Maybe you need to add -- after --wrap (--wrap --)?'."\n") + } + die('See --help for more information'."\n"); + }; + + + if ($wrap) + { + if(scalar @ARGV == 0) + { + die('--wrap requires additional parameters: the command to run'."\n"); + } + $0 = 'qutebrowser-cookiecleaner: cleaning'; + expireContent(); + $0 = 'qutebrowser-cookiecleaner: waiting for '.join(' ',@ARGV); + system(@ARGV); + if ($? == -1) + { + die('Failed to execute subprocess '.join(' ',@ARGV).': '.$!."\n"); + } + $0 = 'qutebrowser-cookiecleaner: cleaning'; + } + elsif(scalar @ARGV != 0) + { + die('Unknown parameters: '.join(' ',@ARGV)."\nDid you mean to use --wrap?\n"); + } + + expireContent(); +} + +main(); |