Completed
Push — master ( 5076fb...1f49d7 )
by
unknown
12s queued 11s
created

gvm.protocols.gmpv8.Gmp.get_vulnerabilities()   A

Complexity

Conditions 1

Size

Total Lines 16
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Importance

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