From: bw1 Date: Sat, 14 Dec 2019 12:57:23 +0000 (+0100) Subject: [matryoshka] add matryoshka.pl X-Git-Url: http://git.99rst.org/?a=commitdiff_plain;h=b8adfe680579e44c6cbc51f3a8b17a44000e6b6b;p=irssi-scripts.irssi.org.git [matryoshka] add matryoshka.pl --- diff --git a/scripts/matryoshka.pl b/scripts/matryoshka.pl new file mode 100644 index 0000000..c1f6ab6 --- /dev/null +++ b/scripts/matryoshka.pl @@ -0,0 +1,336 @@ +use strict; +use vars qw($VERSION %IRSSI); + +use Irssi; +use Storable qw/freeze thaw/; +use Compress::Zlib; +use Crypt::CBC; +use Crypt::Cipher::AES; +use File::Glob ':bsd_glob'; +use CPAN::Meta::YAML; + +$VERSION = '0.01'; +%IRSSI = ( + authors => 'bw1', + contact => 'bw1@aol.at', + name => 'matryoshka', + description => 'a password matryoshka', + license => 'Public Domain', + url => 'https://scripts.irssi.org/', + changed => '2019-12-03', + modules => 'Storable Compress::Zlib Crypt::CBC Crypt::Cipher::AES File::Glob '. + 'CPAN::Meta::YAML', + commands=> 'matryoshka', +); + +my $help = << "END"; +%9Name%9 + $IRSSI{name} +%9Version%9 + $VERSION +%9description%9 + $IRSSI{description} +%9example%9 + /matryoshka expando add mynet /msg -mynet nickserv IDENTIFY account password + /network add -autosendcmd '\$mynet' mynet + + /matryoshka startup add /connect ircserver port password nick +%9Settings%9 + %Umatryoshka_file%U + %Umatryoshka_key%U + %Umatryoshka_key_file%U +%9Commands%9 + %Usave%U + %Udump%U + %Uexpando%U + list + add + remove + update + %Ustartup%U + list + add + remove + run + %Uhelp%U +%9Warning%9 + The passwords are not save in this store! +END + +my ($matryoshka_file, $matryoshka_key, $matryoshka_key_file); +my $db; +my $change=0; +my $key; +my %expandos; +my %expandosf; + +sub cmd { + my ($args, $server, $witem)=@_; + my @args = split /\s+/,$args; + my $arg = shift @args; + my $cmd=0; + if ( $arg eq 'save') { + $change=1; + savekeyfile(); + savefile(); + $cmd++; + } + if ( $arg eq 'dump') { + cmd_dump($server, $witem, @args); + $cmd++; + } + if ( $arg eq 'expando' ) { + scmd_expando($server, $witem, @args); + $cmd++; + } + if ( $arg eq 'startup' ) { + scmd_startup($server, $witem, @args); + $cmd++; + } + if ( $arg eq 'help' || $cmd == 0 ) { + Irssi::print($help, MSGLEVEL_CLIENTCRAP); + } +} + +sub scmd_startup { + my ($server, $witem, @args)=@_; + my $arg= shift @args; + if ($arg eq 'list') { + sscmd_s_list($server, $witem, @args); + } + if ($arg eq 'add') { + sscmd_s_add($server, $witem, @args); + } + if ($arg eq 'remove') { + sscmd_s_remove($server, $witem, @args); + } + if ($arg eq 'run') { + startup_run(); + } +} + +sub sscmd_s_list { + my ($server, $witem, @args)=@_; + if (exists $db->{startup} ) { + my $c=1; + foreach (@{$db->{startup}}) { + Irssi::printformat(MSGLEVEL_CLIENTCRAP, 'startup_theme', + $c, $_ ); + $c++; + } + } +} + +sub sscmd_s_add { + my ($server, $witem, @args)=@_; + if (!exists $db->{startup} ) { + $db->{startup}=[]; + } + push @{$db->{startup}}, join(" ", @args); + $change=1; +} + +sub sscmd_s_remove { + my ($server, $witem, @args)=@_; + my $ex= shift @args; + splice @{$db->{startup}}, $ex-1, 1; + $change=1; +} + +sub startup_run { + if (exists $db->{startup} ) { + foreach (@{$db->{startup}}) { + Irssi::command($_); + } + } +} + +sub scmd_expando { + my ($server, $witem, @args)=@_; + my $arg= shift @args; + if ($arg eq 'list') { + sscmd_e_list($server, $witem, @args); + } + if ($arg eq 'add') { + sscmd_e_add($server, $witem, @args); + } + if ($arg eq 'remove') { + sscmd_e_remove($server, $witem, @args); + } + if ($arg eq 'update') { + updateexpandos(); + } +} + +sub sscmd_e_list { + my ($server, $witem, @args)=@_; + if (exists $db->{expando} ) { + foreach (sort keys %{$db->{expando}}) { + Irssi::printformat(MSGLEVEL_CLIENTCRAP, 'expando_theme', + $_, $db->{expando}->{$_}); + } + } +} + +sub sscmd_e_add { + my ($server, $witem, @args)=@_; + if (!exists $db->{expando} ) { + $db->{expando}={}; + } + my $ex= shift @args; + $db->{expando}->{$ex}= join " ", @args; + $change=1; +} + +sub sscmd_e_remove { + my ($server, $witem, @args)=@_; + my $ex= shift @args; + delete $db->{expando}->{$ex}; + $change=1; +} + +sub cmd_dump { + my ($server, $witem, @args)=@_; + my $yml= CPAN::Meta::YAML->new; + push @$yml, $db; + print $yml->write_string; +} + +sub cmd_help { + my ($args, $server, $witem)=@_; + $args=~ s/\s+//g; + if ($IRSSI{name} eq $args) { + Irssi::print($help, MSGLEVEL_CLIENTCRAP); + Irssi::signal_stop(); + } +} + +sub loadfile { + my $fn= filename($matryoshka_file); + if ( -e $fn) { + my ($serial, $comp, $cyper); + open my $fi, '<', $fn; + local $/; + $cyper= <$fi>; + close $fi; + my $cbc2 = Crypt::CBC->new( -cipher=>'Cipher::AES', -key=>$key ); + my $cyper2 = $cbc2->decrypt($cyper); + my $cbc = Crypt::CBC->new( -cipher=>'Cipher::AES', -key=>$matryoshka_key ); + $comp = $cbc->decrypt($cyper2); + $serial= uncompress( $comp ); + $db= thaw($serial); + $change=0; + } +} + +sub savefile { + my $fn= filename($matryoshka_file); + my $serial= freeze( $db ); + my $comp; + if ($change != 0) { + $comp= compress( $serial, 9 ); + my $cbc = Crypt::CBC->new( -cipher=>'Cipher::AES', -key=>$matryoshka_key); + my $ciphertext = $cbc->encrypt($comp); + my $cbc2 = Crypt::CBC->new( -cipher=>'Cipher::AES', -key=>$key); + my $ciphertext2 = $cbc2->encrypt($ciphertext); + open my $fa, '>', $fn; + print $fa $ciphertext2; + close $fa; + } +} + +sub loadkeyfile { + my $fn= filename($matryoshka_key_file); + if (-e $fn) { + open my $fi, '<', $fn; + local $/; + $key= <$fi>; + close $fi; + } else { + savekeyfile(); + } +} + +sub savekeyfile { + my $fn= filename($matryoshka_key_file); + $key= Crypt::CBC->random_bytes(16); + $change=1; + open my $fa, '>', $fn; + print $fa $key; + close $fa; +} + +sub filename { + my ($fn)= @_; + if ($fn !~ m#/#) { + $fn= Irssi::get_irssi_dir().'/'.$fn; + } else { + $fn= bsd_glob($fn); + } + return $fn; +} + +sub updateexpandos { + foreach (keys %{$db->{expando}}) { + if (!defined $expandos{$_}) { + my $fustr = '$expandosf{'.$_.'}= sub { return "'. $db->{expando}->{$_}.'";}'; + eval($fustr); + Irssi::expando_create $_, $expandosf{$_}, { }; + $expandos{$_}=2; + } else { + $expandos{$_}=2; + } + } + foreach (keys %expandos) { + if ( $expandos{$_} == 1) { + delete $expandos{$_}; + Irssi::expando_destroy $_; + } else { + $expandos{$_}=1; + } + } +} + +sub sig_setup_changed { + $matryoshka_file= Irssi::settings_get_str($IRSSI{name}.'_file'); + $matryoshka_key= Irssi::settings_get_str($IRSSI{name}.'_key'); + if ( $matryoshka_key eq '' ) { + $matryoshka_key= Crypt::CBC->random_bytes(16); + Irssi::settings_set_str($IRSSI{name}.'_key', $matryoshka_key); + $change=1; + } + $matryoshka_key_file= Irssi::settings_get_str($IRSSI{name}.'_key_file'); +} + +sub UNLOAD { + savefile(); +} + +Irssi::theme_register([ + 'expando_theme', '{hilight $0} $1', + 'startup_theme', '{hilight $0} $1', +]); + +Irssi::signal_add('setup changed', \&sig_setup_changed); + +Irssi::settings_add_str($IRSSI{name} ,$IRSSI{name}.'_file', 'matryoshka.store'); +Irssi::settings_add_str($IRSSI{name} ,$IRSSI{name}.'_key', ''); +Irssi::settings_add_str($IRSSI{name} ,$IRSSI{name}.'_key_file', '.matryoshka.key.file'); + +Irssi::command_bind($IRSSI{name}, \&cmd); +foreach ( qw/save dump expando startup/ ){ + Irssi::command_bind($IRSSI{name}.' '.$_, \&cmd); +} +foreach ( qw/list add remove update/ ){ + Irssi::command_bind($IRSSI{name}.' expando '.$_, \&cmd); +} +foreach ( qw/list add remove run/ ){ + Irssi::command_bind($IRSSI{name}.' startup '.$_, \&cmd); +} +Irssi::command_bind('help', \&cmd_help); + +sig_setup_changed(); +loadkeyfile(); +loadfile(); +updateexpandos(); +startup_run();