keyring 0.1.0 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.gitignore +17 -0
- data/Gemfile +7 -0
- data/LICENSE +20 -0
- data/README.md +62 -70
- data/Rakefile +10 -15
- data/bin/keyring +12 -0
- data/keyring.gemspec +28 -0
- data/lib/keyring.rb +22 -13
- data/lib/keyring/backend.rb +42 -0
- data/lib/keyring/backends/macosx_keychain.rb +91 -0
- data/lib/keyring/backends/memory.rb +29 -0
- data/lib/keyring/cli.rb +79 -0
- data/lib/keyring/version.rb +6 -0
- data/test/keyring_tests.rb +7 -0
- data/test/test_backend.rb +38 -0
- data/test/test_backend_macosx_keychain.rb +73 -0
- data/test/test_backend_memory.rb +43 -0
- data/test/test_cli.rb +58 -0
- data/test/test_keyring.rb +36 -0
- data/test/testcmds/macosx/binary +1 -0
- data/test/testcmds/macosx/emptything +1 -0
- data/test/testcmds/macosx/random +1 -0
- data/test/testcmds/macosx/security-delete +27 -0
- data/test/testcmds/macosx/security-find +26 -0
- data/test/testcmds/macosx/security-findempty +26 -0
- data/test/testcmds/macosx/security-findhex +26 -0
- data/test/testcmds/macosx/security-notfound +6 -0
- data/test/testcmds/macosx/security-righthelp +51 -0
- data/test/testcmds/macosx/security-wronghelp +7 -0
- metadata +129 -59
- data/History.txt +0 -4
- data/lib/keyring/Keyring.rb +0 -95
- data/lib/keyring/SimpleKeyring.rb +0 -38
- data/spec/keyring_spec.rb +0 -129
- data/spec/spec_helper.rb +0 -15
- data/version.txt +0 -1
data/lib/keyring/cli.rb
ADDED
@@ -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,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
|
data/test/test_cli.rb
ADDED
@@ -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
|