rex-text 0.1.1 → 0.1.2

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: c21a0eef12185e5d77b4ab24904765c42f464004
4
- data.tar.gz: 6f588d580a7b84a6eddfcf4a07cf0ec617e16d21
3
+ metadata.gz: a213d45ce77b442cf80cc9e8c302d705c9f63128
4
+ data.tar.gz: 739aabf270a14239b68f9bdc3f394eebaa949efc
5
5
  SHA512:
6
- metadata.gz: 91d1531cc4a260903fa59357a6b4aeea72ddce6b3018953e6084f1943149ddedfcd2f7378d6638992020c9e2244a44ca2ab63a48809b4648230388d1d3601304
7
- data.tar.gz: 2cab8cb2862e871ea5cdde228266a1796c23ffaadb46f71118976108a7bff008d6aebd11e09a7e3f43825790a856d8ee3502b4a139a454c7f617ee1d3c9b2403
6
+ metadata.gz: cd856ab7b00383f19e189e4da9f55e8b078a6ef1429535b4e6c223ce853dd83bbdd8fb562cb0f7fe295db52de89c538e11fa1b677f0d97a15684271de22671d7
7
+ data.tar.gz: e77455056b8e1ffa80af71886deae1576a21b8f92bc2450f296dc4430ec6cd5c9a229d03c95fc3cc6cb788aeef5aa9e829103d88116d751bc6046c20b5e1dd33
checksums.yaml.gz.sig CHANGED
Binary file
data.tar.gz.sig CHANGED
Binary file
data/lib/rex/text.rb CHANGED
@@ -25,6 +25,10 @@ require 'rex/text/ebcdic'
25
25
  require 'rex/text/pattern'
26
26
  require 'rex/text/badchars'
27
27
 
28
+ require 'rex/text/color'
29
+ require 'rex/text/table'
30
+
31
+
28
32
  module Rex
29
33
 
30
34
  ###
@@ -0,0 +1,106 @@
1
+ # -*- coding: binary -*-
2
+ module Rex
3
+ module Text
4
+
5
+ ###
6
+ #
7
+ # This module provides an interface to getting ANSI color codes.
8
+ # It's taken mostly from perl's Term::ANSIColor by Russ Allbery
9
+ # <rra@stanford.edu> and Zenin <zenin@best.com>.
10
+ #
11
+ ###
12
+ module Color
13
+
14
+ AnsiAttributes =
15
+ {
16
+ 'clear' => 0,
17
+ 'reset' => 0,
18
+ 'bold' => 1,
19
+ 'dark' => 2,
20
+ 'underline' => 4,
21
+ 'underscore' => 4,
22
+ 'blink' => 5,
23
+ 'reverse' => 7,
24
+ 'concealed' => 8,
25
+ 'black' => 30, 'on_black' => 40,
26
+ 'red' => 31, 'on_red' => 41,
27
+ 'green' => 32, 'on_green' => 42,
28
+ 'yellow' => 33, 'on_yellow' => 43,
29
+ 'blue' => 34, 'on_blue' => 44,
30
+ 'magenta' => 35, 'on_magenta' => 45,
31
+ 'cyan' => 36, 'on_cyan' => 46,
32
+ 'white' => 37, 'on_white' => 47
33
+ }
34
+
35
+ #
36
+ # Return a string with ANSI codes substituted. Derived from code
37
+ # written by The FaerieMUD Consortium.
38
+ #
39
+ def ansi(*attrs)
40
+ attr = attrs.collect {|a| AnsiAttributes[a] ? AnsiAttributes[a] : nil}.compact.join(';')
41
+ attr = "\e[%sm" % attr if (attr.empty? == false)
42
+ return attr
43
+ end
44
+
45
+ #
46
+ # Colorize if this shell supports it
47
+ #
48
+ def colorize(*color)
49
+ supports_color?() ? ansi(*color) : ''
50
+ end
51
+
52
+ def substitute_colors(msg, in_prompt = nil)
53
+ str = msg.dup
54
+ pre_color = post_color = ''
55
+ if (in_prompt)
56
+ pre_color = "\x01" # RL_PROMPT_START_IGNORE
57
+ post_color = "\x02" # RL_PROMPT_END_IGNORE
58
+ end
59
+ str.gsub!(/%cya/, pre_color+colorize('cyan')+post_color)
60
+ str.gsub!(/%red/, pre_color+colorize('red')+post_color)
61
+ str.gsub!(/%grn/, pre_color+colorize('green')+post_color)
62
+ str.gsub!(/%blu/, pre_color+colorize('blue')+post_color)
63
+ str.gsub!(/%yel/, pre_color+colorize('yellow')+post_color)
64
+ str.gsub!(/%whi/, pre_color+colorize('white')+post_color)
65
+ str.gsub!(/%mag/, pre_color+colorize('magenta')+post_color)
66
+ str.gsub!(/%blk/, pre_color+colorize('black')+post_color)
67
+ str.gsub!(/%dred/, pre_color+colorize('dark', 'red')+post_color)
68
+ str.gsub!(/%dgrn/, pre_color+colorize('dark', 'green')+post_color)
69
+ str.gsub!(/%dblu/, pre_color+colorize('dark', 'blue')+post_color)
70
+ str.gsub!(/%dyel/, pre_color+colorize('dark', 'yellow')+post_color)
71
+ str.gsub!(/%dcya/, pre_color+colorize('dark', 'cyan')+post_color)
72
+ str.gsub!(/%dwhi/, pre_color+colorize('dark', 'white')+post_color)
73
+ str.gsub!(/%dmag/, pre_color+colorize('dark', 'magenta')+post_color)
74
+ str.gsub!(/%und/, pre_color+colorize('underline')+post_color)
75
+ str.gsub!(/%bld/, pre_color+colorize('bold')+post_color)
76
+ str.gsub!(/%clr/, pre_color+colorize('clear')+post_color)
77
+ # Background Color
78
+ str.gsub!(/%bgblu/, pre_color+colorize('on_blue')+post_color)
79
+ str.gsub!(/%bgyel/, pre_color+colorize('on_yellow')+post_color)
80
+ str.gsub!(/%bggrn/, pre_color+colorize('on_green')+post_color)
81
+ str.gsub!(/%bgmag/, pre_color+colorize('on_magenta')+post_color)
82
+ str.gsub!(/%bgblk/, pre_color+colorize('on_black')+post_color)
83
+ str.gsub!(/%bgred/, pre_color+colorize('on_red')+post_color)
84
+ str.gsub!(/%bgcyn/, pre_color+colorize('on_cyan')+post_color)
85
+ str.gsub!(/%bgwhi/, pre_color+colorize('on_white')+post_color)
86
+
87
+ str
88
+ end
89
+
90
+ #
91
+ # Resets coloring so that it's back to normal.
92
+ #
93
+ def reset_color
94
+ return if not supports_color?
95
+ print(colorize('clear'))
96
+ end
97
+
98
+ #
99
+ # Colorize if this shell supports it
100
+ #
101
+ def do_colorize(*color)
102
+ supports_color?() ? ansi(*color) : ''
103
+ end
104
+ end
105
+
106
+ end end
@@ -0,0 +1,418 @@
1
+ # -*- coding: binary -*-
2
+
3
+ module Rex
4
+ module Text
5
+
6
+ ###
7
+ #
8
+ # Prints text in a tablized format. Pretty lame at the moment, but
9
+ # whatever.
10
+ #
11
+ ###
12
+ class Table
13
+
14
+ #
15
+ # Initializes a text table instance using the supplied properties. The
16
+ # Table class supports the following hash attributes:
17
+ #
18
+ # Header
19
+ #
20
+ # The string to display as a heading above the table. If none is
21
+ # specified, no header will be displayed.
22
+ #
23
+ # HeaderIndent
24
+ #
25
+ # The amount of space to indent the header. The default is zero.
26
+ #
27
+ # Columns
28
+ #
29
+ # The array of columns that will exist within the table.
30
+ #
31
+ # Rows
32
+ #
33
+ # The array of rows that will exist.
34
+ #
35
+ # Width
36
+ #
37
+ # The maximum width of the table in characters.
38
+ #
39
+ # Indent
40
+ #
41
+ # The number of characters to indent the table.
42
+ #
43
+ # CellPad
44
+ #
45
+ # The number of characters to put between each horizontal cell.
46
+ #
47
+ # Prefix
48
+ #
49
+ # The text to prefix before the table.
50
+ #
51
+ # Postfix
52
+ #
53
+ # The text to affix to the end of the table.
54
+ #
55
+ # Sortindex
56
+ #
57
+ # The column to sort the table on, -1 disables sorting.
58
+ #
59
+ def initialize(opts = {})
60
+ self.header = opts['Header']
61
+ self.headeri = opts['HeaderIndent'] || 0
62
+ self.columns = opts['Columns'] || []
63
+ # updated below if we got a "Rows" option
64
+ self.rows = []
65
+
66
+ self.width = opts['Width'] || 80
67
+ self.indent = opts['Indent'] || 0
68
+ self.cellpad = opts['CellPad'] || 2
69
+ self.prefix = opts['Prefix'] || ''
70
+ self.postfix = opts['Postfix'] || ''
71
+ self.colprops = []
72
+ self.scterm = /#{opts['SearchTerm']}/mi if opts['SearchTerm']
73
+
74
+ self.sort_index = opts['SortIndex'] || 0
75
+ self.sort_order = opts['SortOrder'] || :forward
76
+
77
+ # Default column properties
78
+ self.columns.length.times { |idx|
79
+ self.colprops[idx] = {}
80
+ self.colprops[idx]['MaxWidth'] = self.columns[idx].length
81
+ }
82
+
83
+ # ensure all our internal state gets updated with the given rows by
84
+ # using add_row instead of just adding them to self.rows. See #3825.
85
+ opts['Rows'].each { |row| add_row(row) } if opts['Rows']
86
+
87
+ # Merge in options
88
+ if (opts['ColProps'])
89
+ opts['ColProps'].each_key { |col|
90
+ idx = self.columns.index(col)
91
+
92
+ if (idx)
93
+ self.colprops[idx].merge!(opts['ColProps'][col])
94
+ end
95
+ }
96
+ end
97
+
98
+ end
99
+
100
+ #
101
+ # Converts table contents to a string.
102
+ #
103
+ def to_s
104
+ str = prefix.dup
105
+ str << header_to_s || ''
106
+ str << columns_to_s || ''
107
+ str << hr_to_s || ''
108
+
109
+ sort_rows
110
+ rows.each { |row|
111
+ if (is_hr(row))
112
+ str << hr_to_s
113
+ else
114
+ str << row_to_s(row) if row_visible(row)
115
+ end
116
+ }
117
+
118
+ str << postfix
119
+
120
+ return str
121
+ end
122
+
123
+ #
124
+ # Converts table contents to a csv
125
+ #
126
+ def to_csv
127
+ str = ''
128
+ str << ( columns.join(",") + "\n" )
129
+ rows.each { |row|
130
+ next if is_hr(row) || !row_visible(row)
131
+ str << ( row.map{|x|
132
+ x = x.to_s
133
+ x.gsub(/[\r\n]/, ' ').gsub(/\s+/, ' ').gsub('"', '""')
134
+ }.map{|x| "\"#{x}\"" }.join(",") + "\n" )
135
+ }
136
+ str
137
+ end
138
+
139
+ #
140
+ #
141
+ # Returns the header string.
142
+ #
143
+ def header_to_s # :nodoc:
144
+ if (header)
145
+ pad = " " * headeri
146
+
147
+ return pad + header + "\n" + pad + "=" * header.length + "\n\n"
148
+ end
149
+
150
+ return ''
151
+ end
152
+
153
+ #
154
+ # Prints the contents of the table.
155
+ #
156
+ def print
157
+ puts to_s
158
+ end
159
+
160
+ #
161
+ # Adds a row using the supplied fields.
162
+ #
163
+ def <<(fields)
164
+ add_row(fields)
165
+ end
166
+
167
+ #
168
+ # Adds a row with the supplied fields.
169
+ #
170
+ def add_row(fields = [])
171
+ if fields.length != self.columns.length
172
+ raise RuntimeError, 'Invalid number of columns!'
173
+ end
174
+ fields.each_with_index { |field, idx|
175
+ # Remove whitespace and ensure String format
176
+ field = field.to_s.strip
177
+ if (colprops[idx]['MaxWidth'] < field.to_s.length)
178
+ old = colprops[idx]['MaxWidth']
179
+ colprops[idx]['MaxWidth'] = field.to_s.length
180
+ end
181
+ }
182
+
183
+ rows << fields
184
+ end
185
+
186
+ #
187
+ # Sorts the rows based on the supplied index of sub-arrays
188
+ # If the supplied index is an IPv4 address, handle it differently, but
189
+ # avoid actually resolving domain names.
190
+ #
191
+ def sort_rows(index = sort_index, order = sort_order)
192
+ return if index == -1
193
+ return unless rows
194
+ rows.sort! do |a,b|
195
+ if a[index].nil?
196
+ cmp = -1
197
+ elsif b[index].nil?
198
+ cmp = 1
199
+ elsif valid_ip?(a[index]) and valid_ip?(b[index])
200
+ cmp = IPAddr.new(a[index]) <=> IPAddr.new(b[index])
201
+ elsif a[index] =~ /^[0-9]+$/ and b[index] =~ /^[0-9]+$/
202
+ cmp = a[index].to_i <=> b[index].to_i
203
+ elsif a[index].kind_of?(IPAddr) && a[index].kind_of?(IPAddr) && a[index].ipv6? && b[index].ipv4?
204
+ cmp = 1
205
+ elsif a[index].kind_of?(IPAddr) && b[index].kind_of?(IPAddr) && a[index].ipv4? && b[index].ipv6?
206
+ cmp = -1
207
+ else
208
+ cmp = a[index] <=> b[index] # assumes otherwise comparable.
209
+ end
210
+ order == :forward ? cmp : -cmp
211
+ end
212
+ end
213
+
214
+ #
215
+ # Adds a horizontal line.
216
+ #
217
+ def add_hr
218
+ rows << '__hr__'
219
+ end
220
+
221
+ #
222
+ # Returns new sub-table with headers and rows maching column names submitted
223
+ #
224
+ #
225
+ # Flips table 90 degrees left
226
+ #
227
+ def drop_left
228
+ tbl = self.class.new(
229
+ 'Columns' => Array.new(self.rows.count+1,' '),
230
+ 'Header' => self.header,
231
+ 'Indent' => self.indent)
232
+ (self.columns.count+1).times do |ti|
233
+ row = self.rows.map {|r| r[ti]}.unshift(self.columns[ti]).flatten
234
+ # insert our col|row break. kind of hackish
235
+ row[1] = "| #{row[1]}" unless row.all? {|e| e.nil? || e.empty?}
236
+ tbl << row
237
+ end
238
+ return tbl
239
+ end
240
+
241
+ def valid_ip?(value)
242
+ begin
243
+ IPAddr.new value
244
+ true
245
+ rescue IPAddr::InvalidAddressError
246
+ false
247
+ end
248
+ end
249
+
250
+ #
251
+ # Build table from CSV dump
252
+ #
253
+ def self.new_from_csv(csv)
254
+ # Read in or keep data, get CSV or die
255
+ if csv.is_a?(String)
256
+ csv = File.file?(csv) ? CSV.read(csv) : CSV.parse(csv)
257
+ end
258
+ # Adjust for skew
259
+ if csv.first == ["Keys", "Values"]
260
+ csv.shift # drop marker
261
+ cols = []
262
+ rows = []
263
+ csv.each do |row|
264
+ cols << row.shift
265
+ rows << row
266
+ end
267
+ tbl = self.new('Columns' => cols)
268
+ rows.in_groups_of(cols.count) {|r| tbl << r.flatten}
269
+ else
270
+ tbl = self.new('Columns' => csv.shift)
271
+ while !csv.empty? do
272
+ tbl << csv.shift
273
+ end
274
+ end
275
+ return tbl
276
+ end
277
+
278
+ def [](*col_names)
279
+ tbl = self.class.new('Indent' => self.indent,
280
+ 'Header' => self.header,
281
+ 'Columns' => col_names)
282
+ indexes = []
283
+
284
+ col_names.each do |col_name|
285
+ index = self.columns.index(col_name)
286
+ raise RuntimeError, "Invalid column name #{col_name}" if index.nil?
287
+ indexes << index
288
+ end
289
+
290
+ self.rows.each do |old_row|
291
+ new_row = []
292
+ indexes.map {|i| new_row << old_row[i]}
293
+ tbl << new_row
294
+ end
295
+
296
+ return tbl
297
+ end
298
+
299
+
300
+ alias p print
301
+
302
+ attr_accessor :header, :headeri # :nodoc:
303
+ attr_accessor :columns, :rows, :colprops # :nodoc:
304
+ attr_accessor :width, :indent, :cellpad # :nodoc:
305
+ attr_accessor :prefix, :postfix # :nodoc:
306
+ attr_accessor :sort_index, :sort_order, :scterm # :nodoc:
307
+
308
+ protected
309
+
310
+ #
311
+ # Returns if a row should be visible or not
312
+ #
313
+ def row_visible(row)
314
+ return true if self.scterm.nil?
315
+ row_to_s(row).match(self.scterm)
316
+ end
317
+
318
+ #
319
+ # Defaults cell widths and alignments.
320
+ #
321
+ def defaults # :nodoc:
322
+ self.columns.length.times { |idx|
323
+ }
324
+ end
325
+
326
+ #
327
+ # Checks to see if the row is an hr.
328
+ #
329
+ def is_hr(row) # :nodoc:
330
+ return ((row.kind_of?(String)) && (row == '__hr__'))
331
+ end
332
+
333
+ #
334
+ # Converts the columns to a string.
335
+ #
336
+ def columns_to_s # :nodoc:
337
+ nameline = ' ' * indent
338
+ barline = nameline.dup
339
+ last_col = nil
340
+ last_idx = nil
341
+ columns.each_with_index { |col,idx|
342
+ if (last_col)
343
+ # This produces clean to_s output without truncation
344
+ # Preserves full string in cells for to_csv output
345
+ padding = pad(' ', last_col, last_idx)
346
+ nameline << padding
347
+ remainder = padding.length - cellpad
348
+ remainder = 0 if remainder < 0
349
+ barline << (' ' * (cellpad + remainder))
350
+ end
351
+
352
+ nameline << col
353
+ barline << ('-' * col.length)
354
+
355
+ last_col = col
356
+ last_idx = idx
357
+ }
358
+
359
+ return "#{nameline}\n#{barline}"
360
+ end
361
+
362
+ #
363
+ # Converts an hr to a string.
364
+ #
365
+ def hr_to_s # :nodoc:
366
+ return "\n"
367
+ end
368
+
369
+ #
370
+ # Converts a row to a string.
371
+ #
372
+ def row_to_s(row) # :nodoc:
373
+ line = ' ' * indent
374
+ last_cell = nil
375
+ last_idx = nil
376
+ row.each_with_index { |cell, idx|
377
+ if (idx != 0)
378
+ line << pad(' ', last_cell.to_s, last_idx)
379
+ end
380
+ # Limit wide cells
381
+ if colprops[idx]['MaxChar']
382
+ last_cell = cell.to_s[0..colprops[idx]['MaxChar'].to_i]
383
+ line << last_cell
384
+ else
385
+ line << cell.to_s
386
+ last_cell = cell
387
+ end
388
+ last_idx = idx
389
+ }
390
+
391
+ return line + "\n"
392
+ end
393
+
394
+ #
395
+ # Pads out with the supplied character for the remainder of the space given
396
+ # some text and a column index.
397
+ #
398
+ def pad(chr, buf, colidx, use_cell_pad = true) # :nodoc:
399
+ # Ensure we pad the minimum required amount
400
+ max = colprops[colidx]['MaxChar'] || colprops[colidx]['MaxWidth']
401
+ max = colprops[colidx]['MaxWidth'] if max.to_i > colprops[colidx]['MaxWidth'].to_i
402
+ remainder = max - buf.length
403
+ remainder = 0 if remainder < 0
404
+ val = chr * remainder
405
+
406
+ if (use_cell_pad)
407
+ val << ' ' * cellpad
408
+ end
409
+
410
+ return val
411
+ end
412
+
413
+
414
+ end
415
+
416
+ end
417
+ end
418
+
@@ -1,5 +1,5 @@
1
1
  module Rex
2
2
  module Text
3
- VERSION = "0.1.1"
3
+ VERSION = "0.1.2"
4
4
  end
5
5
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rex-text
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.1
4
+ version: 0.1.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - David 'thelightcosine' Maloney
@@ -85,7 +85,7 @@ cert_chain:
85
85
  2SpuQH+SWteq3NXkAmFEEqvLJQ4sbptZt8OP8ghL3pVAvZNFmww/YVszSkShSzcg
86
86
  QdihYCSEL2drS2cFd50jBeq71sxUtxbv82DUa2b+
87
87
  -----END CERTIFICATE-----
88
- date: 2016-06-21 00:00:00.000000000 Z
88
+ date: 2016-08-10 00:00:00.000000000 Z
89
89
  dependencies:
90
90
  - !ruby/object:Gem::Dependency
91
91
  name: bundler
@@ -155,6 +155,7 @@ files:
155
155
  - lib/rex/text/binary_manipulation.rb
156
156
  - lib/rex/text/block_api.rb
157
157
  - lib/rex/text/checksum.rb
158
+ - lib/rex/text/color.rb
158
159
  - lib/rex/text/compress.rb
159
160
  - lib/rex/text/ebcdic.rb
160
161
  - lib/rex/text/encode.rb
@@ -166,6 +167,7 @@ files:
166
167
  - lib/rex/text/rand.rb
167
168
  - lib/rex/text/randomize.rb
168
169
  - lib/rex/text/silly.rb
170
+ - lib/rex/text/table.rb
169
171
  - lib/rex/text/unicode.rb
170
172
  - lib/rex/text/version.rb
171
173
  - rex-text.gemspec
metadata.gz.sig CHANGED
Binary file