Completed
Push — master ( b519bb...486e1a )
by Jaspar
25s queued 15s
created

ScannersMixin.modify_scanner()   C

Complexity

Conditions 10

Size

Total Lines 66
Code Lines 37

Duplication

Lines 66
Ratio 100 %

Importance

Changes 0
Metric Value
cc 10
eloc 37
nop 10
dl 66
loc 66
rs 5.9999
c 0
b 0
f 0

How to fix   Long Method    Complexity    Many Parameters   

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:

Complexity

Complex classes like gvm.protocols.gmpv208.entities.scanners.ScannersMixin.modify_scanner() often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

Many Parameters

Methods with many parameters are not only hard to understand, but their parameters also often become inconsistent when you need more, or different data.

There are several approaches to avoid long parameter lists:

1
# -*- coding: utf-8 -*-
2
# Copyright (C) 2021 Greenbone Networks GmbH
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
# pylint:  disable=redefined-builtin
20
21
from enum import Enum
22
from typing import Any, Optional
23
24
from gvm.errors import InvalidArgument, InvalidArgumentType, RequiredArgument
25
from gvm.utils import add_filter, to_bool
26
from gvm.xml import XmlCommand
27
28
29
class ScannerType(Enum):
30
    """Enum for scanner type"""
31
32
    OSP_SCANNER_TYPE = "1"
33
    OPENVAS_SCANNER_TYPE = "2"
34
    CVE_SCANNER_TYPE = "3"
35
    GMP_SCANNER_TYPE = "4"  # formerly slave scanner
36
    GREENBONE_SENSOR_SCANNER_TYPE = "5"
37
38
39
def get_scanner_type_from_string(
40
    scanner_type: Optional[str],
41
) -> Optional[ScannerType]:
42
    """Convert a scanner type string to an actual ScannerType instance
43
44
    Arguments:
45
        scanner_type: Scanner type string to convert to a ScannerType
46
    """
47
    if not scanner_type:
48
        return None
49
50
    scanner_type = scanner_type.lower()
51
52
    if (
53
        scanner_type == ScannerType.OSP_SCANNER_TYPE.value
54
        or scanner_type == 'osp'
55
    ):
56
        return ScannerType.OSP_SCANNER_TYPE
57
58
    if (
59
        scanner_type == ScannerType.OPENVAS_SCANNER_TYPE.value
60
        or scanner_type == 'openvas'
61
    ):
62
        return ScannerType.OPENVAS_SCANNER_TYPE
63
64
    if (
65
        scanner_type == ScannerType.CVE_SCANNER_TYPE.value
66
        or scanner_type == 'cve'
67
    ):
68
        return ScannerType.CVE_SCANNER_TYPE
69
70
    if (
71
        scanner_type == ScannerType.GMP_SCANNER_TYPE.value
72
        or scanner_type == 'gmp'
73
    ):
74
        return ScannerType.GMP_SCANNER_TYPE
75
76
    if (
77
        scanner_type == ScannerType.GREENBONE_SENSOR_SCANNER_TYPE.value
78
        or scanner_type == 'greenbone'
79
    ):
80
        return ScannerType.GREENBONE_SENSOR_SCANNER_TYPE
81
82
    raise InvalidArgument(
83
        argument='scanner_type', function=get_scanner_type_from_string.__name__
84
    )
85
86
87
class ScannersMixin:
88
    def clone_scanner(self, scanner_id: str) -> Any:
89
        """Clone an existing scanner
90
91
        Arguments:
92
            scanner_id: UUID of an existing scanner to clone from
93
94
        Returns:
95
            The response. See :py:meth:`send_command` for details.
96
        """
97
        if not scanner_id:
98
            raise RequiredArgument(
99
                function=self.clone_scanner.__name__, argument='scanner_id'
100
            )
101
102
        cmd = XmlCommand("create_scanner")
103
        cmd.add_element("copy", scanner_id)
104
        return self._send_xml_command(cmd)
105
106 View Code Duplication
    def create_scanner(
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
107
        self,
108
        name: str,
109
        host: str,
110
        port: int,
111
        scanner_type: ScannerType,
112
        credential_id: str,
113
        *,
114
        ca_pub: Optional[str] = None,
115
        comment: Optional[str] = None,
116
    ) -> Any:
117
        """Create a new scanner
118
119
        Arguments:
120
            name: Name of the scanner
121
            host: The host of the scanner
122
            port: The port of the scanner
123
            scanner_type: Type of the scanner.
124
            credential_id: UUID of client certificate credential for the
125
                scanner
126
            ca_pub: Certificate of CA to verify scanner certificate
127
            comment: Comment for the scanner
128
        Returns:
129
            The response. See :py:meth:`send_command` for details.
130
        """
131
        if not name:
132
            raise RequiredArgument(
133
                function=self.create_scanner.__name__, argument='name'
134
            )
135
136
        if not host:
137
            raise RequiredArgument(
138
                function=self.create_scanner.__name__, argument='host'
139
            )
140
141
        if not port:
142
            raise RequiredArgument(
143
                function=self.create_scanner.__name__, argument='port'
144
            )
145
146
        if not scanner_type:
147
            raise RequiredArgument(
148
                function=self.create_scanner.__name__, argument='scanner_type'
149
            )
150
151
        if not credential_id:
152
            raise RequiredArgument(
153
                function=self.create_scanner.__name__, argument='credential_id'
154
            )
155
156
        if not isinstance(scanner_type, ScannerType):
157
            raise InvalidArgumentType(
158
                function=self.create_scanner.__name__,
159
                argument='scanner_type',
160
                arg_type=ScannerType.__name__,
161
            )
162
163
        cmd = XmlCommand("create_scanner")
164
        cmd.add_element("name", name)
165
        cmd.add_element("host", host)
166
        cmd.add_element("port", str(port))
167
        cmd.add_element("type", scanner_type.value)
168
169
        if ca_pub:
170
            cmd.add_element("ca_pub", ca_pub)
171
172
        cmd.add_element("credential", attrs={"id": str(credential_id)})
173
174
        if comment:
175
            cmd.add_element("comment", comment)
176
177
        return self._send_xml_command(cmd)
178
179
    def delete_scanner(
180
        self, scanner_id: str, *, ultimate: Optional[bool] = False
181
    ) -> Any:
182
        """Deletes an existing scanner
183
184
        Arguments:
185
            scanner_id: UUID of the scanner to be deleted.
186
            ultimate: Whether to remove entirely, or to the trashcan.
187
        """
188
        if not scanner_id:
189
            raise RequiredArgument(
190
                function=self.delete_scanner.__name__, argument='scanner_id'
191
            )
192
193
        cmd = XmlCommand("delete_scanner")
194
        cmd.set_attribute("scanner_id", scanner_id)
195
        cmd.set_attribute("ultimate", to_bool(ultimate))
196
197
        return self._send_xml_command(cmd)
198
199 View Code Duplication
    def get_scanners(
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
200
        self,
201
        *,
202
        filter: Optional[str] = None,
203
        filter_id: Optional[str] = None,
204
        trash: Optional[bool] = None,
205
        details: Optional[bool] = None,
206
    ) -> Any:
207
        """Request a list of scanners
208
209
        Arguments:
210
            filter: Filter term to use for the query
211
            filter_id: UUID of an existing filter to use for the query
212
            trash: Whether to get the trashcan scanners instead
213
            details:  Whether to include extra details like tasks using this
214
                scanner
215
216
        Returns:
217
            The response. See :py:meth:`send_command` for details.
218
        """
219
        cmd = XmlCommand("get_scanners")
220
221
        add_filter(cmd, filter, filter_id)
222
223
        if trash is not None:
224
            cmd.set_attribute("trash", to_bool(trash))
225
226
        if details is not None:
227
            cmd.set_attribute("details", to_bool(details))
228
229
        return self._send_xml_command(cmd)
230
231
    def get_scanner(self, scanner_id: str) -> Any:
232
        """Request a single scanner
233
234
        Arguments:
235
            scanner_id: UUID of an existing scanner
236
237
        Returns:
238
            The response. See :py:meth:`send_command` for details.
239
        """
240
        cmd = XmlCommand("get_scanners")
241
242
        if not scanner_id:
243
            raise RequiredArgument(
244
                function=self.get_scanner.__name__, argument='scanner_id'
245
            )
246
247
        cmd.set_attribute("scanner_id", scanner_id)
248
249
        # for single entity always request all details
250
        cmd.set_attribute("details", "1")
251
        return self._send_xml_command(cmd)
252
253 View Code Duplication
    def modify_scanner(
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
254
        self,
255
        scanner_id: str,
256
        *,
257
        scanner_type: Optional[ScannerType] = None,
258
        host: Optional[str] = None,
259
        port: Optional[int] = None,
260
        comment: Optional[str] = None,
261
        name: Optional[str] = None,
262
        ca_pub: Optional[str] = None,
263
        credential_id: Optional[str] = None,
264
    ) -> Any:
265
        """Modifies an existing scanner.
266
267
        Arguments:
268
            scanner_id: UUID of scanner to modify.
269
            scanner_type: New type of the Scanner.
270
            host: Host of the scanner.
271
            port: Port of the scanner.
272
            comment: Comment on scanner.
273
            name: Name of scanner.
274
            ca_pub: Certificate of CA to verify scanner's certificate.
275
            credential_id: UUID of the client certificate credential for the
276
                Scanner.
277
278
        Returns:
279
            The response. See :py:meth:`send_command` for details.
280
        """
281
        if not scanner_id:
282
            raise RequiredArgument(
283
                function=self.modify_scanner.__name__,
284
                argument='scanner_id argument',
285
            )
286
287
        cmd = XmlCommand("modify_scanner")
288
        cmd.set_attribute("scanner_id", scanner_id)
289
290
        if scanner_type is not None:
291
            if not isinstance(scanner_type, ScannerType):
292
                raise InvalidArgumentType(
293
                    function=self.modify_scanner.__name__,
294
                    argument='scanner_type',
295
                    arg_type=ScannerType.__name__,
296
                )
297
298
            cmd.add_element("type", scanner_type.value)
299
300
        if host:
301
            cmd.add_element("host", host)
302
303
        if port:
304
            cmd.add_element("port", str(port))
305
306
        if comment:
307
            cmd.add_element("comment", comment)
308
309
        if name:
310
            cmd.add_element("name", name)
311
312
        if ca_pub:
313
            cmd.add_element("ca_pub", ca_pub)
314
315
        if credential_id:
316
            cmd.add_element("credential", attrs={"id": str(credential_id)})
317
318
        return self._send_xml_command(cmd)
319
320
    def verify_scanner(self, scanner_id: str) -> Any:
321
        """Verify an existing scanner
322
323
        Verifies if it is possible to connect to an existing scanner. It is
324
        *not* verified if the scanner works as expected by the user.
325
326
        Arguments:
327
            scanner_id: UUID of the scanner to be verified
328
329
        Returns:
330
            The response. See :py:meth:`send_command` for details.
331
        """
332
        if not scanner_id:
333
            raise RequiredArgument(
334
                function=self.verify_scanner.__name__, argument='scanner_id'
335
            )
336
337
        cmd = XmlCommand("verify_scanner")
338
        cmd.set_attribute("scanner_id", scanner_id)
339
340
        return self._send_xml_command(cmd)
341