keyring 0.1.0 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,79 @@
1
+ # keyring: System keyring abstraction library
2
+ # License: MIT (http://www.opensource.org/licenses/mit-license.php)
3
+
4
+ require 'slop'
5
+ require 'keyring'
6
+
7
+ class Keyring::CLI
8
+ def initialize(options={})
9
+ @options = options
10
+
11
+ @method = @arg = nil
12
+ @opts = Slop.parse(:help => true) do
13
+ banner 'Usage: keyring get|set|delete <service> <username> [password (for set)]'
14
+
15
+ on :v, :version, 'Print the version' do
16
+ puts Keyring::VERSION
17
+ exit
18
+ end
19
+
20
+ command 'set' do
21
+ # FIXME: option to prompt for password
22
+ run do |opts, args|
23
+ @method = :set
24
+ @arg = args
25
+ end
26
+ end
27
+ command 'get' do
28
+ run do |opts, args|
29
+ @method = :get
30
+ @arg = args
31
+ end
32
+ end
33
+ command 'delete' do
34
+ run do |opts, args|
35
+ @method = :delete
36
+ @arg = args
37
+ end
38
+ end
39
+ end
40
+ end
41
+
42
+ def main
43
+ if @method && respond_to?(@method)
44
+ send(@method, @arg)
45
+ else
46
+ puts @opts
47
+ exit 1
48
+ end
49
+ end
50
+
51
+ def set(args)
52
+ ensure_arg_presence(args, 3)
53
+ keyring = Keyring.new
54
+ keyring.set_password(args[0], args[1], args[2])
55
+ end
56
+ def get(args)
57
+ ensure_arg_presence(args, 2)
58
+ keyring = Keyring.new
59
+ puts keyring.get_password(args[0], args[1])
60
+ end
61
+ def delete(args)
62
+ ensure_arg_presence(args, 2)
63
+ keyring = Keyring.new
64
+ keyring.delete_password(args[0], args[1])
65
+ end
66
+
67
+ def ensure_arg_presence(args, count)
68
+ 0.upto(count-1) do |i|
69
+ if !args[i] || args[i].empty?
70
+ if !@options[:testing]
71
+ puts @opts
72
+ exit 1
73
+ else
74
+ raise ArgumentError
75
+ end
76
+ end
77
+ end
78
+ end
79
+ end
@@ -0,0 +1,6 @@
1
+ # keyring: System keyring abstraction library
2
+ # License: MIT (http://www.opensource.org/licenses/mit-license.php)
3
+
4
+ class Keyring
5
+ VERSION = "0.2.0"
6
+ end
@@ -0,0 +1,7 @@
1
+ # keyring: System keyring abstraction library
2
+ # License: MIT (http://www.opensource.org/licenses/mit-license.php)
3
+
4
+ module KeyringTestConstants
5
+ # Fake commands used in place of system commands
6
+ TESTCMDDIR = File.expand_path('testcmds', File.dirname(__FILE__))
7
+ end
@@ -0,0 +1,38 @@
1
+ # keyring: System keyring abstraction library
2
+ # License: MIT (http://www.opensource.org/licenses/mit-license.php)
3
+
4
+ require 'test/unit'
5
+ require 'keyring'
6
+
7
+ class KeyringBackendTests < Test::Unit::TestCase
8
+ def setup
9
+ @backend = Keyring::Backend.new
10
+ end
11
+
12
+ class Keyring::Backend::Test < Keyring::Backend; end
13
+ def test_register_implementation
14
+ Keyring::Backend.register_implementation(Keyring::Backend::Test)
15
+ assert Keyring::Backend.implementations.include?(Keyring::Backend::Test)
16
+ Keyring::Backend.implementations.delete(Keyring::Backend::Test)
17
+ end
18
+ def test_create
19
+ # This should be a bit more thorough
20
+ assert_kind_of Keyring::Backend, Keyring::Backend.create
21
+ end
22
+
23
+ def test_supported
24
+ refute @backend.supported?
25
+ end
26
+ def test_priority
27
+ assert_equal 0, @backend.priority
28
+ end
29
+ def test_set_password
30
+ assert_raises(NotImplementedError) {@backend.set_password('service', 'username', 'password')}
31
+ end
32
+ def test_get_password
33
+ assert_raises(NotImplementedError) {@backend.get_password('service', 'username')}
34
+ end
35
+ def test_delete_password
36
+ assert_raises(NotImplementedError) {@backend.delete_password('service', 'username')}
37
+ end
38
+ end
@@ -0,0 +1,73 @@
1
+ # keyring: System keyring abstraction library
2
+ # License: MIT (http://www.opensource.org/licenses/mit-license.php)
3
+
4
+ require File.expand_path('keyring_tests', File.dirname(__FILE__))
5
+ require 'test/unit'
6
+ require 'mocha/setup'
7
+ require 'keyring'
8
+
9
+ class KeyringBackendMacosxKeychainTests < Test::Unit::TestCase
10
+ include KeyringTestConstants
11
+
12
+ def setup
13
+ @backend = Keyring::Backend::MacosxKeychain.new
14
+ end
15
+
16
+ def test_supported
17
+ @backend.security = File.join(TESTCMDDIR, 'macosx/security-wronghelp')
18
+ refute @backend.supported?
19
+ @backend.security = File.join(TESTCMDDIR, 'macosx/bogus')
20
+ refute @backend.supported?
21
+ @backend.security = File.join(TESTCMDDIR, 'macosx/security-righthelp')
22
+ assert @backend.supported?
23
+ end
24
+ def test_priority
25
+ assert_equal 1, @backend.priority
26
+ end
27
+
28
+ def test_security_command
29
+ assert_equal 'add-generic-password', @backend.security_command('add')
30
+ assert_equal 'find-generic-password', @backend.security_command('find')
31
+ assert_equal 'delete-generic-password', @backend.security_command('delete')
32
+ end
33
+
34
+ def test_set_password
35
+ @backend.expects(:system).with(
36
+ '/usr/bin/security', 'add-generic-password', '-s', 'service', '-a', 'username', '-w', 'password', '-U')
37
+ # We need to set $? to make up for the fact that system was not actually run
38
+ # FIXME: surely there's a better way?
39
+ `true`
40
+ @backend.set_password('service', 'username', 'password')
41
+ end
42
+
43
+ def test_get_password
44
+ @backend.security = File.join(TESTCMDDIR, 'macosx/security-find')
45
+ assert_equal 'password', @backend.get_password('service', 'username')
46
+ end
47
+ def test_get_password_hex
48
+ @backend.security = File.join(TESTCMDDIR, 'macosx/security-findhex')
49
+ assert_equal "\0100\0101\0100\0101\0100\0101\0100\0101", @backend.get_password('service', 'hexuser')
50
+ end
51
+ def test_get_password_empty
52
+ @backend.security = File.join(TESTCMDDIR, 'macosx/security-findempty')
53
+ assert_equal '', @backend.get_password('service', 'emptyuser')
54
+ end
55
+ def test_get_password_notfound
56
+ @backend.security = File.join(TESTCMDDIR, 'macosx/security-notfound')
57
+ assert_nil @backend.get_password('bogus', 'bogus')
58
+ end
59
+
60
+ def test_delete_password_options
61
+ Open3.expects(:popen3).with(
62
+ '/usr/bin/security', 'delete-generic-password', '-s', 'service', '-a', 'username')
63
+ @backend.delete_password('service', 'username')
64
+ end
65
+ def test_delete_password_output
66
+ @backend.security = File.join(TESTCMDDIR, 'macosx/security-delete')
67
+ assert @backend.delete_password('service', 'gooduser')
68
+ end
69
+ def test_delete_password_errors
70
+ @backend.security = File.join(TESTCMDDIR, 'macosx/security-notfound')
71
+ refute @backend.delete_password('bogus', 'bogus')
72
+ end
73
+ end
@@ -0,0 +1,43 @@
1
+ # keyring: System keyring abstraction library
2
+ # License: MIT (http://www.opensource.org/licenses/mit-license.php)
3
+
4
+ require 'test/unit'
5
+ require 'keyring'
6
+
7
+ class KeyringBackendMemoryTests < Test::Unit::TestCase
8
+ def setup
9
+ @backend = Keyring::Backend::Memory.new
10
+ end
11
+
12
+ def test_supported
13
+ assert @backend.supported?
14
+ end
15
+ def test_priority
16
+ assert_equal 0.1, @backend.priority
17
+ end
18
+
19
+ def test_set_password
20
+ @backend.set_password('service', 'username', 'password')
21
+ assert_equal 'password', @backend.instance_variable_get('@keyring')['service']['username']
22
+ end
23
+ def test_get_password
24
+ @backend.set_password('service', 'username', 'password')
25
+ assert_equal 'password', @backend.get_password('service', 'username')
26
+
27
+ # Ensure that get_password behaves properly when asked for things that
28
+ # have not been set
29
+ assert_nil @backend.get_password('service', 'bogus')
30
+ assert_nil @backend.get_password('bogus', 'bogus')
31
+ end
32
+ def test_delete_password
33
+ @backend.set_password('service', 'username', 'password')
34
+ @backend.delete_password('service', 'username')
35
+ assert_nil @backend.instance_variable_get('@keyring')['service']['username']
36
+ assert_nil @backend.get_password('service', 'username')
37
+
38
+ # Ensure that delete_password behaves properly when asked to delete
39
+ # things that have not been set
40
+ @backend.delete_password('service', 'bogus')
41
+ @backend.delete_password('bogus', 'bogus')
42
+ end
43
+ end
@@ -0,0 +1,58 @@
1
+ # keyring: System keyring abstraction library
2
+ # License: MIT (http://www.opensource.org/licenses/mit-license.php)
3
+
4
+ require 'keyring/cli'
5
+ require 'test/unit'
6
+ require 'mocha/setup'
7
+
8
+ class KeyringCLITests < Test::Unit::TestCase
9
+ def setup
10
+ @cli = Keyring::CLI.new(testing: true)
11
+ end
12
+
13
+ EXE = File.expand_path('../bin/keyring', File.dirname(__FILE__))
14
+ def test_help_option
15
+ assert_match /\AUsage:/, `#{EXE} --help`
16
+ assert $?.success?
17
+ end
18
+ def test_version_option
19
+ assert_equal "#{Keyring::VERSION}\n", `#{EXE} --version`
20
+ assert $?.success?
21
+ end
22
+
23
+ def test_set
24
+ assert_raise(ArgumentError) {@cli.set([])}
25
+ assert_raise(ArgumentError) {@cli.set(['service'])}
26
+ assert_raise(ArgumentError) {@cli.set(['service', 'username'])}
27
+
28
+ Keyring.any_instance.expects(:set_password).with('service', 'username', 'password')
29
+ @cli.set(['service', 'username', 'password'])
30
+ end
31
+ def test_get
32
+ assert_raise(ArgumentError) {@cli.get([])}
33
+ assert_raise(ArgumentError) {@cli.get(['service'])}
34
+
35
+ Keyring.any_instance.expects(:get_password).with('service', 'username').returns('password')
36
+ $stdout = output = StringIO.new
37
+ @cli.get(['service', 'username'])
38
+ $stdout = STDOUT
39
+ assert_equal "password\n", output.string
40
+ end
41
+ def test_delete
42
+ assert_raise(ArgumentError) {@cli.delete([])}
43
+ assert_raise(ArgumentError) {@cli.delete(['service'])}
44
+
45
+ Keyring.any_instance.expects(:delete_password).with('service', 'username')
46
+ @cli.delete(['service', 'username'])
47
+ end
48
+
49
+ def test_ensure_arg_presence
50
+ assert_nothing_raised {@cli.ensure_arg_presence([], 0)}
51
+ assert_raise(ArgumentError) {@cli.ensure_arg_presence([], 1)}
52
+ assert_raise(ArgumentError) {@cli.ensure_arg_presence([''], 1)}
53
+
54
+ assert_nothing_raised {@cli.ensure_arg_presence(['a'], 1)}
55
+ assert_raise(ArgumentError) {@cli.ensure_arg_presence(['a'], 2)}
56
+ assert_raise(ArgumentError) {@cli.ensure_arg_presence(['a', ''], 2)}
57
+ end
58
+ end
@@ -0,0 +1,36 @@
1
+ # keyring: System keyring abstraction library
2
+ # License: MIT (http://www.opensource.org/licenses/mit-license.php)
3
+
4
+ require 'test/unit'
5
+ require 'mocha/setup'
6
+ require 'keyring'
7
+
8
+ class KeyringTests < Test::Unit::TestCase
9
+ def setup
10
+ @backend = Keyring::Backend::Memory.new
11
+ @keyring = Keyring.new(@backend)
12
+ end
13
+
14
+ def test_initialize
15
+ keyring = Keyring.new
16
+ assert_kind_of Keyring::Backend, keyring.instance_variable_get(:@backend)
17
+
18
+ backend = Keyring::Backend::Memory.new
19
+ keyring = Keyring.new(backend)
20
+ assert_equal backend, keyring.instance_variable_get(:@backend)
21
+ end
22
+
23
+ def test_get_password
24
+ @backend.expects(:get_password).with('service', 'username').returns('password')
25
+ password = @keyring.get_password('service', 'username')
26
+ assert_equal 'password', password
27
+ end
28
+ def test_set_password
29
+ @backend.expects(:set_password).with('service', 'username', 'password')
30
+ @keyring.set_password('service', 'username', 'password')
31
+ end
32
+ def test_delete_password
33
+ @backend.expects(:delete_password).with('service', 'username')
34
+ @keyring.delete_password('service', 'username')
35
+ end
36
+ end
@@ -0,0 +1 @@
1
+ 01010101
@@ -0,0 +1 @@
1
+ password:
@@ -0,0 +1 @@
1
+ ô%A���t;. u�@r
@@ -0,0 +1,27 @@
1
+ #!/bin/sh
2
+ # keyring: System keyring abstraction library
3
+ # License: MIT (http://www.opensource.org/licenses/mit-license.php)
4
+
5
+ cat <<-EOF
6
+ keychain: "/Users/jheiss/Library/Keychains/login.keychain"
7
+ class: "genp"
8
+ attributes:
9
+ 0x00000007 <blob>="service"
10
+ 0x00000008 <blob>=<NULL>
11
+ "acct"<blob>="username"
12
+ "cdat"<timedate>=0x32303133313132303233353532395A00 "20131120235529Z\000"
13
+ "crtr"<uint32>=<NULL>
14
+ "cusi"<sint32>=<NULL>
15
+ "desc"<blob>=<NULL>
16
+ "gena"<blob>=<NULL>
17
+ "icmt"<blob>=<NULL>
18
+ "invi"<sint32>=<NULL>
19
+ "mdat"<timedate>=0x32303133313132313232353534395A00 "20131121225549Z\000"
20
+ "nega"<sint32>=<NULL>
21
+ "prot"<blob>=<NULL>
22
+ "scrp"<sint32>=<NULL>
23
+ "svce"<blob>="service"
24
+ "type"<uint32>=<NULL>
25
+ EOF
26
+
27
+ printf "password has been deleted.\n" >&2
@@ -0,0 +1,26 @@
1
+ #!/bin/sh
2
+ # keyring: System keyring abstraction library
3
+ # License: MIT (http://www.opensource.org/licenses/mit-license.php)
4
+
5
+ cat <<-EOF
6
+ keychain: "/Users/example/Library/Keychains/login.keychain"
7
+ class: "genp"
8
+ attributes:
9
+ 0x00000007 <blob>="service"
10
+ 0x00000008 <blob>=<NULL>
11
+ "acct"<blob>="username"
12
+ "cdat"<timedate>=0x32303133313132303233353532395A00 "20131120235529Z\000"
13
+ "crtr"<uint32>=<NULL>
14
+ "cusi"<sint32>=<NULL>
15
+ "desc"<blob>=<NULL>
16
+ "gena"<blob>=<NULL>
17
+ "icmt"<blob>=<NULL>
18
+ "invi"<sint32>=<NULL>
19
+ "mdat"<timedate>=0x32303133313132313132343834315A00 "20131121124841Z\000"
20
+ "nega"<sint32>=<NULL>
21
+ "prot"<blob>=<NULL>
22
+ "scrp"<sint32>=<NULL>
23
+ "svce"<blob>="service"
24
+ "type"<uint32>=<NULL>
25
+ EOF
26
+ printf "password: \"password\"\n" >&2
@@ -0,0 +1,26 @@
1
+ #!/bin/sh
2
+ # keyring: System keyring abstraction library
3
+ # License: MIT (http://www.opensource.org/licenses/mit-license.php)
4
+
5
+ cat <<-EOF
6
+ keychain: "/Users/example/Library/Keychains/login.keychain"
7
+ class: "genp"
8
+ attributes:
9
+ 0x00000007 <blob>="service"
10
+ 0x00000008 <blob>=<NULL>
11
+ "acct"<blob>="emptyuser"
12
+ "cdat"<timedate>=0x32303133313132303233353532395A00 "20131120235529Z\000"
13
+ "crtr"<uint32>=<NULL>
14
+ "cusi"<sint32>=<NULL>
15
+ "desc"<blob>=<NULL>
16
+ "gena"<blob>=<NULL>
17
+ "icmt"<blob>=<NULL>
18
+ "invi"<sint32>=<NULL>
19
+ "mdat"<timedate>=0x32303133313132313132343834315A00 "20131121124841Z\000"
20
+ "nega"<sint32>=<NULL>
21
+ "prot"<blob>=<NULL>
22
+ "scrp"<sint32>=<NULL>
23
+ "svce"<blob>="service"
24
+ "type"<uint32>=<NULL>
25
+ EOF
26
+ printf "password: \n" >&2
@@ -0,0 +1,26 @@
1
+ #!/bin/sh
2
+ # keyring: System keyring abstraction library
3
+ # License: MIT (http://www.opensource.org/licenses/mit-license.php)
4
+
5
+ cat <<-EOF
6
+ keychain: "/Users/example/Library/Keychains/login.keychain"
7
+ class: "genp"
8
+ attributes:
9
+ 0x00000007 <blob>="service"
10
+ 0x00000008 <blob>=<NULL>
11
+ "acct"<blob>="hexuser"
12
+ "cdat"<timedate>=0x32303133313132303233353532395A00 "20131120235529Z\000"
13
+ "crtr"<uint32>=<NULL>
14
+ "cusi"<sint32>=<NULL>
15
+ "desc"<blob>=<NULL>
16
+ "gena"<blob>=<NULL>
17
+ "icmt"<blob>=<NULL>
18
+ "invi"<sint32>=<NULL>
19
+ "mdat"<timedate>=0x32303133313132313132343834315A00 "20131121124841Z\000"
20
+ "nega"<sint32>=<NULL>
21
+ "prot"<blob>=<NULL>
22
+ "scrp"<sint32>=<NULL>
23
+ "svce"<blob>="service"
24
+ "type"<uint32>=<NULL>
25
+ EOF
26
+ printf "password: 0x08300831083008310830083108300831 \"\0100\0101\0100\0101\0100\0101\0100\0101\"\n" >&2