Completed
Push — master ( 28754c...01e447 )
by
unknown
21s queued 12s
created

get_snmp_privacy_algorithm_from_string()   A

Complexity

Conditions 3

Size

Total Lines 15
Code Lines 10

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 3
eloc 10
nop 1
dl 0
loc 15
rs 9.9
c 0
b 0
f 0
1
# -*- coding: utf-8 -*-
2
# Copyright (C) 2018 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=arguments-differ, redefined-builtin, too-many-lines
20
21
"""
22
Module for communication with gvmd in `Greenbone Management Protocol version 8`_
23
24
.. _Greenbone Management Protocol version 8:
25
    https://docs.greenbone.net/API/GMP/gmp-8.0.html
26
"""
27
from enum import Enum
28
from typing import Any, List, Optional
29
30
from gvm.errors import InvalidArgument, RequiredArgument
31
from gvm.utils import get_version_string
32
from gvm.xml import XmlCommand
33
34
from gvm.protocols.gmpv7 import (
35
    AlertCondition,
36
    AlertEvent,
37
    AlertMethod,
38
    AliveTest,
39
    AssetType,
40
    CredentialFormat,
41
    FeedType,
42
    Gmp as Gmpv7,
43
    HostsOrdering,
44
    InfoType,
45
    _to_bool,
46
    _add_filter,
47
    PermissionSubjectType,
48
    PortRangeType,
49
    ScannerType,
50
    SeverityLevel,
51
    SnmpAuthAlgorithm,
52
    SnmpPrivacyAlgorithm,
53
    get_asset_type_from_string,
54
    get_feed_type_from_string,
55
    get_hosts_ordering_from_string,
56
    get_info_type_from_string,
57
    get_permission_subject_type_from_string,
58
    get_severity_level_from_string,
59
    get_snmp_auth_algorithm_from_string,
60
    get_snmp_privacy_algorithm_from_string,
61
)
62
63
__all__ = [
64
    "AlertCondition",
65
    "AlertEvent",
66
    "AlertMethod",
67
    "AliveTest",
68
    "AssetType",
69
    "CredentialType",
70
    "CredentialFormat",
71
    "FeedType",
72
    "FilterType",
73
    "Gmp",
74
    "HostsOrdering",
75
    "InfoType",
76
    "PermissionSubjectType",
77
    "PortRangeType",
78
    "ScannerType",
79
    "SeverityLevel",
80
    "SnmpAuthAlgorithm",
81
    "SnmpPrivacyAlgorithm",
82
    "get_asset_type_from_string",
83
    "get_credential_type_from_string",
84
    "get_feed_type_from_string",
85
    "get_filter_type_from_string",
86
    "get_hosts_ordering_from_string",
87
    "get_info_type_from_string",
88
    "get_permission_subject_type_from_string",
89
    "get_severity_level_from_string",
90
    "get_snmp_auth_algorithm_from_string",
91
    "get_snmp_privacy_algorithm_from_string",
92
    "get_ticket_status_from_string",
93
]
94
95
PROTOCOL_VERSION = (8,)
96
97
98 View Code Duplication
class EntityType(Enum):
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
99
    """ Enum for entity types """
100
101
    AGENT = "note"
102
    ALERT = "alert"
103
    ASSET = "asset"
104
    CERT_BUND_ADV = "cert_bund_adv"
105
    CPE = "cpe"
106
    CREDENTIAL = "credential"
107
    CVE = "cve"
108
    DFN_CERT_ADV = "dfn_cert_adv"
109
    FILTER = "filter"
110
    GROUP = "group"
111
    HOST = "host"
112
    INFO = "info"
113
    NOTE = "note"
114
    NVT = "nvt"
115
    OPERATING_SYSTEM = "os"
116
    OVALDEF = "ovaldef"
117
    OVERRIDE = "override"
118
    PERMISSION = "permission"
119
    PORT_LIST = "port_list"
120
    REPORT = "report"
121
    REPORT_FORMAT = "report_format"
122
    RESULT = "result"
123
    ROLE = "role"
124
    SCAN_CONFIG = "config"
125
    SCANNER = "scanner"
126
    SCHEDULE = "schedule"
127
    TAG = "tag"
128
    TARGET = "target"
129
    TASK = "task"
130
    USER = "user"
131
132
    TICKET = "ticket"
133
    VULNERABILITY = "vuln"
134
135
136 View Code Duplication
def get_entity_type_from_string(
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
137
    entity_type: Optional[str]
138
) -> Optional[EntityType]:
139
    """ Convert a entity type string to an actual EntityType instance
140
141
    Arguments:
142
        entity_type: Entity type string to convert to a EntityType
143
    """
144
    if not entity_type:
145
        return None
146
147
    if entity_type == 'vuln':
148
        return EntityType.VULNERABILITY
149
150
    if entity_type == 'os':
151
        return EntityType.OPERATING_SYSTEM
152
153
    if entity_type == 'config':
154
        return EntityType.SCAN_CONFIG
155
156
    try:
157
        return EntityType[entity_type.upper()]
158
    except KeyError:
159
        raise InvalidArgument(
160
            argument='entity_type',
161
            function=get_entity_type_from_string.__name__,
162
        )
163
164
165 View Code Duplication
class FilterType(Enum):
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
166
    """ Enum for filter types """
167
168
    AGENT = "agent"
169
    ALERT = "alert"
170
    ASSET = "asset"
171
    SCAN_CONFIG = "config"
172
    CREDENTIAL = "credential"
173
    FILTER = "filter"
174
    GROUP = "group"
175
    HOST = "host"
176
    NOTE = "note"
177
    OPERATING_SYSTEM = "os"
178
    OVERRIDE = "override"
179
    PERMISSION = "permission"
180
    PORT_LIST = "port_list"
181
    REPORT = "report"
182
    REPORT_FORMAT = "report_format"
183
    RESULT = "result"
184
    ROLE = "role"
185
    SCHEDULE = "schedule"
186
    ALL_SECINFO = "secinfo"
187
    TAG = "tag"
188
    TARGET = "target"
189
    TASK = "task"
190
    TICKET = "ticket"
191
    USER = "user"
192
    VULNERABILITY = "vuln"
193
194
195 View Code Duplication
def get_filter_type_from_string(
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
196
    filter_type: Optional[str]
197
) -> Optional[FilterType]:
198
    """ Convert a filter type string to an actual FilterType instance
199
200
    Arguments:
201
        filter_type (str): Filter type string to convert to a FilterType
202
    """
203
    if not filter_type:
204
        return None
205
206
    if filter_type == 'vuln':
207
        return FilterType.VULNERABILITY
208
209
    if filter_type == 'os':
210
        return FilterType.OPERATING_SYSTEM
211
212
    if filter_type == 'config':
213
        return FilterType.SCAN_CONFIG
214
215
    if filter_type == 'secinfo':
216
        return FilterType.ALL_SECINFO
217
218
    try:
219
        return FilterType[filter_type.upper()]
220
    except KeyError:
221
        raise InvalidArgument(
222
            argument='filter_type',
223
            function=get_filter_type_from_string.__name__,
224
        )
225
226
227
class CredentialType(Enum):
228
    """ Enum for credential types """
229
230
    CLIENT_CERTIFICATE = 'cc'
231
    SNMP = 'snmp'
232
    USERNAME_PASSWORD = 'up'
233
    USERNAME_SSH_KEY = 'usk'
234
    SMIME_CERTIFICATE = 'smime'
235
    PGP_ENCRYPTION_KEY = 'pgp'
236
    PASSWORD_ONLY = 'pw'
237
238
239 View Code Duplication
def get_credential_type_from_string(
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
240
    credential_type: Optional[str]
241
) -> Optional[CredentialType]:
242
    """ Convert a credential type string into a CredentialType instance
243
    """
244
    if not credential_type:
245
        return None
246
247
    try:
248
        return CredentialType[credential_type.upper()]
249
    except KeyError:
250
        raise InvalidArgument(
251
            argument='credential_type',
252
            function=get_credential_type_from_string.__name__,
253
        )
254
255
256
class TicketStatus(Enum):
257
    """ Enum for ticket status """
258
259
    OPEN = 'Open'
260
    FIXED = 'Fixed'
261
    CLOSED = 'Closed'
262
263
264
def get_ticket_status_from_string(
265
    ticket_status: Optional[str]
266
) -> Optional[TicketStatus]:
267
    """ Convert a ticket status string into a TicketStatus instance
268
    """
269
    if not ticket_status:
270
        return None
271
272
    try:
273
        return TicketStatus[ticket_status.upper()]
274
    except KeyError:
275
        raise InvalidArgument(
276
            argument='ticket_status',
277
            function=get_ticket_status_from_string.__name__,
278
        )
279
280
281
class Gmp(Gmpv7):
282
283
    _filter_type = FilterType
284
    _entity_type = EntityType
285
286
    @staticmethod
287
    def get_protocol_version() -> str:
288
        """Determine the Greenbone Management Protocol version.
289
290
        Returns:
291
            str: Implemented version of the Greenbone Management Protocol
292
        """
293
        return get_version_string(PROTOCOL_VERSION)
294
295
    def create_credential(
0 ignored issues
show
Comprehensibility introduced by
This function exceeds the maximum number of variables (19/15).
Loading history...
296
        self,
297
        name: str,
298
        credential_type: CredentialType,
299
        *,
300
        comment: Optional[str] = None,
301
        allow_insecure: Optional[bool] = None,
302
        certificate: Optional[str] = None,
303
        key_phrase: Optional[str] = None,
304
        private_key: Optional[str] = None,
305
        login: Optional[str] = None,
306
        password: Optional[str] = None,
307
        auth_algorithm: Optional[SnmpAuthAlgorithm] = None,
308
        community: Optional[str] = None,
309
        privacy_algorithm: Optional[SnmpPrivacyAlgorithm] = None,
310
        privacy_password: Optional[str] = None,
311
        public_key: Optional[str] = None
312
    ) -> Any:
313
        """Create a new credential
314
315
        Create a new credential e.g. to be used in the method of an alert.
316
317
        Currently the following credential types are supported:
318
319
            - Username + Password
320
            - Username + SSH-Key
321
            - Client Certificates
322
            - SNMPv1 or SNMPv2c protocol
323
            - S/MIME Certificate
324
            - OpenPGP Key
325
            - Password only
326
327
        Arguments:
328
            name: Name of the new credential
329
            credential_type: The credential type.
330
            comment: Comment for the credential
331
            allow_insecure: Whether to allow insecure use of the credential
332
            certificate: Certificate for the credential.
333
                Required for client-certificate and smime credential types.
334
            key_phrase: Key passphrase for the private key.
335
                Used for the username+ssh-key credential type.
336
            private_key: Private key to use for login. Required
337
                for usk credential type. Also used for the cc credential type.
338
                The supported key types (dsa, rsa, ecdsa, ...) and formats (PEM,
339
                PKC#12, OpenSSL, ...) depend on your installed GnuTLS version.
340
            login: Username for the credential. Required for username+password,
341
                username+ssh-key and snmp credential type.
342
            password: Password for the credential. Used for username+password
343
                and snmp credential types.
344
            community: The SNMP community
345
            auth_algorithm: The SNMP authentication algorithm. Required for snmp
346
                credential type.
347
            privacy_algorithm: The SNMP privacy algorithm
348
            privacy_password: The SNMP privacy password
349
            public_key: PGP public key in *armor* plain text format. Required
350
                for pgp credential type.
351
352
        Examples:
353
            Creating a Username + Password credential
354
355
            .. code-block:: python
356
357
                gmp.create_credential(
358
                    name='UP Credential',
359
                    credential_type=CredentialType.USERNAME_PASSWORD,
360
                    login='foo',
361
                    password='bar',
362
                );
363
364
            Creating a Username + SSH Key credential
365
366
            .. code-block:: python
367
368
                with open('path/to/private-ssh-key') as f:
369
                    key = f.read()
370
371
                gmp.create_credential(
372
                    name='USK Credential',
373
                    credential_type=CredentialType.USERNAME_SSH_KEY,
374
                    login='foo',
375
                    key_phrase='foobar',
376
                    private_key=key,
377
                )
378
379
            Creating a PGP credential
380
381
            .. note::
382
383
                A compatible public pgp key file can be exported with GnuPG via
384
                ::
385
386
                    $ gpg --armor --export [email protected] > alice.asc
387
388
            .. code-block:: python
389
390
                with open('path/to/pgp.key.asc') as f:
391
                    key = f.read()
392
393
                gmp.create_credential(
394
                    name='PGP Credential',
395
                    credential_type=CredentialType.PGP_ENCRYPTION_KEY,
396
                    public_key=key,
397
                )
398
399
            Creating a S/MIME credential
400
401
            .. code-block:: python
402
403
                with open('path/to/smime-cert') as f:
404
                    cert = f.read()
405
406
                gmp.create_credential(
407
                    name='SMIME Credential',
408
                    credential_type=CredentialType.SMIME_CERTIFICATE,
409
                    certificate=cert,
410
                )
411
412
            Creating a Password-Only credential
413
414
            .. code-block:: python
415
416
                gmp.create_credential(
417
                    name='Password-Only Credential',
418
                    credential_type=CredentialType.PASSWORD_ONLY,
419
                    password='foo',
420
                )
421
        Returns:
422
            The response. See :py:meth:`send_command` for details.
423
        """
424
        if not name:
425
            raise RequiredArgument(
426
                function="create_credential", argument="name"
427
            )
428
429
        if not isinstance(credential_type, CredentialType):
430
            raise InvalidArgument(
431
                "create_credential requires type to be a CredentialType "
432
                "instance",
433
                function="create_credential",
434
                argument="credential_type",
435
            )
436
437
        cmd = XmlCommand("create_credential")
438
        cmd.add_element("name", name)
439
440
        cmd.add_element("type", credential_type.value)
441
442
        if comment:
443
            cmd.add_element("comment", comment)
444
445
        if allow_insecure is not None:
446
            cmd.add_element("allow_insecure", _to_bool(allow_insecure))
447
448
        if (
449
            credential_type == CredentialType.CLIENT_CERTIFICATE
0 ignored issues
show
Unused Code introduced by
Consider merging these comparisons with "in" to 'credential_type in (CredentialType.CLIENT_CERTIFICATE, CredentialType.SMIME_CERTIFICATE)'
Loading history...
450
            or credential_type == CredentialType.SMIME_CERTIFICATE
451
        ):
452
            if not certificate:
453
                raise RequiredArgument(
454
                    "create_credential requires certificate argument for "
455
                    "credential_type {0}".format(credential_type.name),
456
                    function="create_credential",
457
                    argument="certificate",
458
                )
459
460
            cmd.add_element("certificate", certificate)
461
462 View Code Duplication
        if (
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
463
            credential_type == CredentialType.USERNAME_PASSWORD
0 ignored issues
show
Unused Code introduced by
Consider merging these comparisons with "in" to 'credential_type in (CredentialType.USERNAME_PASSWORD, CredentialType.USERNAME_SSH_KEY, CredentialType.SNMP)'
Loading history...
464
            or credential_type == CredentialType.USERNAME_SSH_KEY
465
            or credential_type == CredentialType.SNMP
466
        ):
467
            if not login:
468
                raise RequiredArgument(
469
                    "create_credential requires login argument for "
470
                    "credential_type {0}".format(credential_type.name),
471
                    function="create_credential",
472
                    argument="login",
473
                )
474
475
            cmd.add_element("login", login)
476
477
        if credential_type == CredentialType.PASSWORD_ONLY and not password:
478
            raise RequiredArgument(
479
                "create_credential requires password argument for "
480
                "credential_type {0}".format(credential_type.name),
481
                function="create_credential",
482
                argument="password",
483
            )
484
485
        if (
486
            credential_type == CredentialType.USERNAME_PASSWORD
0 ignored issues
show
Unused Code introduced by
Consider merging these comparisons with "in" to 'credential_type in (CredentialType.USERNAME_PASSWORD, CredentialType.SNMP, CredentialType.PASSWORD_ONLY)'
Loading history...
487
            or credential_type == CredentialType.SNMP
488
            or credential_type == CredentialType.PASSWORD_ONLY
489
        ) and password:
490
            cmd.add_element("password", password)
491
492 View Code Duplication
        if credential_type == CredentialType.USERNAME_SSH_KEY:
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
493
            if not private_key:
494
                raise RequiredArgument(
495
                    "create_credential requires private_key argument for "
496
                    "credential_type {0}".format(credential_type.name),
497
                    function="create_credential",
498
                    argument="private_key",
499
                )
500
501
            _xmlkey = cmd.add_element("key")
502
            _xmlkey.add_element("private", private_key)
503
504
            if key_phrase:
505
                _xmlkey.add_element("phrase", key_phrase)
506
507
        if credential_type == CredentialType.CLIENT_CERTIFICATE and private_key:
508
            _xmlkey = cmd.add_element("key")
509
            _xmlkey.add_element("private", private_key)
510
511 View Code Duplication
        if credential_type == CredentialType.SNMP:
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
512
            if not isinstance(auth_algorithm, SnmpAuthAlgorithm):
513
                raise InvalidArgument(
514
                    "create_credential requires auth_algorithm to be a "
515
                    "SnmpAuthAlgorithm instance",
516
                    function="create_credential",
517
                    argument="auth_algorithm",
518
                )
519
520
            cmd.add_element("auth_algorithm", auth_algorithm.value)
521
522
            if community:
523
                cmd.add_element("community", community)
524
525
            if privacy_algorithm is not None or privacy_password:
526
                _xmlprivacy = cmd.add_element("privacy")
527
528
                if privacy_algorithm is not None:
529
                    if not isinstance(privacy_algorithm, SnmpPrivacyAlgorithm):
530
                        raise InvalidArgument(
531
                            "create_credential requires algorithm to be a "
532
                            "SnmpPrivacyAlgorithm instance",
533
                            function="create_credential",
534
                            argument="privacy_algorithm",
535
                        )
536
537
                    _xmlprivacy.add_element(
538
                        "algorithm", privacy_algorithm.value
539
                    )
540
541
                if privacy_password:
542
                    _xmlprivacy.add_element("password", privacy_password)
543
544
        if credential_type == CredentialType.PGP_ENCRYPTION_KEY:
545
            if not public_key:
546
                raise RequiredArgument(
547
                    "Creating a pgp credential requires a public_key argument",
548
                    argument="public_key",
549
                    function="create_credential",
550
                )
551
552
            _xmlkey = cmd.add_element("key")
553
            _xmlkey.add_element("public", public_key)
554
555
        return self._send_xml_command(cmd)
556
557
    def modify_credential(
0 ignored issues
show
Comprehensibility introduced by
This function exceeds the maximum number of variables (19/15).
Loading history...
558
        self,
559
        credential_id: str,
560
        *,
561
        name: Optional[str] = None,
562
        comment: Optional[str] = None,
563
        allow_insecure: Optional[bool] = None,
564
        certificate: Optional[str] = None,
565
        key_phrase: Optional[str] = None,
566
        private_key: Optional[str] = None,
567
        login: Optional[str] = None,
568
        password: Optional[str] = None,
569
        auth_algorithm: Optional[SnmpAuthAlgorithm] = None,
570
        community: Optional[str] = None,
571
        privacy_algorithm: Optional[SnmpPrivacyAlgorithm] = None,
572
        privacy_password: Optional[str] = None,
573
        public_key: Optional[str] = None
574
    ) -> Any:
575
        """Modifies an existing credential.
576
577
        Arguments:
578
            credential_id: UUID of the credential
579
            name: Name of the credential
580
            comment: Comment for the credential
581
            allow_insecure: Whether to allow insecure use of the credential
582
            certificate: Certificate for the credential
583
            key_phrase: Key passphrase for the private key
584
            private_key: Private key to use for login
585
            login: Username for the credential
586
            password: Password for the credential
587
            auth_algorithm: The authentication algorithm for SNMP
588
            community: The SNMP community
589
            privacy_algorithm: The privacy algorithm for SNMP
590
            privacy_password: The SNMP privacy password
591
            public_key: PGP public key in *armor* plain text format
592
593
        Returns:
594
            The response. See :py:meth:`send_command` for details.
595
        """
596
        if not credential_id:
597
            raise RequiredArgument(
598
                argument="credential_id", function="modify_credential"
599
            )
600
601
        cmd = XmlCommand("modify_credential")
602
        cmd.set_attribute("credential_id", credential_id)
603
604
        if comment:
605
            cmd.add_element("comment", comment)
606
607
        if name:
608
            cmd.add_element("name", name)
609
610
        if allow_insecure is not None:
611
            cmd.add_element("allow_insecure", _to_bool(allow_insecure))
612
613
        if certificate:
614
            cmd.add_element("certificate", certificate)
615
616
        if key_phrase or private_key:
617
            if not key_phrase or not private_key:
618
                raise RequiredArgument(
619
                    "modify_credential requires "
620
                    "a key_phrase and private_key arguments",
621
                    function="modify_credential",
622
                )
623
            _xmlkey = cmd.add_element("key")
624
            _xmlkey.add_element("phrase", key_phrase)
625
            _xmlkey.add_element("private", private_key)
626
627
        if login:
628
            cmd.add_element("login", login)
629
630
        if password:
631
            cmd.add_element("password", password)
632
633
        if auth_algorithm:
634
            if not isinstance(auth_algorithm, SnmpAuthAlgorithm):
635
                raise InvalidArgument(
636
                    "modify_credential requires auth_algorithm to be a "
637
                    "SnmpAuthAlgorithm instance",
638
                    argument="auth_algorithm",
639
                    function="modify_credential",
640
                )
641
            cmd.add_element("auth_algorithm", auth_algorithm.value)
642
643
        if community:
644
            cmd.add_element("community", community)
645
646
        if privacy_algorithm is not None or privacy_password is not None:
647
            _xmlprivacy = cmd.add_element("privacy")
648
649
            if privacy_algorithm is not None:
650
                if not isinstance(privacy_algorithm, SnmpPrivacyAlgorithm):
651
                    raise InvalidArgument(
652
                        "modify_credential requires privacy_algorithm to be "
653
                        "a SnmpPrivacyAlgorithm instance",
654
                        argument="privacy_algorithm",
655
                        function="modify_credential",
656
                    )
657
658
                _xmlprivacy.add_element("algorithm", privacy_algorithm.value)
659
660
            if privacy_password is not None:
661
                _xmlprivacy.add_element("password", privacy_password)
662
663
        if public_key:
664
            _xmlkey = cmd.add_element("key")
665
            _xmlkey.add_element("public", public_key)
666
667
        return self._send_xml_command(cmd)
668
669
    def create_tag(
670
        self,
671
        name: str,
672
        resource_type: str,
673
        *,
674
        resource_filter: Optional[str] = None,
675
        resource_ids: Optional[List[str]] = None,
676
        value: Optional[str] = None,
677
        comment: Optional[str] = None,
678
        active: Optional[bool] = None
679
    ) -> Any:
680
        """Create a tag.
681
682
        Arguments:
683
            name: Name of the tag. A full tag name consisting of namespace and
684
                predicate e.g. `foo:bar`.
685
            resource_type: Entity type the tag is to be attached to.
686
            resource_filter: Filter term to select resources the tag is to be
687
                attached to. Only one of resource_filter or resource_ids can be
688
                provided.
689
            resource_ids: IDs of the resources the tag is to be attached to.
690
                Only one of resource_filter or resource_ids can be provided.
691
            value: Value associated with the tag.
692
            comment: Comment for the tag.
693
            active: Whether the tag should be active.
694
695
        Returns:
696
            The response. See :py:meth:`send_command` for details.
697
        """
698
        if not name:
699
            raise RequiredArgument(function="create_tag", argument="name")
700
701
        if resource_filter and resource_ids:
702
            raise InvalidArgument(
703
                "create_tag accepts either resource_filter or resource_ids "
704
                "argument",
705
                function="create_tag",
706
            )
707
708
        if not resource_type:
709
            raise RequiredArgument(
710
                function="create_tag", argument="resource_type"
711
            )
712
713
        cmd = XmlCommand('create_tag')
714
        cmd.add_element('name', name)
715
716
        _xmlresources = cmd.add_element("resources")
717
        if resource_filter is not None:
718
            _xmlresources.set_attribute("filter", resource_filter)
719
720
        for resource_id in resource_ids or []:
721
            _xmlresources.add_element(
722
                "resource", attrs={"id": str(resource_id)}
723
            )
724
725
        _xmlresources.add_element("type", resource_type)
726
727
        if comment:
728
            cmd.add_element("comment", comment)
729
730
        if value:
731
            cmd.add_element("value", value)
732
733
        if active is not None:
734
            if active:
735
                cmd.add_element("active", "1")
736
            else:
737
                cmd.add_element("active", "0")
738
739
        return self._send_xml_command(cmd)
740
741
    def modify_tag(
742
        self,
743
        tag_id: str,
744
        *,
745
        comment: Optional[str] = None,
746
        name: Optional[str] = None,
747
        value=None,
748
        active=None,
749
        resource_action: Optional[str] = None,
750
        resource_type: Optional[str] = None,
751
        resource_filter: Optional[str] = None,
752
        resource_ids: Optional[List[str]] = None
753
    ) -> Any:
754
        """Modifies an existing tag.
755
756
        Arguments:
757
            tag_id: UUID of the tag.
758
            comment: Comment to add to the tag.
759
            name: Name of the tag.
760
            value: Value of the tag.
761
            active: Whether the tag is active.
762
            resource_action: Whether to add or remove resources instead of
763
                overwriting. One of '', 'add', 'set' or 'remove'.
764
            resource_type: Type of the resources to which to attach the tag.
765
                Required if resource_filter is set.
766
            resource_filter: Filter term to select resources the tag is to be
767
                attached to.
768
            resource_ids: IDs of the resources to which to attach the tag.
769
770
        Returns:
771
            The response. See :py:meth:`send_command` for details.
772
        """
773
        if not tag_id:
774
            raise RequiredArgument("modify_tag requires a tag_id element")
775
776
        cmd = XmlCommand("modify_tag")
777
        cmd.set_attribute("tag_id", str(tag_id))
778
779
        if comment:
780
            cmd.add_element("comment", comment)
781
782
        if name:
783
            cmd.add_element("name", name)
784
785
        if value:
786
            cmd.add_element("value", value)
787
788
        if active is not None:
789
            cmd.add_element("active", _to_bool(active))
790
791
        if resource_action or resource_filter or resource_ids or resource_type:
792
            if resource_filter and not resource_type:
793
                raise RequiredArgument(
794
                    "modify_tag requires resource_type argument when "
795
                    "resource_filter is set",
796
                    function="modify_tag",
797
                    argument="resource_type",
798
                )
799
800
            _xmlresources = cmd.add_element("resources")
801
            if resource_action is not None:
802
                _xmlresources.set_attribute("action", resource_action)
803
804
            if resource_filter is not None:
805
                _xmlresources.set_attribute("filter", resource_filter)
806
807
            for resource_id in resource_ids or []:
808
                _xmlresources.add_element(
809
                    "resource", attrs={"id": str(resource_id)}
810
                )
811
812
            if resource_type is not None:
813
                _xmlresources.add_element("type", resource_type)
814
815
        return self._send_xml_command(cmd)
816
817
    def clone_ticket(self, ticket_id: str) -> Any:
818
        """Clone an existing ticket
819
820
        Arguments:
821
            ticket_id: UUID of an existing ticket to clone from
822
823
        Returns:
824
            The response. See :py:meth:`send_command` for details.
825
        """
826
        if not ticket_id:
827
            raise RequiredArgument(
828
                function="clone_ticket", argument="ticket_id"
829
            )
830
831
        cmd = XmlCommand("create_ticket")
832
833
        _copy = cmd.add_element("copy", ticket_id)
834
835
        return self._send_xml_command(cmd)
836
837
    def create_ticket(
838
        self,
839
        *,
840
        result_id: str,
841
        assigned_to_user_id: str,
842
        note: str,
843
        comment: Optional[str] = None
844
    ) -> Any:
845
        """Create a new ticket
846
847
        Arguments:
848
            result_id: UUID of the result the ticket applies to
849
            assigned_to_user_id: UUID of a user the ticket should be assigned to
850
            note: A note about opening the ticket
851
            comment: Comment for the ticket
852
853
        Returns:
854
            The response. See :py:meth:`send_command` for details.
855
        """
856
        if not result_id:
857
            raise RequiredArgument(
858
                function="create_ticket", argument="result_id"
859
            )
860
861
        if not assigned_to_user_id:
862
            raise RequiredArgument(
863
                function="create_ticket", argument="assigned_to_user_id"
864
            )
865
866
        if not note:
867
            raise RequiredArgument(function="create_ticket", argument="note")
868
869
        cmd = XmlCommand("create_ticket")
870
871
        _result = cmd.add_element("result")
872
        _result.set_attribute("id", result_id)
873
874
        _assigned = cmd.add_element("assigned_to")
875
        _user = _assigned.add_element("user")
876
        _user.set_attribute("id", assigned_to_user_id)
877
878
        _note = cmd.add_element("open_note", note)
879
880
        if comment:
881
            cmd.add_element("comment", comment)
882
883
        return self._send_xml_command(cmd)
884
885
    def delete_ticket(
886
        self, ticket_id: str, *, ultimate: Optional[bool] = False
887
    ):
888
        """Deletes an existing ticket
889
890
        Arguments:
891
            ticket_id: UUID of the ticket to be deleted.
892
            ultimate: Whether to remove entirely, or to the trashcan.
893
        """
894
        if not ticket_id:
895
            raise RequiredArgument(
896
                function="delete_ticket", argument="ticket_id"
897
            )
898
899
        cmd = XmlCommand("delete_ticket")
900
        cmd.set_attribute("ticket_id", ticket_id)
901
        cmd.set_attribute("ultimate", _to_bool(ultimate))
902
903
        return self._send_xml_command(cmd)
904
905 View Code Duplication
    def get_tickets(
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
906
        self,
907
        *,
908
        trash: Optional[bool] = None,
909
        filter: Optional[str] = None,
910
        filter_id: Optional[str] = None
911
    ) -> Any:
912
        """Request a list of tickets
913
914
        Arguments:
915
            filter: Filter term to use for the query
916
            filter_id: UUID of an existing filter to use for the query
917
            trash: True to request the tickets in the trashcan
918
919
        Returns:
920
            The response. See :py:meth:`send_command` for details.
921
        """
922
        cmd = XmlCommand("get_tickets")
923
924
        _add_filter(cmd, filter, filter_id)
925
926
        if not trash is None:
927
            cmd.set_attribute("trash", _to_bool(trash))
928
929
        return self._send_xml_command(cmd)
930
931
    def get_ticket(self, ticket_id: str) -> Any:
932
        """Request a single ticket
933
934
        Arguments:
935
            ticket_id: UUID of an existing ticket
936
937
        Returns:
938
            The response. See :py:meth:`send_command` for details.
939
        """
940
        if not ticket_id:
941
            raise RequiredArgument(function="get_ticket", argument="ticket_id")
942
943
        cmd = XmlCommand("get_tickets")
944
        cmd.set_attribute("ticket_id", ticket_id)
945
        return self._send_xml_command(cmd)
946
947
    def get_vulnerabilities(
948
        self, *, filter: Optional[str] = None, filter_id: Optional[str] = None
949
    ) -> Any:
950
        """Request a list of vulnerabilities
951
952
        Arguments:
953
            filter: Filter term to use for the query
954
            filter_id: UUID of an existing filter to use for the query
955
        Returns:
956
            The response. See :py:meth:`send_command` for details.
957
        """
958
        cmd = XmlCommand("get_vulns")
959
960
        _add_filter(cmd, filter, filter_id)
961
962
        return self._send_xml_command(cmd)
963
964
    def get_vulnerability(self, vulnerability_id: str) -> Any:
965
        """Request a single vulnerability
966
967
        Arguments:
968
            vulnerability_id: ID of an existing vulnerability
969
970
        Returns:
971
            The response. See :py:meth:`send_command` for details.
972
        """
973
        if not vulnerability_id:
974
            raise RequiredArgument(
975
                function="get_vulnerability", argument="vulnerability_id"
976
            )
977
978
        cmd = XmlCommand("get_vulns")
979
        cmd.set_attribute("vuln_id", vulnerability_id)
980
        return self._send_xml_command(cmd)
981
982
    def modify_ticket(
983
        self,
984
        ticket_id: str,
985
        *,
986
        status: Optional[TicketStatus] = None,
987
        note: Optional[str] = None,
988
        assigned_to_user_id: Optional[str] = None,
989
        comment: Optional[str] = None
990
    ) -> Any:
991
        """Modify a single ticket
992
993
        Arguments:
994
            ticket_id: UUID of an existing ticket
995
            status: New status for the ticket
996
            note: Note for the status change. Required if status is set.
997
            assigned_to_user_id: UUID of the user the ticket should be assigned
998
                to
999
            comment: Comment for the ticket
1000
1001
        Returns:
1002
            The response. See :py:meth:`send_command` for details.
1003
        """
1004
        if not ticket_id:
1005
            raise RequiredArgument(
1006
                function="modify_ticket", argument="ticket_id"
1007
            )
1008
1009
        if status and not note:
1010
            raise RequiredArgument(
1011
                "setting a status in modify_ticket requires a note argument",
1012
                function="modify_ticket",
1013
                argument="note",
1014
            )
1015
1016
        if note and not status:
1017
            raise RequiredArgument(
1018
                "setting a note in modify_ticket requires a status argument",
1019
                function="modify_ticket",
1020
                argument="status",
1021
            )
1022
1023
        cmd = XmlCommand("modify_ticket")
1024
        cmd.set_attribute("ticket_id", ticket_id)
1025
1026
        if assigned_to_user_id:
1027
            _assigned = cmd.add_element("assigned_to")
1028
            _user = _assigned.add_element("user")
1029
            _user.set_attribute("id", assigned_to_user_id)
1030
1031
        if status:
1032
            if not isinstance(status, TicketStatus):
1033
                raise InvalidArgument(
1034
                    "status argument of modify_ticket needs to be a "
1035
                    "TicketStatus",
1036
                    function="modify_ticket",
1037
                    argument="status",
1038
                )
1039
1040
            cmd.add_element('status', status.value)
1041
            cmd.add_element('{}_note'.format(status.name.lower()), note)
1042
1043
        if comment:
1044
            cmd.add_element("comment", comment)
1045
1046
        return self._send_xml_command(cmd)
1047
1048
    def create_filter(
1049
        self,
1050
        name: str,
1051
        *,
1052
        filter_type: Optional[FilterType] = None,
1053
        comment: Optional[str] = None,
1054
        term: Optional[str] = None
1055
    ) -> Any:
1056
        """Create a new filter
1057
1058
        Arguments:
1059
            name: Name of the new filter
1060
            filter_type: Filter for entity type
1061
            comment: Comment for the filter
1062
            term: Filter term e.g. 'name=foo'
1063
1064
        Returns:
1065
            The response. See :py:meth:`send_command` for details.
1066
        """
1067
        return super().create_filter(
1068
            name, filter_type=filter_type, comment=comment, term=term
1069
        )
1070
1071 View Code Duplication
    def modify_filter(
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
1072
        self,
1073
        filter_id: str,
1074
        *,
1075
        comment: Optional[str] = None,
1076
        name: Optional[str] = None,
1077
        term: Optional[str] = None,
1078
        filter_type: Optional[FilterType] = None
1079
    ) -> Any:
1080
        """Modifies an existing filter.
1081
1082
        Arguments:
1083
            filter_id: UUID of the filter to be modified
1084
            comment: Comment on filter.
1085
            name: Name of filter.
1086
            term: Filter term.
1087
            filter_type: Resource type filter applies to.
1088
1089
        Returns:
1090
            The response. See :py:meth:`send_command` for details.
1091
        """
1092
        if not filter_id:
1093
            raise RequiredArgument(
1094
                function="modify_filter", argument="filter_id"
1095
            )
1096
1097
        cmd = XmlCommand("modify_filter")
1098
        cmd.set_attribute("filter_id", filter_id)
1099
1100
        if comment:
1101
            cmd.add_element("comment", comment)
1102
1103
        if name:
1104
            cmd.add_element("name", name)
1105
1106
        if term:
1107
            cmd.add_element("term", term)
1108
1109
        if filter_type:
1110
            if not isinstance(filter_type, FilterType):
1111
                raise InvalidArgument(
1112
                    "modify_filter requires type to be a FilterType instance. "
1113
                    "was {}".format(filter_type),
1114
                    function="modify_filter",
1115
                    argument="filter_type",
1116
                )
1117
            cmd.add_element("type", filter_type.value)
1118
1119
        return self._send_xml_command(cmd)
1120