Anonymous avatar Anonymous committed 164b6e1

preliminary impl, set and get password more or less work

Comments (0)

Files changed (5)

experiments/kwallet_by_dbus.pl

 }; if($@) {
     say "Got error while reading password from closed wallet: $@";
 }
+
+say "Spawn  kwalletmanager  to check what is going on";

lib/Passwd/Keyring/KDEWallet.pm

 use strict;
 #use parent 'Keyring';
 use Net::DBus;
+use Carp;
 
 =head1 NAME
 
 
     use Passwd::Keyring::KDEWallet;
 
-    my $keyring = Passwd::Keyring::KDEWallet->new();
+    my $keyring = Passwd::Keyring::KDEWallet->new(app=>"My beautiful app", group=>"My app web passwords");
 
     $keyring->set_password("John", "verysecret", "my-pseudodomain");
     # And later, on next run maybe
 =cut
 
 sub new {
+    my ($cls, %args) = @_;
+
     my $self = {};
+    $self->{app} = $args{app} || 'Passwd::Keyring::KDEWallet';
+    $self->{group} = $args{group} || 'Passwd::Keyring::default';
     bless $self;
 
-    # TODO: maybe some of those objects should rather be
-    # created on demand and thrown away immediately.
-
     #$self->{bus} = Net::DBus->find()
     $self->{bus} = Net::DBus->session()
       or croak("KWallet not available (can't access DBus)");
-    $self->{kwallet_svc} = $self->{bus}->get_service('org.kde.kwalletd')
+    my $kwallet_svc = $self->{bus}->get_service('org.kde.kwalletd')
       or croak("KWallet not available (can't access KWallet, likely kwalletd not running)");
-    my $kwallet = $self->{kwallet_svc}->get_object('/modules/kwalletd', 'org.kde.KWallet')
+    $self->{kwallet} = $kwallet_svc->get_object('/modules/kwalletd', 'org.kde.KWallet')
       or croak("Kwallet not available (can't find wallet)");
+    $self->_open_if_not_open();
 
-    use Data::Dumper;
-    print Dumper($kwallet);
-
-    $self->{kwallet} = $kwallet->networkWallet();
-    print Dumper($self->{kwallet});
-    print "Wallet = $self->{kwallet}\n";
-
-    # TODO: later
-    my $kwallet_handle = $self->{kwallet}->open($self->{kwallet}, 0, $APP_NAME);
-    print "Opened = $kwallet_handle\n";
-
-    my $folders = $self->{kwallet}->folderList($kwallet_handle, $APP_NAME);
-    print "Folders = ", dump($folders);
+    unless($self->{kwallet}->hasFolder($self->{handle}, $self->{group}, $self->{app})) {
+        $self->{kwallet}->createFolder($self->{handle}, $self->{group}, $self->{app})
+          or croak("Failed to create $self->{group} folder (app $self->{app})");
+    }
 
     return $self;
 }
 
+sub _open_if_not_open {
+    my $self = shift;
+
+    if($self->{handle}) {
+        if($self->{kwallet}->isOpen($self->{handle})) {
+            return;
+        }
+    }
+    my $net_wallet = $self->{kwallet}->networkWallet()
+      or croak("Kwallet not available (can't access network wallet");
+    $self->{handle} = $self->{kwallet}->open($net_wallet, 0, $self->{app})
+      or croak("Failed to open the KDE wallet");
+}
+
 =head2 set_password(username, password, domain)
 
 Sets (stores) password identified by given domain for given user 
 
 sub set_password {
     my ($self, $user_name, $user_password, $domain) = @_;
+    $self->_open_if_not_open();
+    my $status = $self->{kwallet}->writePassword(
+        $self->{handle}, $self->{group}, "$domain || $user_name", $user_password, $self->{app});
+    if($status) { # non-zero means failure
+        croak("Failed to save the password (status $status, user name $user_name, domain $domain, handle $self->{handle}, group $self->{group})");
+    }
 }
 
 =head2 get_password($user_name, $domain)
 
 sub get_password {
     my ($self, $user_name, $domain) = @_;
-#    my $pwd = $KWallet->readPassword($kwallet_handle, 'MyFolder','Some_Userid_Key', $APP_NAME);
-#    print "Password = ", dump($pwd), "\n";
+    $self->_open_if_not_open();
+    my $reply = $self->{kwallet}->readPassword(
+        $self->{handle}, $self->{group}, "$domain || $user_name", $self->{app});
+    return $reply;
 }
 
 =head2 clear_password($user_name, $domain)
     my ($self, $user_name, $domain) = @_;
 }
 
+=head2 is_persistent
+
+Returns info, whether this keyring actually saves passwords persistently.
+
+(true in this case)
+
+=cut
+
+sub is_persistent {
+    my ($self) = @_;
+    return 1;
+}
+
 =head1 AUTHOR
 
 Marcin Kasperski, C<< <Marcin.Kasperski at mekk.waw.pl> >>
 }
 
 diag( "Testing Passwd::Keyring::KDEWallet $Passwd::Keyring::KDEWallet::VERSION, Perl $], $^X" );
+diag( "Consider spawning  kwalletmanager  to check whether some passwords remained uncleared" );

t/01-set-and-get.t

 
 use strict;
 use warnings;
-use Test::Simple tests => 5;
+use Test::Simple tests => 8;
 
 use Passwd::Keyring::KDEWallet;
 
 ok( $ring->clear_password($USER, 'my@@domain') eq 1, "clear_password removed one password" );
 
 ok( !defined($ring->get_password($USER, 'my@@domain')), "no password after clear");
+
+ok( $ring->clear_password($USER, 'my@@domain') eq 0, "clear_password again has nothing to clear" );
+
+ok( $ring->clear_password("Non user", 'my@@domain') eq 0, "clear_password for unknown user has nothing to clear" );
+ok( $ring->clear_password("$USER", 'non domain') eq 0, "clear_password for unknown domain has nothing to clear" );

t/06-recovering-with-app-change.t

 
 use strict;
 use warnings;
-#use Test::More tests => 11;
-use Test::More skip_all => "Currently app and group are meaningful. To be decided whether to keep this behaviour";
+use Test::More tests => 16;
 
 use Passwd::Keyring::KDEWallet;
 
 my $USER = "Herakliusz";
 my $DOMAIN = "test domain";
 my $PWD = "arcytajne haslo";
+my $PWD2 = "inny sekret";
 
-my $orig_ring = Passwd::Keyring::KDEWallet->new(app=>"Passwd::Keyring::Unit tests", group=>"Yet so");
+my $APP1 = "Passwd::Keyring::Unit tests (1)";
+my $APP2 = "Passwd::Keyring::Unit tests (2)";
+my $GROUP1 = "Passwd::Keyring::Unit tests - group 1";
+my $GROUP2 = "Passwd::Keyring::Unit tests - group 2";
+my $GROUP3 = "Passwd::Keyring::Unit tests - group 3";
 
-ok( defined($orig_ring) && ref $orig_ring eq 'Passwd::Keyring::KDEWallet',   'new() works' );
+my @cleanups;
 
-ok( ! defined($orig_ring->get_password($USER, $DOMAIN)), "initially unset");
+{
+    my $ring = Passwd::Keyring::KDEWallet->new(app=>$APP1, group=>$GROUP1);
 
-$orig_ring->set_password($USER, $PWD, $DOMAIN);
-ok(1, "set password");
+    ok( defined($ring) && ref $ring eq 'Passwd::Keyring::KDEWallet',   'new() works' );
 
-ok( $orig_ring->get_password($USER, $DOMAIN) eq $PWD, "normal get works");
+    ok( ! defined($ring->get_password($USER, $DOMAIN)), "initially unset");
 
+    $ring->set_password($USER, $PWD, $DOMAIN);
+    ok(1, "set password");
 
-# Another object with the same app/group
+    ok( $ring->get_password($USER, $DOMAIN) eq $PWD, "normal get works");
 
-my $ring = Passwd::Keyring::KDEWallet->new(app=>"Passwd::Keyring::Unit tests", group=>"Yet so");
+    push @cleanups, sub {
+        ok( $ring->clear_password($USER, $DOMAIN) eq 1, "clearing");
+    };
+}
 
-ok( defined($ring) && ref $ring eq 'Passwd::Keyring::KDEWallet', 'second new() works' );
 
-ok( $ring->get_password($USER, $DOMAIN) eq $PWD, "get from another ring with the same data works");
+# Another object with the same app and group
+
+{
+    my $ring = Passwd::Keyring::KDEWallet->new(app=>$APP1, group=>$GROUP1);
+
+    ok( defined($ring) && ref $ring eq 'Passwd::Keyring::KDEWallet', 'second new() works' );
+
+    ok( $ring->get_password($USER, $DOMAIN) eq $PWD, "get from another ring with the same data works");
+}
+
+# Only app changes
+{
+    my $ring = Passwd::Keyring::KDEWallet->new(app=>$APP2, group=>$GROUP1);
+
+    ok( defined($ring) && ref $ring eq 'Passwd::Keyring::KDEWallet', 'third new() works' );
+
+    ok( $ring->get_password($USER, $DOMAIN) eq $PWD, "get from another ring with changed app but same group works");
+}
 
 # Only group changes
+my $sec_ring;
+{
+    my $ring = Passwd::Keyring::KDEWallet->new(app=>$APP1, group=>$GROUP2);
 
-$ring = Passwd::Keyring::KDEWallet->new(app=>"Passwd::Keyring::Unit tests", group=>"It has changed");
+    ok( defined($ring) && ref $ring eq 'Passwd::Keyring::KDEWallet', 'third new() works' );
 
-ok( defined($ring) && ref $ring eq 'Passwd::Keyring::KDEWallet', 'third new() works' );
+    ok( ! defined($ring->get_password($USER, $DOMAIN)), "changing group forces another password");
 
-ok( $ring->get_password($USER, $DOMAIN) eq $PWD, "get from another ring with different group works");
+    # To test whether original won't be spoiled
+    $ring->set_password($USER, $PWD2, $DOMAIN);
+
+    push @cleanups, sub {
+        ok( $ring->clear_password($USER, $DOMAIN) eq 1, "clearing");
+    };
+}
 
 # App and group change
+{
+    my $ring = Passwd::Keyring::KDEWallet->new(app=>$APP2, group=>$GROUP3);
 
-$ring = Passwd::Keyring::KDEWallet->new(app=>"Something else", group=>"Yet Yet so");
+    ok( defined($ring) && ref $ring eq 'Passwd::Keyring::KDEWallet', 'third new() works' );
 
-ok( defined($ring) && ref $ring eq 'Passwd::Keyring::KDEWallet', 'fourth new() works' );
+    ok( ! defined($ring->get_password($USER, $DOMAIN)), "changing group and app forces another password");
 
-ok( $ring->get_password($USER, $DOMAIN) eq $PWD, "get from another ring with changed app and group works");
+}
 
+# Re-reading original to check whether it was properly kept
+{
+    my $ring = Passwd::Keyring::KDEWallet->new(app=>$APP1, group=>$GROUP1);
+
+    ok( defined($ring) && ref $ring eq 'Passwd::Keyring::KDEWallet', 'second new() works' );
+
+    ok( $ring->get_password($USER, $DOMAIN) eq $PWD, "get original after changes in other group works");
+}
 
 # Cleanup
-ok( $orig_ring->clear_password($USER, $DOMAIN) eq 1, "clearing");
+foreach my $cleanup (@cleanups) {
+    $cleanup->();
+}
 
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.