ronin-support 0.2.0 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (62) hide show
  1. data/.gitignore +11 -0
  2. data/ChangeLog.md +42 -1
  3. data/README.md +4 -1
  4. data/gemspec.yml +2 -1
  5. data/lib/ronin/extensions.rb +2 -0
  6. data/lib/ronin/extensions/enumerable.rb +54 -0
  7. data/lib/ronin/extensions/file.rb +70 -2
  8. data/lib/ronin/extensions/ip_addr.rb +45 -45
  9. data/lib/ronin/extensions/regexp.rb +45 -0
  10. data/lib/ronin/extensions/resolv.rb +80 -0
  11. data/lib/ronin/extensions/string.rb +35 -32
  12. data/lib/ronin/formatting/extensions/binary/integer.rb +12 -5
  13. data/lib/ronin/formatting/extensions/binary/string.rb +44 -16
  14. data/lib/ronin/formatting/extensions/html/integer.rb +51 -31
  15. data/lib/ronin/formatting/extensions/html/string.rb +50 -31
  16. data/lib/ronin/formatting/extensions/http/integer.rb +10 -2
  17. data/lib/ronin/formatting/extensions/sql.rb +20 -0
  18. data/lib/ronin/formatting/extensions/sql/string.rb +98 -0
  19. data/lib/ronin/formatting/extensions/text/array.rb +11 -9
  20. data/lib/ronin/formatting/extensions/text/string.rb +213 -29
  21. data/lib/ronin/formatting/sql.rb +20 -0
  22. data/lib/ronin/network/extensions/http.rb +1 -0
  23. data/lib/ronin/network/extensions/http/net.rb +2 -2
  24. data/lib/ronin/network/extensions/http/uri/http.rb +226 -0
  25. data/lib/ronin/network/extensions/imap/net.rb +1 -1
  26. data/lib/ronin/network/extensions/ssl/net.rb +7 -1
  27. data/lib/ronin/network/http/proxy.rb +20 -21
  28. data/lib/ronin/network/mixins.rb +27 -0
  29. data/lib/ronin/network/mixins/esmtp.rb +165 -0
  30. data/lib/ronin/network/mixins/http.rb +723 -0
  31. data/lib/ronin/network/mixins/imap.rb +151 -0
  32. data/lib/ronin/network/mixins/pop3.rb +141 -0
  33. data/lib/ronin/network/mixins/smtp.rb +159 -0
  34. data/lib/ronin/network/mixins/tcp.rb +331 -0
  35. data/lib/ronin/network/mixins/telnet.rb +199 -0
  36. data/lib/ronin/network/mixins/udp.rb +227 -0
  37. data/lib/ronin/network/ssl.rb +17 -11
  38. data/lib/ronin/path.rb +3 -3
  39. data/lib/ronin/spec/ui/output.rb +28 -0
  40. data/lib/ronin/support.rb +3 -0
  41. data/lib/ronin/support/version.rb +1 -1
  42. data/lib/ronin/ui/output.rb +21 -0
  43. data/lib/ronin/ui/output/helpers.rb +248 -0
  44. data/lib/ronin/ui/output/output.rb +146 -0
  45. data/lib/ronin/ui/output/terminal.rb +21 -0
  46. data/lib/ronin/ui/output/terminal/color.rb +118 -0
  47. data/lib/ronin/ui/output/terminal/raw.rb +103 -0
  48. data/lib/ronin/ui/shell.rb +219 -0
  49. data/ronin-support.gemspec +1 -1
  50. data/spec/extensions/enumerable_spec.rb +24 -0
  51. data/spec/extensions/file_spec.rb +39 -0
  52. data/spec/extensions/ip_addr_spec.rb +6 -0
  53. data/spec/extensions/resolv_spec.rb +18 -0
  54. data/spec/formatting/html/integer_spec.rb +2 -2
  55. data/spec/formatting/html/string_spec.rb +1 -1
  56. data/spec/formatting/sql/string_spec.rb +55 -0
  57. data/spec/formatting/text/string_spec.rb +110 -0
  58. data/spec/network/ssl_spec.rb +10 -4
  59. data/spec/ui/classes/test_shell.rb +22 -0
  60. data/spec/ui/output_spec.rb +32 -0
  61. data/spec/ui/shell_spec.rb +79 -0
  62. metadata +132 -90
@@ -99,7 +99,7 @@ Gem::Specification.new do |gemspec|
99
99
  end
100
100
 
101
101
  if gemspec.respond_to?(:required_rubygems_version=)
102
- gemspec.required_rubygems_version = metadata['required_ruby_version']
102
+ gemspec.required_rubygems_version = metadata['required_rubygems_version']
103
103
  end
104
104
 
105
105
  parse_versions = lambda { |versions|
@@ -0,0 +1,24 @@
1
+ require 'spec_helper'
2
+ require 'ronin/extensions/enumerable'
3
+
4
+ describe Enumerable do
5
+ describe "#map_hash" do
6
+ it "should map elements to a Hash" do
7
+ [1, 2, 3].map_hash { |i| i ** 2 }.should == {
8
+ 1 => 1,
9
+ 2 => 4,
10
+ 3 => 9
11
+ }
12
+ end
13
+
14
+ it "should not map the same element twice" do
15
+ [1, 2, 2].map_hash { |i| rand }.keys.should =~ [1, 2]
16
+ end
17
+
18
+ it "should set the default_proc of the Hash" do
19
+ hash = [].map_hash { |i| i ** 2 }
20
+
21
+ hash[3].should == 9
22
+ end
23
+ end
24
+ end
@@ -1,6 +1,8 @@
1
1
  require 'spec_helper'
2
2
  require 'ronin/extensions/file'
3
3
 
4
+ require 'tempfile'
5
+
4
6
  describe File do
5
7
  subject { File }
6
8
 
@@ -8,6 +10,43 @@ describe File do
8
10
  subject.should respond_to(:escape_path)
9
11
  end
10
12
 
13
+ describe "each_line" do
14
+ let(:lines) { %w[one two three] }
15
+
16
+ before(:all) do
17
+ @file = Tempfile.new('ronin-support')
18
+ @file.puts(*lines)
19
+ @file.close
20
+ end
21
+
22
+ it "should enumerate over each line in the file" do
23
+ File.each_line(@file.path).to_a.should == lines
24
+ end
25
+ end
26
+
27
+ describe "each_row" do
28
+ let(:rows) do
29
+ [
30
+ %w[one two three],
31
+ %w[four five six]
32
+ ]
33
+ end
34
+
35
+ let(:separator) { '|' }
36
+ let(:newline) { "\r\n" }
37
+ let(:lines) { rows.map { |row| row.join(separator) }.join(newline) }
38
+
39
+ before(:all) do
40
+ @file = Tempfile.new('ronin-support')
41
+ @file.write(lines)
42
+ @file.close
43
+ end
44
+
45
+ it "should enumerate over each row from each line" do
46
+ File.each_row(@file.path,separator).to_a.should == rows
47
+ end
48
+ end
49
+
11
50
  describe "escape_path" do
12
51
  it "should remove null-bytes" do
13
52
  File.escape_path("hello\0world\0").should == "helloworld"
@@ -160,10 +160,16 @@ describe IPAddr do
160
160
  let(:bad_ip) { IPAddr.new('0.0.0.0') }
161
161
 
162
162
  describe "#lookup" do
163
+ let(:nameserver) { '4.2.2.1' }
164
+
163
165
  it "should lookup the host-name for an IP" do
164
166
  ip.lookup.should include('localhost')
165
167
  end
166
168
 
169
+ it "may lookup host-names via other nameservers" do
170
+ ip.lookup(nameserver).should be_empty
171
+ end
172
+
167
173
  it "should return an empty Array for unknown IP addresses" do
168
174
  bad_ip.lookup.should be_empty
169
175
  end
@@ -0,0 +1,18 @@
1
+ require 'spec_helper'
2
+ require 'ronin/extensions/resolv'
3
+
4
+ describe Resolv do
5
+ describe "resolver" do
6
+ let(:nameserver) { '4.2.2.1' }
7
+
8
+ subject { Resolv }
9
+
10
+ it "should create a new Resolv::DNS object if a nameserver is given" do
11
+ subject.resolver(nameserver).should be_kind_of(Resolv::DNS)
12
+ end
13
+
14
+ it "should return the default resolver otherwise" do
15
+ subject.resolver.should == Resolv
16
+ end
17
+ end
18
+ end
@@ -53,14 +53,14 @@ describe Integer do
53
53
  end
54
54
 
55
55
  describe "#format_js" do
56
- let(:js_escaped) { "%26" }
56
+ let(:js_escaped) { '\x26' }
57
57
 
58
58
  it "should JavaScript format ascii bytes" do
59
59
  subject.format_js.should == js_escaped
60
60
  end
61
61
 
62
62
  it "should JavaScript format unicode bytes" do
63
- 0xd556.format_js.should == "%uD556"
63
+ 0xd556.format_js.should == '\uD556'
64
64
  end
65
65
  end
66
66
  end
@@ -94,7 +94,7 @@ describe String do
94
94
  end
95
95
 
96
96
  describe "#format_js" do
97
- let(:js_formatted) { "%6F%6E%65%20%26%20%74%77%6F" }
97
+ let(:js_formatted) { '\x6F\x6E\x65\x20\x26\x20\x74\x77\x6F' }
98
98
 
99
99
  it "should JavaScript escape all characters" do
100
100
  subject.format_js.should == js_formatted
@@ -0,0 +1,55 @@
1
+ require 'spec_helper'
2
+ require 'ronin/formatting/extensions/sql/string'
3
+
4
+ describe String do
5
+ before(:all) do
6
+ @string = '/etc/passwd'
7
+ @sql_encoded = '0x2f6574632f706173737764'
8
+ @string_with_quotes = %{"O'Brian"}
9
+ end
10
+
11
+ it "should provide the #sql_escape method" do
12
+ @string.should respond_to(:sql_escape)
13
+ end
14
+
15
+ it "should provide the #sql_encode method" do
16
+ @string.should respond_to(:sql_encode)
17
+ end
18
+
19
+ it "should provide the #sql_decode method" do
20
+ @string.should respond_to(:sql_decode)
21
+ end
22
+
23
+ describe "SQL escaping" do
24
+ it "should be able to single-quote escape" do
25
+ @string_with_quotes.sql_escape(:single).should == %{'"O''Brian"'}
26
+ end
27
+
28
+ it "should be able to double-quote escape" do
29
+ @string_with_quotes.sql_escape(:double).should == %{"""O'Brian"""}
30
+ end
31
+ end
32
+
33
+ describe "SQL-hex encoding" do
34
+ it "should be able to be SQL-hex encoded" do
35
+ @string.sql_encode.should == @sql_encoded
36
+ end
37
+
38
+ it "should return an empty String if empty" do
39
+ ''.sql_encode.should == ''
40
+ end
41
+ end
42
+
43
+ describe "SQL-hex decoding" do
44
+ it "should be able to be SQL-hex decoded" do
45
+ encoded = @string.sql_encode
46
+
47
+ encoded.should == @sql_encoded
48
+ encoded.sql_decode.should == @string
49
+ end
50
+
51
+ it "should be able to decode SQL comma-escaping" do
52
+ "'Conan O''Brian'".sql_decode.should == "Conan O'Brian"
53
+ end
54
+ end
55
+ end
@@ -4,6 +4,10 @@ require 'ronin/formatting/text'
4
4
  describe String do
5
5
  subject { "hello" }
6
6
 
7
+ it "should provide String.generate" do
8
+ described_class.should respond_to(:generate)
9
+ end
10
+
7
11
  it "should provide String#format_chars" do
8
12
  should respond_to(:format_chars)
9
13
  end
@@ -24,6 +28,112 @@ describe String do
24
28
  should respond_to(:insert_after)
25
29
  end
26
30
 
31
+ describe "generate" do
32
+ subject { described_class }
33
+
34
+ it "should generate Strings from CharSets" do
35
+ strings = subject.generate(:lowercase_hexadecimal, :numeric).to_a
36
+
37
+ strings.grep(/^[0-9a-f][0-9]$/).should == strings
38
+ end
39
+
40
+ it "should generate Strings from lengths of CharSets" do
41
+ strings = subject.generate([:numeric, 2]).to_a
42
+
43
+ strings.grep(/^[0-9]{2}$/).should == strings
44
+ end
45
+
46
+ it "should generate Strings from varying lengths of CharSets" do
47
+ strings = subject.generate([:numeric, 1..2]).to_a
48
+
49
+ strings.grep(/^[0-9]{1,2}$/).should == strings
50
+ end
51
+
52
+ it "should generate Strings from custom CharSets" do
53
+ strings = subject.generate([%w[a b c], 2]).to_a
54
+
55
+ strings.grep(/^[abc]{2}$/).should == strings
56
+ end
57
+
58
+ it "should generate Strings containing known Strings" do
59
+ strings = subject.generate('foo', [%w[a b c], 2]).to_a
60
+
61
+ strings.grep(/^foo[abc]{2}$/).should == strings
62
+ end
63
+
64
+ it "should raise a TypeError for non String, Symbol, Enumerable CharSets" do
65
+ lambda {
66
+ subject.generate([Object.new, 2]).to_a
67
+ }.should raise_error(TypeError)
68
+ end
69
+
70
+ it "should raise an ArgumentError for unknown CharSets" do
71
+ lambda {
72
+ subject.generate([:foo_bar, 2]).to_a
73
+ }.should raise_error(ArgumentError)
74
+ end
75
+
76
+ it "should raise a TypeError for non Integer,Array,Range lengths" do
77
+ lambda {
78
+ subject.generate([:numeric, 'foo']).to_a
79
+ }.should raise_error(TypeError)
80
+ end
81
+ end
82
+
83
+ describe "#fuzz" do
84
+ subject { 'GET /one/two/three' }
85
+
86
+ it "should match Regexps" do
87
+ fuzzed = subject.fuzz(/GET/ => ['get']).to_a
88
+
89
+ fuzzed.should == ['get /one/two/three']
90
+ end
91
+
92
+ it "should match Strings" do
93
+ fuzzed = subject.fuzz('GET' => ['get']).to_a
94
+
95
+ fuzzed.should == ['get /one/two/three']
96
+ end
97
+
98
+ it "should match Integers" do
99
+ fuzzed = subject.fuzz(0x20 => ["\t"]).to_a
100
+
101
+ fuzzed.should == ["GET\t/one/two/three"]
102
+ end
103
+
104
+ it "should substitute using Procs" do
105
+ fuzzed = subject.fuzz('GET' => [lambda { |s| s.downcase }]).to_a
106
+
107
+ fuzzed.should == ['get /one/two/three']
108
+ end
109
+
110
+ it "should substitute using Integers" do
111
+ fuzzed = subject.fuzz(' ' => [0x09]).to_a
112
+
113
+ fuzzed.should == ["GET\t/one/two/three"]
114
+ end
115
+
116
+ it "should incrementally replace each occurrence" do
117
+ fuzzed = subject.fuzz('/' => ["\n\r"]).to_a
118
+
119
+ fuzzed.should == [
120
+ "GET \n\rone/two/three",
121
+ "GET /one\n\rtwo/three",
122
+ "GET /one/two\n\rthree"
123
+ ]
124
+ end
125
+
126
+ it "should replace each occurrence with each substitution" do
127
+ fuzzed = subject.fuzz('GET' => ["\n\rGET", "G\n\rET", "GET\n\r"]).to_a
128
+
129
+ fuzzed.should == [
130
+ "\n\rGET /one/two/three",
131
+ "G\n\rET /one/two/three",
132
+ "GET\n\r /one/two/three"
133
+ ]
134
+ end
135
+ end
136
+
27
137
  describe "#format_bytes" do
28
138
  it "should format each byte in the String" do
29
139
  subject.format_bytes { |b|
@@ -2,13 +2,19 @@ require 'spec_helper'
2
2
  require 'ronin/network/ssl'
3
3
 
4
4
  describe Network::SSL do
5
- describe 'verify' do
6
- it "should map verify mode names to numeric values" do
7
- subject.verify(:peer).should == OpenSSL::SSL::VERIFY_PEER
5
+ describe 'VERIFY' do
6
+ subject { Network::SSL::VERIFY }
7
+
8
+ it "should map verify mode names to OpenSSL VERIFY_* constants" do
9
+ subject[:peer].should == OpenSSL::SSL::VERIFY_PEER
8
10
  end
9
11
 
10
12
  it "should default to VERIFY_NONE if no verify mode name is given" do
11
- subject.verify.should == OpenSSL::SSL::VERIFY_NONE
13
+ subject[nil].should == OpenSSL::SSL::VERIFY_NONE
14
+ end
15
+
16
+ it "should raise an exception for unknown verify modes" do
17
+ lambda { subject[:foo_bar] }.should raise_error
12
18
  end
13
19
  end
14
20
  end
@@ -0,0 +1,22 @@
1
+ require 'ronin/ui/shell'
2
+
3
+ class TestShell < Ronin::UI::Shell
4
+
5
+ def a_public_method
6
+ end
7
+
8
+ protected
9
+
10
+ def command1
11
+ :command1
12
+ end
13
+
14
+ def command_with_arg(arg)
15
+ arg
16
+ end
17
+
18
+ def command_with_args(*args)
19
+ args
20
+ end
21
+
22
+ end
@@ -0,0 +1,32 @@
1
+ require 'spec_helper'
2
+ require 'ronin/ui/output'
3
+
4
+ describe UI::Output do
5
+ it "should be quiet by default" do
6
+ should be_quiet
7
+ end
8
+
9
+ it "may become verbose" do
10
+ subject.verbose!
11
+
12
+ should be_verbose
13
+ should_not be_quiet
14
+ should_not be_silent
15
+ end
16
+
17
+ it "may become quiet" do
18
+ subject.quiet!
19
+
20
+ should be_quiet
21
+ should_not be_silent
22
+ should_not be_verbose
23
+ end
24
+
25
+ it "may become silent" do
26
+ subject.silent!
27
+
28
+ should be_silent
29
+ should_not be_quiet
30
+ should_not be_verbose
31
+ end
32
+ end
@@ -0,0 +1,79 @@
1
+ require 'spec_helper'
2
+ require 'ronin/ui/shell'
3
+
4
+ require 'ui/classes/test_shell'
5
+
6
+ describe UI::Shell do
7
+ context "with handler callback" do
8
+ let(:line) { 'one two three' }
9
+
10
+ it "should call the input handler with the shell and input line" do
11
+ lines = []
12
+ shell = described_class.new { |shell,input| lines << input }
13
+
14
+ shell.call(line)
15
+
16
+ lines.should == [line]
17
+ end
18
+ end
19
+
20
+ context "with commands" do
21
+ subject { TestShell.new }
22
+
23
+ describe "#commands" do
24
+ it "should include builtin methods" do
25
+ subject.commands.should include(:help, :exit)
26
+ end
27
+
28
+ it "should include protected methods" do
29
+ subject.commands.should include(:command1, :command_with_arg, :command_with_args)
30
+ end
31
+
32
+ it "should not include public methods" do
33
+ subject.commands.should_not include(:a_public_method)
34
+ end
35
+ end
36
+
37
+ describe "#call" do
38
+ it "should ignore empty lines" do
39
+ subject.call('').should == false
40
+ end
41
+
42
+ it "should ignore white-space lines" do
43
+ subject.call(" \t ").should == false
44
+ end
45
+
46
+ it "should not allow calling the handler method" do
47
+ subject.call('handler').should == false
48
+ end
49
+
50
+ it "should not allow calling unknown commands" do
51
+ subject.call('an_unknown_command').should == false
52
+ end
53
+
54
+ it "should not allow calling unknown commands" do
55
+ subject.call('an_unknown_command').should == false
56
+ end
57
+
58
+ it "should not allow calling public methods" do
59
+ subject.call('a_public_method').should == false
60
+ end
61
+
62
+ it "should allow calling protected methods" do
63
+ subject.call('command1').should == :command1
64
+ end
65
+
66
+ it "should raise an exception when passing invalid number of arguments" do
67
+ lambda {
68
+ subject.call('command_with_arg too many args')
69
+ }.should raise_error(ArgumentError)
70
+ end
71
+
72
+ it "should splat the command arguments to the command method" do
73
+ subject.call('command_with_args one two three').should == [
74
+ 'one', 'two', 'three'
75
+ ]
76
+ end
77
+ end
78
+ end
79
+ end