Class: NaslDoc::CLI::Application

Inherits:
Object
  • Object
show all
Defined in:
lib/nasldoc/cli/application.rb

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initializeApplication

Initializes the Application class

  • Sets the default output directory to nasldoc_output/

  • Sets the template directory to lib/templates

  • Sets the assets directory to lib/assets



40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
# File 'lib/nasldoc/cli/application.rb', line 40

def initialize
  @file_list = Array.new
  @function_count = 0
  @error_count = 0
  @options = Hash.new

  @options[:output_directory] = "nasldoc_ouput/"

  @functions = Array.new
  @globals = Array.new
  @includes = Array.new

  @overview = nil

  @fn_ns_map = {}
  @obj_ns_map = {}
  @obj_fn_map = {}

  @namespaces = []

  @template_dir = Pathname.new(__FILE__).realpath.to_s.gsub('cli/application.rb', 'templates')
  @asset_dir = Pathname.new(__FILE__).realpath.to_s.gsub('cli/application.rb', 'assets')
  @current_file = "(unknown)"
end

Instance Attribute Details

#error_countObject

Returns the value of attribute error_count.



32
33
34
# File 'lib/nasldoc/cli/application.rb', line 32

def error_count
  @error_count
end

Instance Method Details

#base(path) ⇒ Object

Generates the base name for a path

Returns:

  • htmlized file name for .inc file



75
76
77
# File 'lib/nasldoc/cli/application.rb', line 75

def base path
  File.basename(path, '.inc')
end

#build_file_page(path) ⇒ Object

Processes each .inc file and sets instance variables for each template



126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
# File 'lib/nasldoc/cli/application.rb', line 126

def build_file_page path
  puts "[*] Processing file: #{path}"
  @current_file = File.basename(path)
  contents = File.open(path, "rb") { |f| f.read }

  # Parse the input file.
  begin
    tree = Nasl::Parser.new.parse(contents, path)
  rescue Nasl::ParseException, Nasl::TokenException
    puts "[!!!] File '#{path}' couldn't be parsed. It should be added to the blacklist."
    return nil
  end

  # get namespace mapping
  build_namespace_map(tree, @namespaces, @fn_ns_map, @obj_ns_map, @obj_fn_map)
  
  # Collect the functions.
  @functions = Hash.new()
  tree.all(:Function).map do |fn|
    ns = @fn_ns_map[fn.to_s]
    show_ns = 0
    if(fn.fn_type == "normal" and !ns.nil?)
      show_ns = 1
    end
    code_snip = fn.context(nil, false, false)
    if (!code_snip.nil?)
      code_snip = code_snip.gsub(/#*$/, "").rstrip
    end
    @functions[fn.to_s] = {
      :name => fn.name.name,
      :code => code_snip,
      :params => fn.params.map(&:name),
      :namespace => ns,
      :fn_type => fn.fn_type,
      :show_ns => show_ns,
      :object => @obj_fn_map[fn.to_s]
    }
    @function_count += 1
  end

  @funcs_prv = {}
  @funcs_pub = {}

  for function in tree.all(:Function) do
    if (defined? function.tokens[0].type and function.tokens[0].type == :PUBLIC)
      @funcs_pub[function.to_s] = @functions[function.to_s]
    elsif (defined? function.tokens[0].type and function.tokens[0].type == :PRIVATE)
      @funcs_prv[function.to_s] = @functions[function.to_s]
    elsif (function.fn_type == 'obj' and defined? function.tokens[0].type and function.tokens[0].type.nil?)
      if(obj_fn_map[function.to_s] == function.name.name) # handle constructor
        @funcs_pub[function.to_s] = @functions[function.to_s]
      else
        @funcs_prv[function.to_s] = @functions[function.to_s]
      end
    elsif (function.name.name =~ /^_/)
      @funcs_prv[function.to_s] = @functions[function.to_s]
    else
      @funcs_pub[function.to_s] = @functions[function.to_s]
    end
  end
#       @funcs_prv = @functions.select { |n, p| n =~ /^_/ }
#       @funcs_pub = @functions.reject { |n, p| @funcs_prv.key? n }

  # Collect the globals.
  @globals = tree.all(:Global).map(&:idents).flatten.map do |id|
    if id.is_a? Nasl::Assignment
      id.lval.name
    else
      id.name
    end
  end.sort

  @globs_prv = @globals.select { |n| n =~ /^_/ }
  @globs_pub = @globals.reject { |n| @globs_prv.include? n }

  # Collect the includes.
  @includes = tree.all(:Include).map(&:filename).map(&:text).sort

  # Parse the comments.
  @comments = tree.all(:Comment)
  puts "[**] #{@comments.size} comment(s) were found"
  @comments.map! do |comm|
    begin
      NaslDoc::CLI::Comment.new(comm, path)
    rescue CommentException => e
      # A short message is okay for format errors.
      puts "[!!!] #{e.class.name} #{e.message}"
      @error_count += 1
      nil
    rescue Exception => e
      # A detailed message is given for programming errors.
      puts "[!!!] #{e.class.name} #{e.message}"
      puts e.backtrace.map{ |l| l.prepend "[!!!!] " }.join("\n")
      nil
    end
  end
  @comments.compact!
  @comments.keep_if &:valid
  puts "[**] #{@comments.size} nasldoc comment(s) were parsed"

  # Find the overview comment.
  @overview = @comments.select{ |c| c.type == :file }.shift

  build_template "file", path
end

#build_file_pagesObject

Builds each page from the file_list



233
234
235
236
237
# File 'lib/nasldoc/cli/application.rb', line 233

def build_file_pages
  @file_list.each do |f|
    build_file_page(f)
  end
end

#build_namespace_map(tree, namespaces, fn_map, obj_map, obj_fn_map, level = 0, prefix = nil, object = nil) ⇒ Object

Generates namespace mappings



87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
# File 'lib/nasldoc/cli/application.rb', line 87

def build_namespace_map(tree, namespaces, fn_map, obj_map, obj_fn_map, level=0, prefix = nil, object = nil)
  cur_namespace = prefix
  for node in tree do
    if(node.class.to_s == "Nasl::Namespace")
      if(level == 0)
        namespaces << node.name.name
        build_namespace_map(node, namespaces, fn_map, obj_map, obj_fn_map, level + 1, node.name.name)
      else
        ns = prefix + '::' + node.name.name
        namespaces << ns
        build_namespace_map(node, namespaces, fn_map, obj_map, obj_fn_map, level + 1, ns)
      end
    elsif(node.class.to_s == "Nasl::Function")
      fn_map[node.to_s] = cur_namespace
      if(!object.nil?)
        obj_fn_map[node.to_s] = object 
      end
    elsif(node.class.to_s == "Nasl::Object")
      obj_map[node.to_s] = cur_namespace
      build_namespace_map(node, namespaces, fn_map, obj_map, obj_fn_map, level + 1, cur_namespace, node.name.name)
    end
  end
end

#build_template(name, path = nil) ⇒ Object

Compiles a template for each file



112
113
114
115
116
117
118
119
120
121
122
123
# File 'lib/nasldoc/cli/application.rb', line 112

def build_template name, path=nil
  path ||= name

  dest = url(path)
  puts "[**] Creating #{dest}"
  @erb = ERB.new File.new("#{@template_dir}/#{name}.erb").read, nil, "%"
  html = @erb.result(get_binding)

  File.open("#{@options[:output_directory]}/#{dest}", 'w+') do |f|
    f.puts html
  end
end

#copy_assetsObject

Copies required assets to the final build directory



240
241
242
# File 'lib/nasldoc/cli/application.rb', line 240

def copy_assets
  puts `cp -vr #{@asset_dir}/* #{@options[:output_directory]}/`
end

#get_bindingObject

For ERB Support

Returns:

  • ERB Binding for access to instance variables in templates



68
69
70
# File 'lib/nasldoc/cli/application.rb', line 68

def get_binding
  binding
end

#parse_argsObject

Parses the command line arguments



295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
# File 'lib/nasldoc/cli/application.rb', line 295

def parse_args
  opts = OptionParser.new do |opt|
    opt.banner = "#{APP_NAME} v#{VERSION}\nTenable Network Security.\[email protected]\n\n"
    opt.banner << "Usage: #{APP_NAME} [options] [file|directory]"

    opt.separator ''
    opt.separator 'Options'

    opt.on('-o', '--output DIRECTORY', "Directory to output results to, created if it doesn't exit") do |option|
      @options[:output_directory] = option
    end

    opt.separator ''
    opt.separator 'Other Options'

    opt.on_tail('-v', '--version', "Shows application version information") do
      puts "#{APP_NAME} - #{VERSION}"
      exit
    end

    opt.on_tail('-?', '--help', 'Show this message') do
      puts opt.to_s + "\n"
      exit
    end
  end

  if ARGV.length != 0
    opts.parse!
  else
    puts opts.to_s + "\n"
    exit
  end
end

Prints documentation stats to stdout



245
246
247
248
249
250
# File 'lib/nasldoc/cli/application.rb', line 245

def print_documentation_stats
  puts "\n\nDocumentation Statistics"
  puts "Files: #{@file_list.size}"
  puts "Functions: #{@function_count}"
  puts "Errors: #{@error_count}"
end

#remove_blacklist(file_list) ⇒ Object

Removes blacklisted files from the file list



253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
# File 'lib/nasldoc/cli/application.rb', line 253

def remove_blacklist file_list
  blacklist = [
    "apple_device_model_list.inc",
    "blacklist_dss.inc",
    "blacklist_rsa.inc",
    "blacklist_ssl_rsa1024.inc",
    "blacklist_ssl_rsa2048.inc",
    "custom_CA.inc",
    "daily_badip.inc",
    "daily_badip2.inc",
    "daily_badurl.inc",
    "known_CA.inc",
    "oui.inc",
    "oval-definitions-schematron.inc",
    "ovaldi32-rhel5.inc",
    "ovaldi32-win-dyn-v100.inc",
    "ovaldi32-win-dyn-v90.inc",
    "ovaldi32-win-static.inc",
    "ovaldi64-rhel5.inc",
    "ovaldi64-win-dyn-v100.inc",
    "ovaldi64-win-dyn-v90.inc",
    "ovaldi64-win-static.inc",
    "plugin_feed_info.inc",
    "sc_families.inc",
    "scap_schema.inc",
    "ssl_known_cert.inc"
  ]

  new_file_list = file_list.dup

  file_list.each_with_index do |file, index|
    blacklist.each do |bf|
      if file =~ /#{bf}/
        new_file_list.delete(file)
      end
    end
  end

  return new_file_list
end

#runObject

Main function for running nasldoc



330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
# File 'lib/nasldoc/cli/application.rb', line 330

def run
  parse_args

  if File.directory?(ARGV.first) == true
    pattern = File.join(ARGV.first, '**', '*.inc')
    @file_list = Dir.glob pattern
  else
    @file_list << ARGV.first
  end

  # Ensure the output directory exists.
  if File.directory?(@options[:output_directory]) == false
    Dir.mkdir @options[:output_directory]
  end

  # Get rid of non-NASL files.
  @file_list = remove_blacklist(@file_list)

  # Ensure we process files in a consistent order.
  @file_list.sort! do |a, b|
    base(a) <=> base(b)
  end

  puts "[*] Building documentation..."

  build_template "index"
  build_file_pages
  copy_assets

  print_documentation_stats
end

#url(path) ⇒ Object

Generates the HTML base name for a path

Returns:

  • htmlized file name for .inc file



82
83
84
# File 'lib/nasldoc/cli/application.rb', line 82

def url path
  base(path).gsub('.', '_') + '.html'
end