Total Complexity | 59 |
Total Lines | 580 |
Duplicated Lines | 34.48 % |
Changes | 0 |
Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.
Common duplication problems, and corresponding solutions are:
Complex classes like gvm.protocols.gmpv208.entities.scan_configs 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.
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 | # MAYBE we should change filter to filter_string (everywhere) |
||
21 | |||
22 | |||
23 | from typing import Any, List, Optional, Tuple |
||
24 | from lxml.etree import XMLSyntaxError |
||
25 | |||
26 | from gvm.errors import RequiredArgument, InvalidArgument, InvalidArgumentType |
||
27 | from gvm.utils import add_filter, deprecation, is_list_like, to_base64, to_bool |
||
28 | from gvm.xml import XmlCommand |
||
29 | |||
30 | |||
31 | class ScanConfigsMixin: |
||
32 | def clone_scan_config(self, config_id: str) -> Any: |
||
33 | """Clone a scan config from an existing one |
||
34 | |||
35 | Arguments: |
||
36 | config_id: UUID of the existing scan config |
||
37 | |||
38 | Returns: |
||
39 | The response. See :py:meth:`send_command` for details. |
||
40 | """ |
||
41 | if not config_id: |
||
42 | raise RequiredArgument( |
||
43 | function=self.clone_scan_config.__name__, argument='config_id' |
||
44 | ) |
||
45 | |||
46 | cmd = XmlCommand("create_config") |
||
47 | cmd.add_element("copy", config_id) |
||
48 | return self._send_xml_command(cmd) |
||
49 | |||
50 | def create_scan_config( |
||
51 | self, config_id: str, name: str, *, comment: Optional[str] = None |
||
52 | ) -> Any: |
||
53 | """Create a new scan config |
||
54 | |||
55 | Arguments: |
||
56 | config_id: UUID of the existing scan config |
||
57 | name: Name of the new scan config |
||
58 | comment: A comment on the config |
||
59 | |||
60 | Returns: |
||
61 | The response. See :py:meth:`send_command` for details. |
||
62 | """ |
||
63 | if not name: |
||
64 | raise RequiredArgument( |
||
65 | function=self.create_scan_config.__name__, argument='name' |
||
66 | ) |
||
67 | |||
68 | if not config_id: |
||
69 | raise RequiredArgument( |
||
70 | function=self.create_scan_config.__name__, argument='config_id' |
||
71 | ) |
||
72 | |||
73 | cmd = XmlCommand("create_config") |
||
74 | if comment is not None: |
||
75 | cmd.add_element("comment", comment) |
||
76 | cmd.add_element("copy", config_id) |
||
77 | cmd.add_element("name", name) |
||
78 | cmd.add_element("usage_type", "scan") |
||
79 | return self._send_xml_command(cmd) |
||
80 | |||
81 | def create_scan_config_from_osp_scanner( |
||
82 | self, scanner_id: str, name: str, *, comment: Optional[str] = None |
||
83 | ) -> Any: |
||
84 | """Create a new scan config from an ospd scanner. |
||
85 | |||
86 | Create config by retrieving the expected preferences from the given |
||
87 | scanner via OSP. |
||
88 | |||
89 | Arguments: |
||
90 | scanner_id: UUID of an OSP scanner to get config data from |
||
91 | name: Name of the new scan config |
||
92 | comment: A comment on the config |
||
93 | |||
94 | Returns: |
||
95 | The response. See :py:meth:`send_command` for details. |
||
96 | """ |
||
97 | if not name: |
||
98 | raise RequiredArgument( |
||
99 | function=self.create_scan_config_from_osp_scanner.__name__, |
||
100 | argument='name', |
||
101 | ) |
||
102 | |||
103 | if not scanner_id: |
||
104 | raise RequiredArgument( |
||
105 | function=self.create_scan_config_from_osp_scanner.__name__, |
||
106 | argument='scanner_id', |
||
107 | ) |
||
108 | |||
109 | cmd = XmlCommand("create_config") |
||
110 | if comment is not None: |
||
111 | cmd.add_element("comment", comment) |
||
112 | cmd.add_element("scanner", scanner_id) |
||
113 | cmd.add_element("name", name) |
||
114 | cmd.add_element("usage_type", "scan") |
||
115 | return self._send_xml_command(cmd) |
||
116 | |||
117 | def delete_scan_config( |
||
118 | self, config_id: str, *, ultimate: Optional[bool] = False |
||
119 | ) -> Any: |
||
120 | """Deletes an existing config |
||
121 | |||
122 | Arguments: |
||
123 | config_id: UUID of the config to be deleted. |
||
124 | ultimate: Whether to remove entirely, or to the trashcan. |
||
125 | """ |
||
126 | if not config_id: |
||
127 | raise RequiredArgument( |
||
128 | function=self.delete_scan_config.__name__, argument='config_id' |
||
129 | ) |
||
130 | |||
131 | cmd = XmlCommand("delete_config") |
||
132 | cmd.set_attribute("config_id", config_id) |
||
133 | cmd.set_attribute("ultimate", to_bool(ultimate)) |
||
134 | |||
135 | return self._send_xml_command(cmd) |
||
136 | |||
137 | View Code Duplication | def get_scan_configs( |
|
|
|||
138 | self, |
||
139 | *, |
||
140 | filter: Optional[str] = None, |
||
141 | filter_id: Optional[str] = None, |
||
142 | trash: Optional[bool] = None, |
||
143 | details: Optional[bool] = None, |
||
144 | families: Optional[bool] = None, |
||
145 | preferences: Optional[bool] = None, |
||
146 | tasks: Optional[bool] = None, |
||
147 | ) -> Any: |
||
148 | """Request a list of scan configs |
||
149 | |||
150 | Arguments: |
||
151 | filter: Filter term to use for the query |
||
152 | filter_id: UUID of an existing filter to use for the query |
||
153 | trash: Whether to get the trashcan scan configs instead |
||
154 | details: Whether to get config families, preferences, nvt selectors |
||
155 | and tasks. |
||
156 | families: Whether to include the families if no details are |
||
157 | requested |
||
158 | preferences: Whether to include the preferences if no details are |
||
159 | requested |
||
160 | tasks: Whether to get tasks using this config |
||
161 | |||
162 | Returns: |
||
163 | The response. See :py:meth:`send_command` for details. |
||
164 | """ |
||
165 | cmd = XmlCommand("get_configs") |
||
166 | cmd.set_attribute("usage_type", "scan") |
||
167 | |||
168 | add_filter(cmd, filter, filter_id) |
||
169 | |||
170 | if trash is not None: |
||
171 | cmd.set_attribute("trash", to_bool(trash)) |
||
172 | |||
173 | if details is not None: |
||
174 | cmd.set_attribute("details", to_bool(details)) |
||
175 | |||
176 | if families is not None: |
||
177 | cmd.set_attribute("families", to_bool(families)) |
||
178 | |||
179 | if preferences is not None: |
||
180 | cmd.set_attribute("preferences", to_bool(preferences)) |
||
181 | |||
182 | if tasks is not None: |
||
183 | cmd.set_attribute("tasks", to_bool(tasks)) |
||
184 | |||
185 | return self._send_xml_command(cmd) |
||
186 | |||
187 | def get_scan_config( |
||
188 | self, config_id: str, *, tasks: Optional[bool] = None |
||
189 | ) -> Any: |
||
190 | """Request a single scan config |
||
191 | |||
192 | Arguments: |
||
193 | config_id: UUID of an existing scan config |
||
194 | tasks: Whether to get tasks using this config |
||
195 | |||
196 | Returns: |
||
197 | The response. See :py:meth:`send_command` for details. |
||
198 | """ |
||
199 | if not config_id: |
||
200 | raise RequiredArgument( |
||
201 | function=self.get_scan_config.__name__, argument='config_id' |
||
202 | ) |
||
203 | |||
204 | cmd = XmlCommand("get_configs") |
||
205 | cmd.set_attribute("config_id", config_id) |
||
206 | |||
207 | cmd.set_attribute("usage_type", "scan") |
||
208 | |||
209 | if tasks is not None: |
||
210 | cmd.set_attribute("tasks", to_bool(tasks)) |
||
211 | |||
212 | # for single entity always request all details |
||
213 | cmd.set_attribute("details", "1") |
||
214 | |||
215 | return self._send_xml_command(cmd) |
||
216 | |||
217 | def import_scan_config(self, config: str) -> Any: |
||
218 | """Import a scan config from XML |
||
219 | |||
220 | Arguments: |
||
221 | config: Scan Config XML as string to import. This XML must |
||
222 | contain a :code:`<get_configs_response>` root element. |
||
223 | |||
224 | Returns: |
||
225 | The response. See :py:meth:`send_command` for details. |
||
226 | """ |
||
227 | if not config: |
||
228 | raise RequiredArgument( |
||
229 | function=self.import_scan_config.__name__, argument='config' |
||
230 | ) |
||
231 | |||
232 | cmd = XmlCommand("create_config") |
||
233 | |||
234 | try: |
||
235 | cmd.append_xml_str(config) |
||
236 | except XMLSyntaxError as e: |
||
237 | raise InvalidArgument( |
||
238 | function=self.import_scan_config.__name__, argument='config' |
||
239 | ) from e |
||
240 | |||
241 | return self._send_xml_command(cmd) |
||
242 | |||
243 | View Code Duplication | def modify_scan_config_set_nvt_preference( |
|
244 | self, |
||
245 | config_id: str, |
||
246 | name: str, |
||
247 | nvt_oid: str, |
||
248 | *, |
||
249 | value: Optional[str] = None, |
||
250 | ) -> Any: |
||
251 | """Modifies the nvt preferences of an existing scan config. |
||
252 | |||
253 | Arguments: |
||
254 | config_id: UUID of scan config to modify. |
||
255 | name: Name for nvt preference to change. |
||
256 | nvt_oid: OID of the NVT associated with preference to modify |
||
257 | value: New value for the preference. None to delete the preference |
||
258 | and to use the default instead. |
||
259 | """ |
||
260 | if not config_id: |
||
261 | raise RequiredArgument( |
||
262 | function=self.modify_scan_config_set_nvt_preference.__name__, |
||
263 | argument='config_id', |
||
264 | ) |
||
265 | |||
266 | if not nvt_oid: |
||
267 | raise RequiredArgument( |
||
268 | function=self.modify_scan_config_set_nvt_preference.__name__, |
||
269 | argument='nvt_oid', |
||
270 | ) |
||
271 | |||
272 | if not name: |
||
273 | raise RequiredArgument( |
||
274 | function=self.modify_scan_config_set_nvt_preference.__name__, |
||
275 | argument='name', |
||
276 | ) |
||
277 | |||
278 | cmd = XmlCommand("modify_config") |
||
279 | cmd.set_attribute("config_id", str(config_id)) |
||
280 | |||
281 | _xmlpref = cmd.add_element("preference") |
||
282 | |||
283 | _xmlpref.add_element("nvt", attrs={"oid": nvt_oid}) |
||
284 | _xmlpref.add_element("name", name) |
||
285 | |||
286 | if value: |
||
287 | _xmlpref.add_element("value", to_base64(value)) |
||
288 | |||
289 | return self._send_xml_command(cmd) |
||
290 | |||
291 | def modify_scan_config_set_name(self, config_id: str, name: str) -> Any: |
||
292 | """Modifies the name of an existing scan config |
||
293 | |||
294 | Arguments: |
||
295 | config_id: UUID of scan config to modify. |
||
296 | name: New name for the config. |
||
297 | """ |
||
298 | if not config_id: |
||
299 | raise RequiredArgument( |
||
300 | function=self.modify_scan_config_set_name.__name__, |
||
301 | argument='config_id', |
||
302 | ) |
||
303 | |||
304 | if not name: |
||
305 | raise RequiredArgument( |
||
306 | function=self.modify_scan_config_set_name.__name__, |
||
307 | argument='name', |
||
308 | ) |
||
309 | |||
310 | cmd = XmlCommand("modify_config") |
||
311 | cmd.set_attribute("config_id", str(config_id)) |
||
312 | |||
313 | cmd.add_element("name", name) |
||
314 | |||
315 | return self._send_xml_command(cmd) |
||
316 | |||
317 | def modify_scan_config_set_comment( |
||
318 | self, config_id: str, *, comment: Optional[str] = None |
||
319 | ) -> Any: |
||
320 | """Modifies the comment of an existing scan config |
||
321 | |||
322 | Arguments: |
||
323 | config_id: UUID of scan config to modify. |
||
324 | comment: Comment to set on a config. Default is an |
||
325 | empty comment and the previous comment will be |
||
326 | removed. |
||
327 | """ |
||
328 | if not config_id: |
||
329 | raise RequiredArgument( |
||
330 | function=self.modify_scan_config_set_comment.__name__, |
||
331 | argument='config_id argument', |
||
332 | ) |
||
333 | |||
334 | cmd = XmlCommand("modify_config") |
||
335 | cmd.set_attribute("config_id", str(config_id)) |
||
336 | if not comment: |
||
337 | comment = "" |
||
338 | cmd.add_element("comment", comment) |
||
339 | |||
340 | return self._send_xml_command(cmd) |
||
341 | |||
342 | def modify_scan_config_set_scanner_preference( |
||
343 | self, config_id: str, name: str, *, value: Optional[str] = None |
||
344 | ) -> Any: |
||
345 | """Modifies the scanner preferences of an existing scan config |
||
346 | |||
347 | Arguments: |
||
348 | config_id: UUID of scan config to modify. |
||
349 | name: Name of the scanner preference to change |
||
350 | value: New value for the preference. None to delete the preference |
||
351 | and to use the default instead. |
||
352 | |||
353 | """ |
||
354 | if not config_id: |
||
355 | raise RequiredArgument( |
||
356 | function=( |
||
357 | self.modify_scan_config_set_scanner_preference.__name__ |
||
358 | ), |
||
359 | argument='config_id', |
||
360 | ) |
||
361 | |||
362 | if not name: |
||
363 | raise RequiredArgument( |
||
364 | function=( |
||
365 | self.modify_scan_config_set_scanner_preference.__name__ |
||
366 | ), |
||
367 | argument='name argument', |
||
368 | ) |
||
369 | |||
370 | cmd = XmlCommand("modify_config") |
||
371 | cmd.set_attribute("config_id", str(config_id)) |
||
372 | |||
373 | _xmlpref = cmd.add_element("preference") |
||
374 | |||
375 | _xmlpref.add_element("name", name) |
||
376 | |||
377 | if value: |
||
378 | _xmlpref.add_element("value", to_base64(value)) |
||
379 | |||
380 | return self._send_xml_command(cmd) |
||
381 | |||
382 | View Code Duplication | def modify_scan_config_set_nvt_selection( |
|
383 | self, config_id: str, family: str, nvt_oids: List[str] |
||
384 | ) -> Any: |
||
385 | """Modifies the selected nvts of an existing scan config |
||
386 | |||
387 | The manager updates the given family in the config to include only the |
||
388 | given NVTs. |
||
389 | |||
390 | Arguments: |
||
391 | config_id: UUID of scan config to modify. |
||
392 | family: Name of the NVT family to include NVTs from |
||
393 | nvt_oids: List of NVTs to select for the family. |
||
394 | """ |
||
395 | if not config_id: |
||
396 | raise RequiredArgument( |
||
397 | function=self.modify_scan_config_set_nvt_selection.__name__, |
||
398 | argument='config_id', |
||
399 | ) |
||
400 | |||
401 | if not family: |
||
402 | raise RequiredArgument( |
||
403 | function=self.modify_scan_config_set_nvt_selection.__name__, |
||
404 | argument='family argument', |
||
405 | ) |
||
406 | |||
407 | if not is_list_like(nvt_oids): |
||
408 | raise InvalidArgumentType( |
||
409 | function=self.modify_scan_config_set_nvt_selection.__name__, |
||
410 | argument='nvt_oids', |
||
411 | arg_type='list', |
||
412 | ) |
||
413 | |||
414 | cmd = XmlCommand("modify_config") |
||
415 | cmd.set_attribute("config_id", str(config_id)) |
||
416 | |||
417 | _xmlnvtsel = cmd.add_element("nvt_selection") |
||
418 | _xmlnvtsel.add_element("family", family) |
||
419 | |||
420 | for nvt in nvt_oids: |
||
421 | _xmlnvtsel.add_element("nvt", attrs={"oid": nvt}) |
||
422 | |||
423 | return self._send_xml_command(cmd) |
||
424 | |||
425 | View Code Duplication | def modify_scan_config_set_family_selection( |
|
426 | self, |
||
427 | config_id: str, |
||
428 | families: List[Tuple[str, bool, bool]], |
||
429 | *, |
||
430 | auto_add_new_families: Optional[bool] = True, |
||
431 | ) -> Any: |
||
432 | """ |
||
433 | Selected the NVTs of a scan config at a family level. |
||
434 | |||
435 | Arguments: |
||
436 | config_id: UUID of scan config to modify. |
||
437 | families: A list of tuples (str, bool, bool): |
||
438 | str: the name of the NVT family selected, |
||
439 | bool: add new NVTs to the family automatically, |
||
440 | bool: include all NVTs from the family |
||
441 | auto_add_new_families: Whether new families should be added to the |
||
442 | scan config automatically. Default: True. |
||
443 | """ |
||
444 | if not config_id: |
||
445 | raise RequiredArgument( |
||
446 | function=self.modify_scan_config_set_family_selection.__name__, |
||
447 | argument='config_id', |
||
448 | ) |
||
449 | |||
450 | if not is_list_like(families): |
||
451 | raise InvalidArgumentType( |
||
452 | function=self.modify_scan_config_set_family_selection.__name__, |
||
453 | argument='families', |
||
454 | arg_type='list', |
||
455 | ) |
||
456 | |||
457 | cmd = XmlCommand("modify_config") |
||
458 | cmd.set_attribute("config_id", str(config_id)) |
||
459 | |||
460 | _xmlfamsel = cmd.add_element("family_selection") |
||
461 | _xmlfamsel.add_element("growing", to_bool(auto_add_new_families)) |
||
462 | |||
463 | for family in families: |
||
464 | _xmlfamily = _xmlfamsel.add_element("family") |
||
465 | _xmlfamily.add_element("name", family[0]) |
||
466 | |||
467 | if len(family) != 3: |
||
468 | raise InvalidArgument( |
||
469 | "Family must be a tuple of 3. (str, bool, bool)" |
||
470 | ) |
||
471 | |||
472 | if not isinstance(family[1], bool) or not isinstance( |
||
473 | family[2], bool |
||
474 | ): |
||
475 | raise InvalidArgumentType( |
||
476 | function=( |
||
477 | self.modify_scan_config_set_family_selection.__name__ |
||
478 | ), |
||
479 | argument='families', |
||
480 | arg_type='[tuple(str, bool, bool)]', |
||
481 | ) |
||
482 | |||
483 | _xmlfamily.add_element("all", to_bool(family[2])) |
||
484 | _xmlfamily.add_element("growing", to_bool(family[1])) |
||
485 | |||
486 | return self._send_xml_command(cmd) |
||
487 | |||
488 | def modify_scan_config( |
||
489 | self, config_id: str, selection: Optional[str] = None, **kwargs |
||
490 | ) -> Any: |
||
491 | """Modifies an existing scan config. |
||
492 | |||
493 | DEPRECATED. Please use *modify_config_set_* methods instead. |
||
494 | |||
495 | modify_config has four modes to operate depending on the selection. |
||
496 | |||
497 | Arguments: |
||
498 | config_id: UUID of scan config to modify. |
||
499 | selection: one of 'scan_pref', 'nvt_pref', 'nvt_selection' or |
||
500 | 'family_selection' |
||
501 | name: New name for preference. |
||
502 | value: New value for preference. |
||
503 | nvt_oids: List of NVTs associated with preference to modify. |
||
504 | family: Name of family to modify. |
||
505 | |||
506 | Returns: |
||
507 | The response. See :py:meth:`send_command` for details. |
||
508 | """ |
||
509 | if not config_id: |
||
510 | raise RequiredArgument( |
||
511 | function=self.modify_scan_config.__name__, |
||
512 | argument='config_id argument', |
||
513 | ) |
||
514 | |||
515 | if selection is None: |
||
516 | deprecation( |
||
517 | "Using modify_config to update the comment of a scan config is" |
||
518 | "deprecated. Please use modify_scan_config_set_comment instead." |
||
519 | ) |
||
520 | return self.modify_scan_config_set_comment( |
||
521 | config_id, comment=kwargs.get("comment") |
||
522 | ) |
||
523 | |||
524 | if selection not in ( |
||
525 | "nvt_pref", |
||
526 | "scan_pref", |
||
527 | "family_selection", |
||
528 | "nvt_selection", |
||
529 | ): |
||
530 | raise InvalidArgument( |
||
531 | "selection must be one of nvt_pref, " |
||
532 | "scan_pref, family_selection or " |
||
533 | "nvt_selection" |
||
534 | ) |
||
535 | |||
536 | if selection == "nvt_pref": |
||
537 | deprecation( |
||
538 | "Using modify_scan_config to update a nvt preference of a scan " |
||
539 | "config is deprecated. Please use " |
||
540 | "modify_scan_config_set_nvt_preference instead." |
||
541 | ) |
||
542 | return self.modify_scan_config_set_nvt_preference( |
||
543 | config_id, **kwargs |
||
544 | ) |
||
545 | |||
546 | if selection == "scan_pref": |
||
547 | deprecation( |
||
548 | "Using modify_scan_config to update a scanner preference of a " |
||
549 | "scan config is deprecated. Please use " |
||
550 | "modify_scan_config_set_scanner_preference instead." |
||
551 | ) |
||
552 | return self.modify_scan_config_set_scanner_preference( |
||
553 | config_id, **kwargs |
||
554 | ) |
||
555 | |||
556 | if selection == "nvt_selection": |
||
557 | deprecation( |
||
558 | "Using modify_scan_config to update a nvt selection of a " |
||
559 | "scan config is deprecated. Please use " |
||
560 | "modify_scan_config_set_nvt_selection instead." |
||
561 | ) |
||
562 | return self.modify_scan_config_set_nvt_selection( |
||
563 | config_id, **kwargs |
||
564 | ) |
||
565 | |||
566 | deprecation( |
||
567 | "Using modify_scan_config to update a family selection of a " |
||
568 | "scan config is deprecated. Please use " |
||
569 | "modify_scan_config_set_family_selection instead." |
||
570 | ) |
||
571 | return self.modify_scan_config_set_family_selection(config_id, **kwargs) |
||
572 | |||
573 | def sync_scan_config(self) -> Any: |
||
574 | """Request an OSP config synchronization with scanner |
||
575 | |||
576 | Returns: |
||
577 | The response. See :py:meth:`send_command` for details. |
||
578 | """ |
||
579 | return self._send_xml_command(XmlCommand("sync_config")) |
||
580 |