costan-zerg_support 0.0.9

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.
@@ -0,0 +1,185 @@
1
+ #:nodoc:
2
+ module Zerg::Support::Process
3
+ # perhaps this should be merged in process
4
+ end
5
+
6
+ if RUBY_PLATFORM =~ /win/ and RUBY_PLATFORM !~ /darwin/
7
+ require 'win32/process'
8
+
9
+ #:nodoc: all
10
+ module Zerg::Support::Process
11
+ def self.spawn(binary, args = [], options = {})
12
+ # command line processing
13
+ command_line = '"' + binary + '" "' +
14
+ args.map { |a| a.gsub '"', '""' }.join('" "') + '"'
15
+
16
+ # environment processing
17
+ environment_string = nil
18
+ if options[:env]
19
+ if options[:unsetenv_others]
20
+ environment = options[:env]
21
+ else
22
+ environment = Hash.new.merge(ENV).merge(options[:env])
23
+ end
24
+ environment_string = environment.keys.sort.
25
+ map { |k| "#{k}=#{environment[k]}" }.join "\0"
26
+ environment_string << "\0"
27
+ end
28
+
29
+ # redirection processing
30
+ startup_info = {}
31
+ files = {}
32
+ stream_files = {}
33
+ deferred_opens = []
34
+ [[STDIN, :stdin], [STDOUT, :stdout], [STDERR, :stderr]].each do |pair|
35
+ next unless options[pair.first]
36
+ if options[pair.first].kind_of? String
37
+ filename = options[pair.first]
38
+ files[filename] ||= File.open(filename,
39
+ (pair.last == :stdin) ? 'r' : 'w+')
40
+ startup_info[pair.last] = files[filename]
41
+ stream_files[pair.first] = files[filename]
42
+ else
43
+ deferred_opens << Kernel.proc do
44
+ io = stream_files[options[pair.first]] || pair.first
45
+ startup_info[pair.last] = stream_files[pair.first] = io
46
+ end
47
+ end
48
+ end
49
+ deferred_opens.each { |d| d.call }
50
+
51
+ # process leader
52
+ creation_flags = 0
53
+ if options[:pgroup]
54
+ creation_flags |= Process::DETACHED_PROCESS
55
+ if options[:pgroup].kind_of? Numeric and options[:pgroup] > 0
56
+ # TODO: what now?
57
+ else
58
+ creation_flags |= Process::CREATE_NEW_PROCESS_GROUP
59
+ end
60
+ end
61
+
62
+ info = Process.create :command_line => command_line,
63
+ :cwd => options[:chdir] || Dir.pwd,
64
+ :environment => environment_string,
65
+ :creation_flags => creation_flags,
66
+ :startup_info => startup_info
67
+ files.each { |name, io| io.close }
68
+
69
+ return info[:process_id]
70
+ end
71
+ end
72
+
73
+ else
74
+
75
+ #:nodoc:
76
+ module Zerg::Support::Process
77
+ # Spawns a new process and returns its pid immediately.
78
+ # Like Kernel.spawn in ruby1.9, except that the environment is passed
79
+ # as an option with the key :env
80
+ def self.spawn(binary, args = [], options = {})
81
+ if Kernel.respond_to? :spawn
82
+ # ruby1.9+: spawn!
83
+ options = options.dup
84
+ env = options.delete(:env)
85
+ Kernel.spawn *([env, binary] + args + [options])
86
+ else
87
+ # below 1.9: emulate
88
+
89
+ # chdir option
90
+ Dir.chdir options[:chdir] if options[:chdir]
91
+
92
+ child_pid = fork do
93
+ Helpers.do_redirects options
94
+ Helpers.close_fds options
95
+ Helpers.set_process_group options
96
+ Helpers.set_environment options
97
+ Helpers.set_rlimits options
98
+
99
+ Kernel.exec *([binary] + args)
100
+ end
101
+ end
102
+
103
+ return child_pid
104
+ end
105
+ end
106
+ end
107
+
108
+ # Helpers for spawning processes.
109
+ module Zerg::Support::Process::Helpers
110
+ # Closes all open file descriptors except for stdin/stdout/stderr
111
+ def self.close_fds(options)
112
+ return if options[:close_others] == false
113
+
114
+ ObjectSpace.each_object(IO) do |io|
115
+ next if [STDIN, STDOUT, STDERR].include? io
116
+
117
+ begin
118
+ io.close unless io.closed?
119
+ rescue Exception
120
+ end
121
+ end
122
+ end
123
+
124
+ # Sets process limits (rlimits) according to the given options. The options
125
+ # follow the convention of Kernel.spawn in ruby1.9
126
+ def self.set_rlimits(options)
127
+ # rlimit options
128
+ options.each do |k, v|
129
+ next unless k.kind_of? Symbol and k.to_s[0, 7] == 'rlimit_'
130
+ rconst = Process.const_get k.to_s.upcase.to_sym
131
+ if v.kind_of? Enumerable
132
+ Process.setrlimit rconst, v.first, v.last
133
+ else
134
+ Process.setrlimit rconst, v
135
+ end
136
+ end
137
+ end
138
+
139
+ # Sets the process' group according to the given options. The options
140
+ # follow the convention of Kernel.spawn in ruby1.9
141
+ def self.set_process_group(options)
142
+ return unless options[:pgroup]
143
+
144
+ if options[:pgroup].kind_of? Numeric and options[:pgroup] > 0
145
+ Process.setpgid 0, options[:pgroup]
146
+ else
147
+ Process.setsid
148
+ end
149
+ end
150
+
151
+ # Sets the process' environment according to the given options. The options
152
+ # follow the convention of Kernel.spawn in ruby1.9
153
+ def self.set_environment(options)
154
+ return unless options[:env]
155
+
156
+ ENV.clear if options[:unsetenv_others]
157
+ options[:env].each do |key, value|
158
+ ENV[key] = value
159
+ end
160
+ end
161
+
162
+ # Performs IO redirections according to the given options. The options
163
+ # follow the convention of Kernel.spawn in ruby1.9
164
+ def self.do_redirects(options)
165
+ redirected_files = {}
166
+ file_redirects = []
167
+ fd_redirects = []
168
+ options.each do |key, value|
169
+ next unless key.kind_of? IO
170
+ if value.kind_of? String
171
+ if redirected_files[value]
172
+ fd_redirects << [key, redirected_files[value]]
173
+ else
174
+ file_redirects << [key, value]
175
+ redirected_files[value] = key
176
+ end
177
+ else
178
+ fd_redirects << [key, value]
179
+ end
180
+ end
181
+ (file_redirects + fd_redirects).each do |r|
182
+ r.first.reopen r.last
183
+ end
184
+ end
185
+ end
@@ -0,0 +1,21 @@
1
+ # :nodoc
2
+ module Zerg
3
+ end
4
+
5
+ # TODO(victor): document this
6
+ module Zerg::Support
7
+ end
8
+
9
+ require 'rubygems'
10
+ require 'zerg_support/gems.rb'
11
+ require 'zerg_support/process.rb'
12
+ require 'zerg_support/open_ssh.rb'
13
+ require 'zerg_support/spawn.rb'
14
+
15
+ # TODO(victor): document this
16
+ module Zerg::Support::EventMachine
17
+ end
18
+
19
+ require 'zerg_support/event_machine/connection_mocks.rb'
20
+ require 'zerg_support/event_machine/frame_protocol.rb'
21
+ require 'zerg_support/event_machine/object_protocol.rb'
data/test/fork_tree.rb ADDED
@@ -0,0 +1,34 @@
1
+ # Used in test_process.rb to produce a tree of children.
2
+ # Usage:
3
+ # ruby test/fork_tree.rb level interval cookie
4
+ # Arguments:
5
+ # level - the fork level; 0 means don't fork, otherwise fork two children
6
+ # with fork level-1
7
+ # interval - the time to sleep (in seconds)
8
+ # cookie - an argument that's preserved to help track down the process
9
+ # also, the PID will be written to cookie.pid unless the file already
10
+ # exists (this means that only the fork tree's root writes it)
11
+
12
+ require 'English'
13
+
14
+ # extract arguments
15
+ level = ARGV[1].to_i
16
+ interval = ARGV[2].to_f
17
+ cookie = ARGV[3]
18
+
19
+ # write PID file
20
+ pid_file = cookie + ".pid"
21
+ unless File.exist? pid_file
22
+ File.open(pid_file, "w") { |f| f.write $PID.to_s }
23
+ end
24
+
25
+ # spawn children
26
+ unless level == 0
27
+ 2.times do
28
+ Thread.new do
29
+ system "ruby test/fork_tree.rb -- #{level - 1} #{interval} #{cookie}"
30
+ end
31
+ end
32
+ end
33
+
34
+ sleep interval
@@ -0,0 +1,57 @@
1
+ require 'test/unit'
2
+
3
+ require 'zerg_support'
4
+
5
+ require 'rubygems'
6
+ require 'flexmock/test_unit'
7
+
8
+ class HollowReceiveMock < Zerg::Support::EventMachine::ReceiveMock
9
+ end
10
+
11
+ # Collects groups of 3 letters, stores them into idenity hashes.
12
+ class ReceiveFooMock < Zerg::Support::EventMachine::ReceiveMock
13
+ object_name :foo
14
+
15
+ def receive_data(data)
16
+ @s ||= ''
17
+ data.each_byte do |c|
18
+ @s << c
19
+ if @s.length == 3
20
+ receive_foo @s => @s
21
+ @s = ''
22
+ end
23
+ end
24
+ end
25
+ end
26
+
27
+ class ConnectionMocksTest < Test::Unit::TestCase
28
+ def test_send_mock
29
+ send_mock = Zerg::Support::EventMachine::SendMock.new
30
+ assert_equal send_mock.string, ''
31
+
32
+ send_mock.send_data('a')
33
+ assert_equal send_mock.string, 'a'
34
+
35
+ send_mock.send_data('bcd')
36
+ assert_equal send_mock.string, 'abcd'
37
+
38
+ send_mock.send_data('em')
39
+ assert_equal send_mock.string, 'abcdem'
40
+ end
41
+
42
+ def test_receive_mock_calls_recieve_data
43
+ recv_mock = HollowReceiveMock.new ['a', 'bcd', 'em']
44
+ flexmock(recv_mock).should_receive(:receive_data).with('a').once
45
+ flexmock(recv_mock).should_receive(:receive_data).with('bcd').once
46
+ flexmock(recv_mock).should_receive(:receive_data).with('em').once
47
+ recv_mock.replay
48
+ end
49
+
50
+ def test_receive_mock_collects_objects
51
+ foos = ReceiveFooMock.new(['a', 'bcd', 'emx']).replay.foos
52
+ assert_equal [{'abc' => 'abc'}, {'dem' => 'dem'}], foos
53
+
54
+ foos = ReceiveFooMock.new('ab').replay.foos
55
+ assert_equal [], foos
56
+ end
57
+ end
@@ -0,0 +1,119 @@
1
+ require 'zerg_support'
2
+
3
+ require 'test/unit'
4
+
5
+ class TestFrameProtocol < Test::Unit::TestCase
6
+ FP = Zerg::Support::EventMachine::FrameProtocol
7
+
8
+ # Send mock for frames.
9
+ class SendFramesMock < Zerg::Support::EventMachine::SendMock
10
+ include FP
11
+ end
12
+
13
+ # Receive mock for frames.
14
+ class ReceiveFramesMock < Zerg::Support::EventMachine::ReceiveMock
15
+ include FP
16
+ object_name :frame
17
+ end
18
+
19
+ def setup
20
+ super
21
+ @send_mock = SendFramesMock.new
22
+ end
23
+
24
+ def teardown
25
+ super
26
+ end
27
+
28
+ def continuous_data_test(frames)
29
+ truncated_data_test frames, []
30
+ end
31
+
32
+ def truncated_data_test(frames, sub_lengths)
33
+ frames.each { |frame| @send_mock.send_frame frame }
34
+ in_string = @send_mock.string
35
+ in_strings, i = [], 0
36
+ sub_lengths.each do |sublen|
37
+ in_strings << in_string[i, sublen]
38
+ i += sublen
39
+ end
40
+ in_strings << in_string[i..-1] if i < in_string.length
41
+ out_frames = ReceiveFramesMock.new(@send_mock.string).replay.frames
42
+ assert_equal frames, out_frames
43
+ end
44
+
45
+ def test_empty_frame
46
+ continuous_data_test ['']
47
+ end
48
+
49
+ def test_byte_frame
50
+ continuous_data_test ['F']
51
+ end
52
+
53
+ def test_string_frame
54
+ continuous_data_test [(32...128).to_a.pack('C*')]
55
+ end
56
+
57
+ def test_multiple_frames
58
+ continuous_data_test [(32...128).to_a.pack('C*'), '', 'F', '', '1234567890']
59
+ end
60
+
61
+ def test_truncated_border
62
+ truncated_data_test ['A', 'A'], [1, 0, 2, 0]
63
+ end
64
+
65
+ def test_truncated_border_and_joined_data_size
66
+ truncated_data_test ['A', 'A'], [1, 1, 1, 1]
67
+ end
68
+
69
+ def test_truncated_size
70
+ long_frame = (32...128).to_a.pack('C*') * 5
71
+ truncated_data_test [long_frame], [1]
72
+ end
73
+
74
+ def test_truncated_size_and_data
75
+ long_frame = (32...128).to_a.pack('C*') * 5
76
+ truncated_data_test [long_frame], [1, 16]
77
+ end
78
+
79
+ def test_badass
80
+ # TODO(not_me): this test takes 4 seconds; replace with more targeted tests
81
+
82
+ # build the badass string
83
+ s2_frame = 'qwertyuiopasdfgh' * 8 * 128 # 16384 characters, size is 3 bytes
84
+ @send_mock.send_frame s2_frame
85
+ s2_string = @send_mock.string
86
+ s2_count = 3
87
+ send_string = s2_string * s2_count
88
+ ex_frames = [s2_frame] * s2_count
89
+
90
+ # build cut points in a string
91
+ s2_points = [0, 1, 2, 3, 4, 5, 127, 128, 8190, 16381, 16382, 16383]
92
+ cut_points = []
93
+ 0.upto(s2_count - 1) do |i|
94
+ cut_points += s2_points.map { |p| p + i * s2_string.length }
95
+ end
96
+
97
+ # try all combinations of cutting up the string in 4 pieces
98
+ 0.upto(cut_points.length - 1) do |i|
99
+ (i + 1).upto(cut_points.length - 1) do |j|
100
+ (j + 1).upto(cut_points.length - 1) do |k|
101
+ packets = [0...cut_points[i], cut_points[i]...cut_points[j],
102
+ cut_points[j]...cut_points[k], cut_points[k]..-1].
103
+ map { |r| send_string[r] }
104
+ assert_equal ex_frames, ReceiveFramesMock.new(packets).replay.frames
105
+ end
106
+ end
107
+ end
108
+ end
109
+
110
+ def test_natural_encoding
111
+ table = [[0, "\0"], [1, "\x01"], [127, "\x7f"], [128, "\x80\x01"],
112
+ [65535, "\xff\xff\x03"], [0xf0f0f0, "\xf0\xe1\xc3\x07"],
113
+ [0xaa55aa55aa55, "\xd5\xd4\xd6\xd2\xda\xca\x2a"]]
114
+ table.each do |entry|
115
+ assert_equal entry.last, FP.encode_natural(entry.first)
116
+ assert_equal entry.first, FP.decode_natural(entry.last)
117
+ end
118
+ end
119
+ end
data/test/test_gems.rb ADDED
@@ -0,0 +1,29 @@
1
+ require 'digest/sha1'
2
+ require 'test/unit'
3
+
4
+ require 'zerg_support'
5
+
6
+ class TestGems < Test::Unit::TestCase
7
+ def hash_gems_file
8
+ file_path = File.join(File.dirname(__FILE__),
9
+ '../lib/zerg_support/gems.rb')
10
+ Digest::SHA1.hexdigest File.read(file_path)
11
+ end
12
+
13
+ def test_source_is_manually_tested
14
+ golden_hash = '21ba9ca1e8fa3aa205b468a884746eb37697df9b'
15
+ source_hash = hash_gems_file
16
+
17
+ assert_equal golden_hash, source_hash, <<END_MESSAGE
18
+ lib/zerg_support/zerg_support.rb has changed
19
+
20
+ You need to manually test the file, then replace golden_hash in this test.
21
+ Manual testing plan:
22
+ 1. rake install this gem (zerg_support)
23
+ 2. install zerg
24
+ 3. validate that the installation does not crash and the binary gets symlinked
25
+ in the correct place
26
+ 4. replace golden_hash with #{source_hash}
27
+ END_MESSAGE
28
+ end
29
+ end
@@ -0,0 +1,55 @@
1
+ require 'test/unit'
2
+
3
+ require 'zerg_support'
4
+
5
+ class ObjectProtocolTest < Test::Unit::TestCase
6
+ OP = Zerg::Support::EventMachine::ObjectProtocol
7
+
8
+ class SendObjectMock < Zerg::Support::EventMachine::SendMock
9
+ include OP
10
+ end
11
+ class ReceiveObjectMock < Zerg::Support::EventMachine::ReceiveMock
12
+ include OP
13
+ object_name :object
14
+ end
15
+
16
+ def one_test(*objects)
17
+ send_mock = SendObjectMock.new
18
+ objects.each { |o| send_mock.send_object o }
19
+ assert_equal objects, ReceiveObjectMock.new(send_mock.string).replay.objects
20
+ end
21
+
22
+ def test_border_cases
23
+ one_test({})
24
+ one_test(nil)
25
+ one_test('')
26
+ one_test(false)
27
+ one_test(0)
28
+ one_test([])
29
+ end
30
+
31
+ def test_literals
32
+ one_test(1)
33
+ one_test(true)
34
+ one_test('A')
35
+ one_test("A\nB\nC\tD")
36
+ end
37
+
38
+ def test_arrays
39
+ one_test(['A'])
40
+ one_test(['B', 'C'])
41
+ one_test([0, 'C', [9, 'e'], true])
42
+ end
43
+
44
+ def test_hashes
45
+ one_test({:command => 'run', :binary => '/bin/sh', :quick => false})
46
+ one_test({:command => 'run', :args => { :key => 'v3', :log => true}})
47
+ end
48
+
49
+ def test_multiple_nested
50
+ one_test({:command => 'init', :user => "m\0e", :key => false },
51
+ {:command => 'package', :map => {'dir' => 1, 'NA' => true} },
52
+ "1234567890",
53
+ {:command => 'run', :sequence => [1, nil, 2, true, "Q\n"]})
54
+ end
55
+ end
@@ -0,0 +1,125 @@
1
+ require 'zerg_support'
2
+
3
+ require 'test/unit'
4
+
5
+ module OpenSSHData; end
6
+
7
+ class OpenSshTest < Test::Unit::TestCase
8
+ include OpenSSHData
9
+ OpenSSH = Zerg::Support::OpenSSH
10
+
11
+ def setup
12
+ @rsa_key = OpenSSH.load_key StringIO.new(obsidian_rsa_privkey)
13
+ @dsa_key = OpenSSH.load_key StringIO.new(obsidian_dsa_privkey)
14
+ end
15
+
16
+ @@mpi_test_table = [[0, "\0"], [0x80, "\0\x80"], [0x1234, "\x12\x34"],
17
+ [0xAA55, "\0\xAA\x55"]]
18
+ def test_encode_mpi
19
+ @@mpi_test_table.each {|e| assert_equal e.last, OpenSSH.encode_mpi(e.first) }
20
+ end
21
+
22
+ def test_decode_mpi
23
+ @@mpi_test_table.each {|e| assert_equal e.first, OpenSSH.decode_mpi(e.last) }
24
+ end
25
+
26
+ @@pubkey_pack_table = [[[], ''], [[''], "\0\0\0\0"],
27
+ [['A'], "\0\0\0\1A"],
28
+ [['A', 'BC'], "\0\0\0\1A\0\0\0\2BC"]]
29
+
30
+ def test_pack_pubkey_components
31
+ @@pubkey_pack_table.each do |e|
32
+ assert_equal e.last, OpenSSH.pack_pubkey_components(e.first)
33
+ end
34
+ end
35
+
36
+ def test_unpack_pubkey_components
37
+ @@pubkey_pack_table.each do |e|
38
+ assert_equal e.first, OpenSSH.unpack_pubkey_components(e.last)
39
+ end
40
+ end
41
+
42
+ def test_load_key
43
+ assert_equal obsidian_rsa_privkey, @rsa_key.to_pem
44
+ assert_equal obsidian_dsa_privkey, @dsa_key.to_pem
45
+ end
46
+
47
+ def test_encode_pubkey
48
+ assert_equal obsidian_rsa_pubkey, OpenSSH.encode_pubkey(@rsa_key)
49
+ assert_equal obsidian_dsa_pubkey, OpenSSH.encode_pubkey(@dsa_key)
50
+ end
51
+
52
+ def test_decode_pubkey
53
+ assert_equal @rsa_key.public_key.to_pem,
54
+ OpenSSH.decode_pubkey(obsidian_rsa_pubkey).to_pem
55
+ assert_equal @dsa_key.public_key.to_pem,
56
+ OpenSSH.decode_pubkey(obsidian_dsa_pubkey).to_pem
57
+ end
58
+ end
59
+
60
+ module OpenSSHData
61
+ def known_hosts_file
62
+ <<END_KH
63
+ github.com,65.74.177.129 ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEAq2A7hRGmdnm9tUDbO9IDSwBK6TbQa+PXYPCPy6rbTrTtw7PHkccKrpp0yVhp5HdEIcKr6pLlVDBfOLX9QUsyCOV0wzfjIJNlGEYsdlLJizHhbn2mUjvSAHQqZETYP81eFzLQNnPHt4EVVUh7VfDESU84KezmD5QlWpXLmvU31/yMf+Se8xhHTvKSCZIFImWwoG6mbUoWf9nzpIoaSjB+weqqUUmpaaasXVal72J+UX2B+2RPW3RcT0eOzQgqlJL3RKrTJvdsjE3JEAvGq3lGHSZXy28G3skua2SmVi/w4yCE6gbODqnTWlg7+wC604ydGXA8VJiS5ap43JXiUFFAaQ==
64
+ obsidian.local ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEAq7VciLo2wB+/2ThHXejC/kgkN205zlyS5cvN40Mqi3qvRVS75X1RawDoLot8eJ9KCYqZFr2Dr73d/EQNltN7dKJoPIj1IKxoraWkyNFbhhzpYuOltg9oO5UBSTNLupqla7zcdj4IwCCkBYk4+TS0dwmi20buOJ0FPY5PgbzmMnUiV9ipBqeJSdZB+TePH1gqlt7AP/6ti/0gxb2K7F69dZl/BSxMEzRCfBlTFC3f/4n8IdCuSJvNxxY+TtRnLL5CKUhj9QaIBan6JCkdRvVOBY7wmsNT8nGDzfDFSDD3KKn93g4LRkyMeaYlSDLxKy8PnNhjWgBNH1YNYyicsGfBKQ==
65
+ rubyforge.org,205.234.109.19 ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEA3tPhdPUFGAYyrT1quRSOevLbAdKAJ6Ovwqw0m99R0QkqUwMUh09pgedWZeij7HtAHtoWPrNFev8FrwcwnL14NgA/gwNnXxbqd4twC1HyFShUf7POry8bz3Qk+84STHeMY8++hhn8LgNyfuVQswHoW661aqieLM6pF8q8xIUtkXA7daNpJAL4nTN1TxgUoCDpCa0EbUPkGpwFPNtGPuokRXNOCR9g8T6LmPQbzGUTc4CzFfQ9rrHaimqkEmRWJbBOaik1bdQNqOh6MUDDuUSpkJV7fwu3bl4fF5/1kw2HCREEjJmESOYnZhOS+MCp1qAUcuXqpMqXD8ATNsuXqrIhTQ==
66
+ END_KH
67
+ end
68
+
69
+ def obsidian_rsa_pubkey
70
+ 'AAAAB3NzaC1yc2EAAAABIwAAAQEAq7VciLo2wB+/2ThHXejC/kgkN205zlyS5cvN40Mqi3qvRVS75X1RawDoLot8eJ9KCYqZFr2Dr73d/EQNltN7dKJoPIj1IKxoraWkyNFbhhzpYuOltg9oO5UBSTNLupqla7zcdj4IwCCkBYk4+TS0dwmi20buOJ0FPY5PgbzmMnUiV9ipBqeJSdZB+TePH1gqlt7AP/6ti/0gxb2K7F69dZl/BSxMEzRCfBlTFC3f/4n8IdCuSJvNxxY+TtRnLL5CKUhj9QaIBan6JCkdRvVOBY7wmsNT8nGDzfDFSDD3KKn93g4LRkyMeaYlSDLxKy8PnNhjWgBNH1YNYyicsGfBKQ=='
71
+ end
72
+
73
+ def obsidian_dsa_pubkey
74
+ 'AAAAB3NzaC1kc3MAAACBAPdWp4HhWUoNawosyEBvrhPSbjhCJiKnVWiUS6bo0BCGzTHhugrkv2HgtlKhWo8nqTw5E4YxzFVyZ0YQt4m7NYDLTZVjrqbIpL/3F5qNXco127O/im0cG27AKC8Jf7knmUTjd8EBhtK65tNDmxPtzKQtemlNTVPX1VccOn6eLtn1AAAAFQDtQC21TJrf/p5WNsU9UIJzO9/hIwAAAIEAgwTrIfleQMEAK9N3xeMVZpAGfSAoX6owLtk3z+iQ3rM9FRvM/CgezOgezLowJghkw/bcQDmMuudBUuijrM3zZWdr6eqoNbFTR/KKiUx3cYf0LAHNPbXfVz+P7BXqjcEj75qnwuHQMp7vNMg+dmV40UA2TiC5/8QlaZVwkOSPN6gAAACAPMGJEFkoR0ayfkd0S/tnY9ilO17T6rdoDuF25ATtNUd6Zji6tslxBkQFWtTeinO3rGkqJRPndq0wp3E33AOHhJE/FOIlWl4Tf6aeU95Y4enYujKQDiImSTXmdiw5wq/LFdc3a2waOUvuI+647wxgHhqTmD7xI2biGZLYN9Oasy0='
75
+ end
76
+
77
+ def obsidian_rsa_privkey
78
+ <<END_RSAK
79
+ -----BEGIN RSA PRIVATE KEY-----
80
+ MIIEoQIBAAKCAQEAq7VciLo2wB+/2ThHXejC/kgkN205zlyS5cvN40Mqi3qvRVS7
81
+ 5X1RawDoLot8eJ9KCYqZFr2Dr73d/EQNltN7dKJoPIj1IKxoraWkyNFbhhzpYuOl
82
+ tg9oO5UBSTNLupqla7zcdj4IwCCkBYk4+TS0dwmi20buOJ0FPY5PgbzmMnUiV9ip
83
+ BqeJSdZB+TePH1gqlt7AP/6ti/0gxb2K7F69dZl/BSxMEzRCfBlTFC3f/4n8IdCu
84
+ SJvNxxY+TtRnLL5CKUhj9QaIBan6JCkdRvVOBY7wmsNT8nGDzfDFSDD3KKn93g4L
85
+ RkyMeaYlSDLxKy8PnNhjWgBNH1YNYyicsGfBKQIBIwKCAQA/xwUc13Nr7okWKtit
86
+ 2hyKVU9HyXve7y8/aPSzf1jx+l5blIBN7LfXSXrPdaNCvtJbULyEygxXN+S8yNHY
87
+ 73b/b4XNV3D9gd281x/y0WsjL09fPpyitUP435LDatL8Ks+6TXZ1D7obedaFtqAi
88
+ DEMHpH5Rch33xUsW3RY3gK1F8GHzYh+zMd0llH8w6IVBv0hrWttyp+4By1dhXA3L
89
+ alYYOlGbu5cNuJfz50v4T/uB9F63JqHtAxEjqD7SvjCUbogGPxEH1k4Or+3xGuvR
90
+ yTPaiuR9kehBstjbqc91rTLnGOr5a1VUIq6++0tCVOXQa+x5J5zCu/baGTdfkgRU
91
+ loILAoGBAOHQcGIEgD1xHwFX9AafarF+1j4pPkM1p2u+9DNTIl1f2Rk6yOHlHZGF
92
+ mfozMyh6l4HpvPTT7nflM4YR0JWJNbQIpCY8CdYKMXBVWcH4PXuqwyGKJBZMXWkn
93
+ hKvelJ0UZUwx5+n8fTmSxLcIIlz5uKEE5k23/3cKkP7P6+Z6YuIZAoGBAMKpYBkM
94
+ A4JMJ3QJ5TVsdFOoO0b1wThRgQTZR6ic9rNeXnZiL0mmr44DX2T1rTnEm6KZv2f2
95
+ kWLQp5jx8BPFI+TUv16j4xrnnuHPhuBordCYQizSPcxXqL8b8a/KU+S5xofRjwB6
96
+ +8szd/JmGFDY8WgWrtIL32TdRhcIFg0Dg1mRAoGAE1sCUYtbcvsRSUINmirr41QD
97
+ vC9rvJ4y6/pss/Eu1M2zhdHWtEbWphLEDiGlTJzLKGR96Rl61xOlVKJw9t/gCB3/
98
+ cP3U9RbRCaDqb7YxJ9tvz6zBQ71nF6RNM02XtbFKgt+0yunBlzh3QuNwqOI0ZZK0
99
+ p5Ntqx4pr3DoVZV2MKMCgYBprGdeDdYE54MhvDqZWCHkRWIB8x+/fLPAzbkvpap+
100
+ oPFzdyD8GKhxqg82zoKbs991hqm8GCMJwboRMuFp0WtBtVHxjCrUF1ZAEZJckJje
101
+ 85GjTY9DCwPVdZHUdSY6VjiS33mD6v23c7YkgJDbbnRrtIrJy+5MsqJkRjfbLcr2
102
+ GwKBgQCWDKVM8mZJcmM3KJwzBWh+b5T7tIbOBFaCvOBq4G0UUZGytWVUaddSbdh5
103
+ YJ+1CoLDB+Wp3U95B1USQuSYwwr0wOYy42HBII7HnkaphT9HgDIhgvttFhX162oC
104
+ bRizr31NgiGtgJbHJ9QPhaLvn3mZtZAFfRaEEdZslUzqRSACww==
105
+ -----END RSA PRIVATE KEY-----
106
+ END_RSAK
107
+ end
108
+
109
+ def obsidian_dsa_privkey
110
+ <<END_DSAK
111
+ -----BEGIN DSA PRIVATE KEY-----
112
+ MIIBvAIBAAKBgQD3VqeB4VlKDWsKLMhAb64T0m44QiYip1VolEum6NAQhs0x4boK
113
+ 5L9h4LZSoVqPJ6k8OROGMcxVcmdGELeJuzWAy02VY66myKS/9xeajV3KNduzv4pt
114
+ HBtuwCgvCX+5J5lE43fBAYbSuubTQ5sT7cykLXppTU1T19VXHDp+ni7Z9QIVAO1A
115
+ LbVMmt/+nlY2xT1QgnM73+EjAoGBAIME6yH5XkDBACvTd8XjFWaQBn0gKF+qMC7Z
116
+ N8/okN6zPRUbzPwoHszoHsy6MCYIZMP23EA5jLrnQVLoo6zN82Vna+nqqDWxU0fy
117
+ iolMd3GH9CwBzT2131c/j+wV6o3BI++ap8Lh0DKe7zTIPnZleNFANk4guf/EJWmV
118
+ cJDkjzeoAoGAPMGJEFkoR0ayfkd0S/tnY9ilO17T6rdoDuF25ATtNUd6Zji6tslx
119
+ BkQFWtTeinO3rGkqJRPndq0wp3E33AOHhJE/FOIlWl4Tf6aeU95Y4enYujKQDiIm
120
+ STXmdiw5wq/LFdc3a2waOUvuI+647wxgHhqTmD7xI2biGZLYN9Oasy0CFQDL/9Z1
121
+ fSLn88m1sUeWAZ4Ys2IIxw==
122
+ -----END DSA PRIVATE KEY-----
123
+ END_DSAK
124
+ end
125
+ end