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=arguments-differ, unused-import
20
21from typing import Any, List, Optional
22
23from gvm.errors import RequiredArgument, InvalidArgumentType
24from gvm.protocols.gmpv208.entities.targets import (
25    TargetsMixin as Gmp208TargetsMixin,
26    AliveTest,
27)
28from gvm.utils import to_bool, to_comma_list
29from gvm.xml import XmlCommand
30
31
32class TargetsMixin(Gmp208TargetsMixin):
33    def create_target(
34        self,
35        name: str,
36        *,
37        asset_hosts_filter: Optional[str] = None,
38        hosts: Optional[List[str]] = None,
39        comment: Optional[str] = None,
40        exclude_hosts: Optional[List[str]] = None,
41        ssh_credential_id: Optional[str] = None,
42        ssh_credential_port: Optional[int] = None,
43        smb_credential_id: Optional[str] = None,
44        esxi_credential_id: Optional[str] = None,
45        snmp_credential_id: Optional[str] = None,
46        alive_test: Optional[AliveTest] = None,
47        allow_simultaneous_ips: Optional[bool] = None,
48        reverse_lookup_only: Optional[bool] = None,
49        reverse_lookup_unify: Optional[bool] = None,
50        port_range: Optional[str] = None,
51        port_list_id: Optional[str] = None,
52    ) -> Any:
53        """Create a new target
54
55        Arguments:
56            name: Name of the target
57            asset_hosts_filter: Filter to select target host from assets hosts
58            hosts: List of hosts addresses to scan
59            exclude_hosts: List of hosts addresses to exclude from scan
60            comment: Comment for the target
61            ssh_credential_id: UUID of a ssh credential to use on target
62            ssh_credential_port: The port to use for ssh credential
63            smb_credential_id: UUID of a smb credential to use on target
64            snmp_credential_id: UUID of a snmp credential to use on target
65            esxi_credential_id: UUID of a esxi credential to use on target
66            alive_test: Which alive test to use
67            allow_simultaneous_ips: Whether to scan multiple IPs of the
68                same host simultaneously
69            reverse_lookup_only: Whether to scan only hosts that have names
70            reverse_lookup_unify: Whether to scan only one IP when multiple IPs
71                have the same name.
72            port_range: Port range for the target
73            port_list_id: UUID of the port list to use on target
74
75        Returns:
76            The response. See :py:meth:`send_command` for details.
77        """
78        if not name:
79            raise RequiredArgument(
80                function=self.create_target.__name__, argument='name'
81            )
82
83        cmd = XmlCommand("create_target")
84        cmd.add_element("name", name)
85
86        if asset_hosts_filter:
87            cmd.add_element(
88                "asset_hosts", attrs={"filter": str(asset_hosts_filter)}
89            )
90        elif hosts:
91            cmd.add_element("hosts", to_comma_list(hosts))
92        else:
93            raise RequiredArgument(
94                function=self.create_target.__name__,
95                argument='hosts or asset_hosts_filter',
96            )
97
98        if comment:
99            cmd.add_element("comment", comment)
100
101        if exclude_hosts:
102            cmd.add_element("exclude_hosts", to_comma_list(exclude_hosts))
103
104        if ssh_credential_id:
105            _xmlssh = cmd.add_element(
106                "ssh_credential", attrs={"id": ssh_credential_id}
107            )
108            if ssh_credential_port:
109                _xmlssh.add_element("port", str(ssh_credential_port))
110
111        if smb_credential_id:
112            cmd.add_element("smb_credential", attrs={"id": smb_credential_id})
113
114        if esxi_credential_id:
115            cmd.add_element("esxi_credential", attrs={"id": esxi_credential_id})
116
117        if snmp_credential_id:
118            cmd.add_element("snmp_credential", attrs={"id": snmp_credential_id})
119
120        if alive_test:
121            if not isinstance(alive_test, AliveTest):
122                raise InvalidArgumentType(
123                    function=self.create_target.__name__,
124                    argument='alive_test',
125                    arg_type=AliveTest.__name__,
126                )
127
128            cmd.add_element("alive_tests", alive_test.value)
129
130        if allow_simultaneous_ips is not None:
131            cmd.add_element(
132                "allow_simultaneous_ips", to_bool(allow_simultaneous_ips)
133            )
134
135        if reverse_lookup_only is not None:
136            cmd.add_element("reverse_lookup_only", to_bool(reverse_lookup_only))
137
138        if reverse_lookup_unify is not None:
139            cmd.add_element(
140                "reverse_lookup_unify", to_bool(reverse_lookup_unify)
141            )
142
143        if port_range:
144            cmd.add_element("port_range", port_range)
145
146        if port_list_id:
147            cmd.add_element("port_list", attrs={"id": port_list_id})
148
149        return self._send_xml_command(cmd)
150
151    def modify_target(
152        self,
153        target_id: str,
154        *,
155        name: Optional[str] = None,
156        comment: Optional[str] = None,
157        hosts: Optional[List[str]] = None,
158        exclude_hosts: Optional[List[str]] = None,
159        ssh_credential_id: Optional[str] = None,
160        ssh_credential_port: Optional[bool] = None,
161        smb_credential_id: Optional[str] = None,
162        esxi_credential_id: Optional[str] = None,
163        snmp_credential_id: Optional[str] = None,
164        alive_test: Optional[AliveTest] = None,
165        allow_simultaneous_ips: Optional[bool] = None,
166        reverse_lookup_only: Optional[bool] = None,
167        reverse_lookup_unify: Optional[bool] = None,
168        port_list_id: Optional[str] = None,
169    ) -> Any:
170        """Modifies an existing target.
171
172        Arguments:
173            target_id: ID of target to modify.
174            comment: Comment on target.
175            name: Name of target.
176            hosts: List of target hosts.
177            exclude_hosts: A list of hosts to exclude.
178            ssh_credential_id: UUID of SSH credential to use on target.
179            ssh_credential_port: The port to use for ssh credential
180            smb_credential_id: UUID of SMB credential to use on target.
181            esxi_credential_id: UUID of ESXi credential to use on target.
182            snmp_credential_id: UUID of SNMP credential to use on target.
183            port_list_id: UUID of port list describing ports to scan.
184            alive_test: Which alive tests to use.
185            allow_simultaneous_ips: Whether to scan multiple IPs of the
186                same host simultaneously
187            reverse_lookup_only: Whether to scan only hosts that have names.
188            reverse_lookup_unify: Whether to scan only one IP when multiple IPs
189                have the same name.
190
191        Returns:
192            The response. See :py:meth:`send_command` for details.
193        """
194        if not target_id:
195            raise RequiredArgument(
196                function=self.modify_target.__name__, argument='target_id'
197            )
198
199        cmd = XmlCommand("modify_target")
200        cmd.set_attribute("target_id", target_id)
201
202        if comment:
203            cmd.add_element("comment", comment)
204
205        if name:
206            cmd.add_element("name", name)
207
208        if hosts:
209            cmd.add_element("hosts", to_comma_list(hosts))
210            if exclude_hosts is None:
211                exclude_hosts = ['']
212
213        if exclude_hosts:
214            cmd.add_element("exclude_hosts", to_comma_list(exclude_hosts))
215
216        if alive_test:
217            if not isinstance(alive_test, AliveTest):
218                raise InvalidArgumentType(
219                    function=self.modify_target.__name__,
220                    argument='alive_test',
221                    arg_type=AliveTest.__name__,
222                )
223            cmd.add_element("alive_tests", alive_test.value)
224
225        if ssh_credential_id:
226            _xmlssh = cmd.add_element(
227                "ssh_credential", attrs={"id": ssh_credential_id}
228            )
229
230            if ssh_credential_port:
231                _xmlssh.add_element("port", str(ssh_credential_port))
232
233        if smb_credential_id:
234            cmd.add_element("smb_credential", attrs={"id": smb_credential_id})
235
236        if esxi_credential_id:
237            cmd.add_element("esxi_credential", attrs={"id": esxi_credential_id})
238
239        if snmp_credential_id:
240            cmd.add_element("snmp_credential", attrs={"id": snmp_credential_id})
241
242        if allow_simultaneous_ips is not None:
243            cmd.add_element(
244                "allow_simultaneous_ips", to_bool(allow_simultaneous_ips)
245            )
246
247        if reverse_lookup_only is not None:
248            cmd.add_element("reverse_lookup_only", to_bool(reverse_lookup_only))
249
250        if reverse_lookup_unify is not None:
251            cmd.add_element(
252                "reverse_lookup_unify", to_bool(reverse_lookup_unify)
253            )
254
255        if port_list_id:
256            cmd.add_element("port_list", attrs={"id": port_list_id})
257
258        return self._send_xml_command(cmd)
259