Passed
Pull Request — master (#344)
by Jaspar
01:26
created

start-alert-scan.gmp.main()   B

Complexity

Conditions 3

Size

Total Lines 129
Code Lines 89

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 3
eloc 89
nop 2
dl 0
loc 129
rs 7.36
c 0
b 0
f 0

How to fix   Long Method   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
# -*- coding: utf-8 -*-
2
# Copyright (C) 2018 Henning Häcker
3
#
4
# SPDX-License-Identifier: GPL-3.0-or-later
5
#
6
# This program is free software: you can redistribute it and/or modify
7
# it under the terms of the GNU General Public License as published by
8
# the Free Software Foundation, either version 3 of the License, or
9
# (at your option) any later version.
10
#
11
# This program is distributed in the hope that it will be useful,
12
# but WITHOUT ANY WARRANTY; without even the implied warranty of
13
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14
# GNU General Public License for more details.
15
#
16
# You should have received a copy of the GNU General Public License
17
# along with this program.  If not, see <http://www.gnu.org/licenses/>.
18
19
from typing import List
20
from argparse import ArgumentParser, RawTextHelpFormatter
21
22
23
HELP_TEXT = """
24
        This script makes an E-Mail alert scan.
25
26
        Usage examples: 
27
            $ gvm-script --gmp-username name --gmp-password pass ssh --hostname
28
            ... start-alert-scan.gmp.py +h
29
            ... start-alert-scan.gmp.py ++target-name ++hosts ++ports \
30
                    ++port-list-name +C ++recipient ++sender
31
            ... start-alert-scan.gmp.py ++target-name ++hosts ++port-list-id \
32
                    +C ++recipient ++sender
33
            ... start-alert-scan.gmp.py ++target-id +C ++recipient ++sender
34
    """
35
36
37
def get_config(gmp, config, debug=False):
38
    # get all configs of the openvas instance
39
    # filter for all rows!
40
    res = gmp.get_configs(filter="rows=-1")
41
42
    if config < 0 or config > 4:
43
        raise ValueError("Wrong config identifier. Choose between [0,4].")
44
    # match the config abbreviation to accepted config names
45
    config_list = [
46
        'Full and fast',
47
        'Full and fast ultimate',
48
        'Full and very deep',
49
        'Full and very deep ultimate',
50
        'System Discovery',
51
    ]
52
    template_abbreviation_mapper = {
53
        0: config_list[0],
54
        1: config_list[1],
55
        2: config_list[2],
56
        3: config_list[3],
57
        4: config_list[4],
58
    }
59
60
    for conf in res.xpath('config'):
61
        cid = conf.xpath('@id')[0]
62
        name = conf.xpath('name/text()')[0]
63
64
        # get the config id of the desired template
65
        if template_abbreviation_mapper.get(config) == name:
66
            config_id = cid
67
            if debug:
68
                print(name + ": " + config_id)
69
            break
70
71
    return config_id
0 ignored issues
show
introduced by
The variable config_id does not seem to be defined for all execution paths.
Loading history...
72
73
74
def get_target(
75
    gmp,
76
    target_name: str = None,
77
    hosts: List[str] = None,
78
    ports: str = None,
79
    port_list_name: str = None,
80
    port_list_id: str = None,
81
    debug: bool = False,
82
):
83
    targets = gmp.get_targets()
84
    counter = 0
85
    exists = True
86
    # iterate over existing targets and find a vacant targetName
87
    while exists:
88
        exists = False
89
        if target_name is None:
90
            target_name = "target_{}".format(str(counter))
91
        for target in targets.xpath('target'):
92
            name = target.xpath('name/text()')[0]
93
            if name == target_name:
94
                exists = True
95
                break
96
        counter += 1
97
98
    if debug:
99
        print("target name: {}".format(target_name))
100
101
    if not port_list_id:
102
        # iterate over existing port lists and find a vacant name
103
        existing_port_lists = [""]
104
        for name in gmp.get_port_lists().findall("port_list/name"):
105
            existing_port_lists.append(str(name.text))
106
107
        if port_list_name is None:
108
            port_list_name = "portlist_{}".format(str(counter))
109
        counter = 0
110
        while True:
111
            if port_list_name not in existing_port_lists:
112
                break
113
            counter += 1
114
115
        # create port list
116
        portlist = gmp.create_port_list(port_list_name, ports)
117
        port_list_id = portlist.xpath('@id')[0]
118
        if debug:
119
            print("New Portlist-name:\t{}".format(str(port_list_name)))
120
            print("New Portlist-id:\t{}".format(str(port_list_id)))
121
122
    # integrate port list id into create_target
123
    res = gmp.create_target(target_name, hosts=hosts, port_list_id=port_list_id)
124
    return res.xpath('@id')[0]
125
126
127
def get_alert(
128
    gmp,
129
    sender_email: str,
130
    recipient_email: str,
131
    alert_name: str = None,
132
    debug=False,
133
):
134
135
    # create alert if necessary
136
    alert_object = gmp.get_alerts(filter='name={}'.format(alert_name))
137
    alert = alert_object.xpath('alert')
138
139
    if len(alert) == 0:
140
        print("creating new alert {}".format(alert_name))
141
        gmp.create_alert(
142
            alert_name,
143
            event=gmp.types.AlertEvent.TASK_RUN_STATUS_CHANGED,
144
            event_data={"status": "Done"},
145
            condition=gmp.types.AlertCondition.ALWAYS,
146
            method=gmp.types.AlertMethod.EMAIL,
147
            method_data={
148
                """Task '$n': $e
149
150
After the event $e,
151
the following condition was met: $c
152
153
This email escalation is configured to attach report format '$r'.
154
Full details and other report formats are available on the scan engine.
155
156
$t
157
158
Note:
159
This email was sent to you as a configured security scan escalation.
160
Please contact your local system administrator if you think you
161
should not have received it.
162
""": "message",
163
                "2": "notice",
164
                sender_email: "from_address",
165
                "[OpenVAS-Manager] Task": "subject",
166
                "c402cc3e-b531-11e1-9163-406186ea4fc5": "notice_attach_format",
167
                recipient_email: "to_address",
168
            },
169
        )
170
171
        alert_object = gmp.get_alerts(filter='name={}'.format(recipient_email))
172
        alert = alert_object.xpath('alert')
173
174
    alert_id = alert[0].get('id', 'no id found')
175
    if debug:
176
        print("alert_id: {}".format(str(alert_id)))
177
178
    return alert_id
179
180
181
def get_scanner(gmp):
182
    res = gmp.get_scanners()
183
    scanner_ids = res.xpath('scanner/@id')
184
    return scanner_ids[1]  # default scanner
185
186
187
def create_and_start_task(
188
    gmp,
189
    config_id: str,
190
    target_id: str,
191
    scanner_id: str,
192
    alert_id: str,
193
    alert_name: str,
194
    debug: bool = False,
195
):
196
    # Create the task
197
    tasks = gmp.get_tasks(filter="name~{}".format(alert_name))
198
    task_name = "Alert Scan for Alert {}".format(alert_name)
199
    if tasks:
200
        task_name = "Alert Scan for Alert {} ({})".format(
201
            alert_name, len(tasks.xpath('tasks/@id'))
202
        )
203
    task_comment = "Alert Scan"
204
    res = gmp.create_task(
205
        task_name,
206
        config_id,
207
        target_id,
208
        scanner_id,
209
        alert_ids=[alert_id],
210
        comment=task_comment,
211
    )
212
213
    # Start the task
214
    task_id = res.xpath('@id')[0]
215
    gmp.start_task(task_id)
216
217
    print('Task started: ' + task_name)
218
219
    if debug:
220
        # Stop the task (for performance reasons)
221
        gmp.stop_task(task_id)
222
        print('Task stopped')
223
224
225
def main(gmp, args):
226
    # pylint: disable=undefined-variable, unused-argument
227
228
    parser = ArgumentParser(
229
        prefix_chars="+",
230
        add_help=False,
231
        formatter_class=RawTextHelpFormatter,
232
        description=HELP_TEXT,
233
    )
234
235
    parser.add_argument(
236
        "+h",
237
        "++help",
238
        action="help",
239
        help="Show this help message and exit.",
240
    )
241
242
    target = parser.add_mutually_exclusive_group(required=True)
243
244
    target.add_argument(
245
        "++target-id",
246
        type=str,
247
        dest="target_id",
248
        help="Use an existing by target id",
249
    )
250
251
    target.add_argument(
252
        "++target-name",
253
        type=str,
254
        dest="target_name",
255
        help="Create a target by name",
256
    )
257
258
    parser.add_argument(
259
        "++hosts",
260
        nargs='+',
261
        dest='hosts',
262
        help="Host(s) for the new target",
263
    )
264
265
    ports = parser.add_mutually_exclusive_group()
266
267
    ports.add_argument(
268
        "++port-list-id",
269
        type=str,
270
        dest="port_list_id",
271
        help="An existing portlist id for the new target",
272
    )
273
    ports.add_argument(
274
        "++ports",
275
        type=str,
276
        dest='ports',
277
        help="Ports in the new target: e.g. T:80-80,8080",
278
    )
279
280
    parser.add_argument(
281
        "++port-list-name",
282
        type=str,
283
        dest="port_list_name",
284
        help="Name for the new portlist in the new target",
285
    )
286
287
    parser.add_argument(
288
        "+C",
289
        "++scan_config",
290
        default=0,
291
        type=int,
292
        dest='config',
293
        help="Choose from existing scan config:"
294
        " 0: Full and fast"
295
        " 1: Full and fast ultimate"
296
        " 2: Full and very deep"
297
        " 3: Full and very deep ultimate"
298
        " 4: System Discovery",
299
    )
300
301
    parser.add_argument(
302
        "++recipient",
303
        required=True,
304
        dest='recipient_email',
305
        type=str,
306
        help="Alert recipient E-Mail address",
307
    )
308
309
    parser.add_argument(
310
        "++sender",
311
        required=True,
312
        dest='sender_email',
313
        type=str,
314
        help="Alert senders E-Mail address",
315
    )
316
317
    parser.add_argument(
318
        "++alert-name",
319
        dest='alert_name',
320
        type=str,
321
        help="Optional Alert name",
322
    )
323
324
    script_args, _ = parser.parse_known_args()
325
326
    if script_args.alert_name is None:
327
        script_args.alert_name = script_args.recipient_email
328
329
    config_id = get_config(gmp, script_args.config)
330
    if not script_args.target_id:
331
        target_id = get_target(
332
            gmp,
333
            target_name=script_args.target_id,
334
            hosts=script_args.hosts,
335
            ports=script_args.ports,
336
            port_list_name=script_args.port_list_name,
337
            port_list_id=script_args.port_list_id,
338
        )
339
    else:
340
        target_id = script_args.target_id
341
    alert_id = get_alert(
342
        gmp,
343
        script_args.sender_email,
344
        script_args.recipient_email,
345
        script_args.alert_name,
346
    )
347
    scanner_id = get_scanner(gmp)
348
349
    create_and_start_task(
350
        gmp, config_id, target_id, scanner_id, alert_id, script_args.alert_name
351
    )
352
353
    print("\nScript finished\n")
354
355
356
if __name__ == '__gmp__':
357
    main(gmp, args)
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable args does not seem to be defined.
Loading history...
Comprehensibility Best Practice introduced by
The variable gmp does not seem to be defined.
Loading history...
358