Passed
Pull Request — master (#155)
by Jan
03:30 queued 22s
created

oval_graph.client.Client.kill_web_browsers()   A

Complexity

Conditions 2

Size

Total Lines 3
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 3
CRAP Score 2

Importance

Changes 0
Metric Value
cc 2
eloc 3
nop 1
dl 0
loc 3
rs 10
c 0
b 0
f 0
ccs 3
cts 3
cp 1
crap 2
1 1
import re
2 1
import argparse
3 1
import tempfile
4 1
import os
5 1
import webbrowser
6 1
import subprocess
7 1
from datetime import datetime
8 1
import sys
9
10 1
from .xml_parser import XmlParser
11 1
from .exceptions import NotChecked
12 1
from ._builder_html_graph import BuilderHtmlGraph
13 1
from .__init__ import __version__
14
15
16 1
class Client():
17 1
    def __init__(self, args):
18 1
        self.parser = None
19 1
        self.MESSAGES = self._get_message()
20 1
        self.arg = self.parse_arguments(args)
21 1
        self.hide_passing_tests = self.arg.hide_passing_tests
22 1
        self.source_filename = self.arg.source_filename
23 1
        self.rule_name = self.arg.rule_id
24 1
        self.out = self.arg.output
25 1
        self.verbose = self.arg.verbose
26
27 1
        self.parts = self.get_src('parts')
28 1
        self.START_OF_FILE_NAME = 'graph-of-'
29 1
        self.date = str(datetime.now().strftime("-%d_%m_%Y-%H_%M_%S"))
30 1
        self.isatty = sys.stdout.isatty()
31
32 1
        self.all_rules = self.arg.all
33 1
        self.all_in_one = None
34 1
        self.display_html = None
35 1
        if type(self).__name__ in ('ArfToHtml', 'JsonToHtml'):
36 1
            self._set_attributes_for_ArfToHtml_or_JsonToHtml()
37
38 1
        self.show_failed_rules = False
39 1
        self.show_not_selected_rules = False
40 1
        if type(self).__name__ in ('ArfToHtml', 'ArfToJson'):
41 1
            self._set_attributes_for_ArfToHtml_or_ArfToJson()
42
43 1
        self.xml_parser = None
44 1
        if type(self).__name__ != 'JsonToHtml':
45 1
            self.xml_parser = XmlParser(self.source_filename)
46
47 1
        self.html_builder = None
48 1
        if type(self).__name__ != 'ArfToJson':
49 1
            self.html_builder = BuilderHtmlGraph(self.parts, self.verbose)
50
51 1
        self.web_browsers = []
52
53 1
    def _set_attributes_for_ArfToHtml_or_JsonToHtml(self):
54 1
        self.all_in_one = self.arg.all_in_one
55 1
        self.all_rules = True if self.all_in_one else self.arg.all
56 1
        self.display_html = True if self.out is None else self.arg.display
57
58 1
    def _set_attributes_for_ArfToHtml_or_ArfToJson(self):
59 1
        self.show_failed_rules = self.arg.show_failed_rules
60 1
        self.show_not_selected_rules = self.arg.show_not_selected_rules
61
62 1
    def _get_message(self):
63 1
        MESSAGES = {
64
            'description': '',
65
            'source_filename': '',
66
        }
67 1
        return MESSAGES
68
69 1
    def print_red_text(self, text):
70
        CRED = '\033[91m'
71
        CEND = '\033[0m'
72
        print(CRED + str(text) + CEND)
73
74 1
    def run_gui_and_return_answers(self):
75 1
        if self.isatty:
76 1
            if self.all_rules:
77
                return self._get_rules()
78
            else:
79 1
                try:
80 1
                    import inquirer
81 1
                    return inquirer.prompt(self.get_questions())
82 1
                except ImportError:
83 1
                    print(self.get_selection_rules())
84 1
                    return None
85
        else:
86 1
            return self._get_rules()
87
88 1
    def _get_rules(self):
89 1
        return {
90
            'rules': self._get_only_fail_rule(
91
                self.search_rules_id())} if self.show_failed_rules else {
92
            'rules': self.search_rules_id()}
93
94 1
    def get_list_of_matched_rules(self):
95 1
        return self._get_only_fail_rule(
96
            self.search_rules_id()) if self.show_failed_rules else self.search_rules_id()
97
98 1
    def get_list_of_lines(self):
99 1
        lines = ['== The Rule ID regular expressions ==']
100 1
        for rule in self.get_list_of_matched_rules():
101 1
            lines.append("^" + rule + "$")
102 1
        if self.show_not_selected_rules:
103 1
            for line in self.get_lines_of_wanted_not_selected_rules():
104 1
                lines.append(line)
105 1
        lines.append(
106
            "Interactive rule selection is not available,"
107
            " because inquirer is not installed."
108
            " Copy id of the rule you want to visualize and"
109
            " paste it into a command with regular"
110
            " expression characters(^$).\n"
111
            "Alternatively, use the --all or --all-in-one arguments.")
112 1
        return lines
113
114 1
    def get_selection_rules(self):
115 1
        return "\n".join(self.get_list_of_lines())
116
117 1
    def get_lines_of_wanted_not_selected_rules(self):
118 1
        out = []
119 1
        out.append('== The not selected rule IDs ==')
120 1
        for rule in self._get_wanted_rules_from_array_of_IDs(
121
                self.xml_parser.notselected_rules):
122 1
            out.append(rule + '(Not selected)')
123 1
        return out
124
125 1
    def get_choices(self):
126 1
        if self.show_not_selected_rules:
127 1
            print("\n".join(self.get_lines_of_wanted_not_selected_rules()))
128 1
        return self.get_list_of_matched_rules()
129
130 1
    def get_questions(self):
131 1
        choices = self.get_choices()
132 1
        from inquirer.questions import Checkbox as checkbox
133 1
        questions = [
134
            checkbox(
135
                'rules',
136
                message=(
137
                    "= The Rules IDs = (move - UP and DOWN arrows,"
138
                    " select - SPACE or LEFT and RIGHT arrows, submit - ENTER)"),
139
                choices=choices,
140
            ),
141
        ]
142 1
        return questions
143
144 1
    def _get_only_fail_rule(self, rules):
145 1
        return list(
146
            filter(
147
                lambda rule: self.xml_parser.used_rules[rule]['result'] == 'fail',
148
                rules))
149
150 1
    def _get_wanted_rules_from_array_of_IDs(self, rules):
151 1
        return [
152
            x for x in rules if re.search(
153
                self.rule_name, x)]
154
155 1
    def search_rules_id(self):
156 1
        return self._check_rules_id(
157
            self._get_wanted_rules_from_array_of_IDs(
158
                self.xml_parser.used_rules.keys()),
159
            self._get_wanted_rules_from_array_of_IDs(
160
                self.xml_parser.notselected_rules))
161
162 1
    def _check_rules_id(self, rules, notselected_rules):
163 1
        if len(notselected_rules) and not rules:
164 1
            raise ValueError(
165
                ('Rule(s) "{}" was not selected, '
166
                 "so there are no results. The rule is"
167
                 ' "notselected" because it'
168
                 " wasn't a part of the executed profile"
169
                 " and therefore it wasn't evaluated "
170
                 "during the scan.")
171
                .format(notselected_rules))
172 1
        elif not notselected_rules and not rules:
173 1
            raise ValueError('404 rule "{}" not found!'.format(self.rule_name))
174
        else:
175 1
            return rules
176
177 1
    def get_save_src(self, rule):
178 1
        if self.out is not None:
179 1
            os.makedirs(self.out, exist_ok=True)
180 1
            return os.path.join(
181
                self.out,
182
                self.START_OF_FILE_NAME + rule + '.html')
183 1
        return os.path.join(
184
            tempfile.gettempdir(),
185
            self.START_OF_FILE_NAME + rule + '.html')
186
187 1
    def get_src(self, src):
188 1
        _dir = os.path.dirname(os.path.realpath(__file__))
189 1
        return str(os.path.join(_dir, src))
190
191 1
    def _build_and_save_html(self, dict_oval_trees, src, rules, out_src):
192 1
        self.html_builder.save_html(dict_oval_trees, src, rules)
193 1
        out_src.append(src)
194
195 1
    def open_html(self, out):
196 1
        for src in out:
197 1
            self.open_web_browser(src)
198
199 1
    def open_web_browser(self, src):
200 1
        if self.display_html:
201 1
            try:
202 1
                self.web_browsers.append(subprocess.Popen(["firefox", src]))
203
            except BaseException:
204
                default_web_browser_name = webbrowser.get().name
205
                self.web_browsers.append(subprocess.Popen(
206
                    [default_web_browser_name, src]))
207
208 1
    def kill_web_browsers(self):
209 1
        for web_browser in self.web_browsers:
210 1
            web_browser.kill()
211
212 1
    def _prepare_data(self, rules, dict_oval_trees, out_src):
213 1
        for rule in rules['rules']:
214 1
            try:
215 1
                self._put_to_dict_oval_trees(dict_oval_trees, rule)
216 1
                if not self.all_in_one:
217 1
                    self._build_and_save_html(
218
                        dict_oval_trees, self._get_src_for_one_graph(
219
                            rule), dict(
220
                            rules=[rule]), out_src)
221 1
                    dict_oval_trees = {}
222 1
            except NotChecked as error:
223
                self.print_red_text(error)
224 1
        if self.all_in_one:
225
            self._build_and_save_html(
226
                dict_oval_trees, self.get_save_src(
227
                    'rules' + self.date), rules, out_src)
228
229 1
    def prepare_data(self, rules):
230 1
        out_src = []
231 1
        oval_tree_dict = dict()
232 1
        self._prepare_data(rules, oval_tree_dict, out_src)
233 1
        self.open_html(out_src)
234 1
        return out_src
235
236 1
    def parse_arguments(self, args):
237 1
        self.prepare_parser()
238 1
        return self.parser.parse_args(args)
239
240 1
    def prepare_args_when_output_is_html(self):
241 1
        self.parser.add_argument(
242
            '-i',
243
            '--all-in-one',
244
            action="store_true",
245
            default=False,
246
            help="Processes all rules into one file.")
247 1
        self.parser.add_argument(
248
            '-d',
249
            '--display',
250
            action="store_true",
251
            default=False,
252
            help="Enables opening a web browser with a graph, when is used --output.")
253
254 1
    def prepare_args_when_user_can_list_in_rules(self):
255 1
        self.parser.add_argument(
256
            '--show-failed-rules',
257
            action="store_true",
258
            default=False,
259
            help="Show only FAILED rules")
260 1
        self.parser.add_argument(
261
            '--show-not-selected-rules',
262
            action="store_true",
263
            default=False,
264
            help="Show notselected rules. These rules will not be visualized.")
265
266 1
    def prepare_parser(self):
267 1
        self.parser = argparse.ArgumentParser(
268
            prog='oval-graph',
269
            description=self.MESSAGES.get('description'))
270 1
        self.parser.add_argument(
271
            '--version',
272
            action='version',
273
            version='%(prog)s ' + __version__)
274 1
        self.parser.add_argument(
275
            '-a',
276
            '--all',
277
            action="store_true",
278
            default=False,
279
            help="Process all matched rules.")
280 1
        self.parser.add_argument(
281
            '--hide-passing-tests',
282
            action="store_true",
283
            default=False,
284
            help=(
285
                "Do not display passing tests for better orientation in"
286
                " graphs that contain a large amount of nodes."))
287 1
        self.parser.add_argument(
288
            '-v',
289
            '--verbose',
290
            action="store_true",
291
            default=False,
292
            help="Displays details about the results of the running command.")
293 1
        self.parser.add_argument(
294
            '-o',
295
            '--output',
296
            action="store",
297
            default=None,
298
            help='The file where to save output.')
299 1
        self.parser.add_argument(
300
            "source_filename",
301
            help=self.MESSAGES.get('source_filename'))
302 1
        self.parser.add_argument(
303
            "rule_id", help=(
304
                "Rule ID to be visualized. A part from the full rule ID"
305
                " a part of the ID or a regular expression can be used."
306
                " If brackets are used in the regular expression "
307
                "the regular expression must be quoted."))
308