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_output/"

	@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



291
292
293
294
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
# File 'lib/nasldoc/cli/application.rb', line 291

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
# File 'lib/nasldoc/cli/application.rb', line 253

def remove_blacklist file_list
	blacklist = [
		"apple_device_model_list.inc",
		"blacklist_",
		"custom_CA.inc",
		"daily_badip",
		"daily_badurl.inc",
		"known_CA.inc",
		"oui.inc",
		"oval-definitions-schematron.inc",
		"plugin_feed_info.inc",
		"sc_families.inc",
		"scap_schema.inc",
		"ssl_known_cert.inc",
                                     "ssh_get_info2",
                                     "torture_cgi",
                                     "daily_badip3.inc",
                                     "cisco_ios.inc",
		"ovaldi32",
		"ovaldi64",
		"os_cves.inc",
                                     "kernel_cves.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



326
327
328
329
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
# File 'lib/nasldoc/cli/application.rb', line 326

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