Passed
Pull Request — master (#124)
by
unknown
01:41
created

gmp.clients.pyshell.Arguments.__init__()   A

Complexity

Conditions 1

Size

Total Lines 2
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 2
nop 2
dl 0
loc 2
rs 10
c 0
b 0
f 0
1
# -*- coding: utf-8 -*-
0 ignored issues
show
Coding Style introduced by
This module should have a docstring.

The coding style of this project requires that you add a docstring to this code element. Below, you find an example for methods:

class SomeClass:
    def some_method(self):
        """Do x and return foo."""

If you would like to know more about docstrings, we recommend to read PEP-257: Docstring Conventions.

Loading history...
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
import argparse
20
import code
21
import configparser
22
import logging
23
import os
24
import sys
25
26
from gmp import get_version
27
from gmp.clients.helper import authenticate
28
from gmp.connections import (SSHConnection,
29
                             TLSConnection,
30
                             UnixSocketConnection,
31
                             DEFAULT_UNIX_SOCKET_PATH,
32
                             DEFAULT_TIMEOUT,
33
                             DEFAULT_GVM_PORT)
34
from gmp.protocols.latest import Gmp, Osp
35
from gmp.transforms import EtreeCheckCommandTransform
36
37
38
__version__ = get_version()
39
40
logger = logging.getLogger(__name__)
0 ignored issues
show
Coding Style Naming introduced by
The name logger does not conform to the constant naming conventions ((([A-Z_][A-Z0-9_]*)|(__.*__))$).

This check looks for invalid names for a range of different identifiers.

You can set regular expressions to which the identifiers must conform if the defaults do not match your requirements.

If your project includes a Pylint configuration file, the settings contained in that file take precedence.

To find out more about Pylint, please refer to their site.

Loading history...
41
42
PROTOCOL_OSP = 'OSP'
43
PROTOCOL_GMP = 'GMP'
44
DEFAULT_PROTOCOL = PROTOCOL_GMP
45
46
HELP_TEXT = """
47
    gvm-pyshell {version} (C) 2017 Greenbone Networks GmbH
48
49
    This program is a command line tool to access services
50
    via Greenbone Management Protocol (GMP) and
51
    Open Scanner Protocol (OSP).
52
53
    It is possible to start a shell like the python interactive
54
    mode where you could type things like "tasks = gmp.get_task".
55
56
    At the moment only these commands are support in the interactive shell:
57
58
    Example:
59
        gmp.authenticate('admin', 'admin')
60
61
        tasks = gmp.get_tasks()
62
63
        list = tasks.xpath('task')
64
65
        taskid = list[0].attrib
66
67
    Good introduction in working with XPath is well described here:
68
    https://www.w3schools.com/xml/xpath_syntax.asp
69
70
    To get out of the shell enter:
71
        Ctrl + D on Linux  or
72
        Ctrl + Z on Windows
73
74
    Further Information about the GMP Protocol can be found at:
75
    http://docs.greenbone.net/index.html#api_documentation
76
    Note: "GMP" was formerly known as "OMP".
77
78
    This program is free software: you can redistribute it and/or modify
79
    it under the terms of the GNU General Public License as published by
80
    the Free Software Foundation, either version 3 of the License, or
81
    (at your option) any later version.
82
83
    This program is distributed in the hope that it will be useful,
84
    but WITHOUT ANY WARRANTY; without even the implied warranty of
85
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
86
    GNU General Public License for more details.
87
88
    You should have received a copy of the GNU General Public License
89
    along with this program.  If not, see <http://www.gnu.org/licenses/>.
90
    """.format(version=__version__)
91
92
93
class Help(object):
0 ignored issues
show
Unused Code introduced by
The variable __class__ seems to be unused.
Loading history...
94
    """Help class to overwrite the help function from python itself.
95
    """
96
97
    def __call__(self):
98
        return print(HELP_TEXT)
99
100
    def __repr__(self):
101
        # do pwd command
102
        return HELP_TEXT
103
104
105
class Arguments:
0 ignored issues
show
Coding Style introduced by
This class should have a docstring.

The coding style of this project requires that you add a docstring to this code element. Below, you find an example for methods:

class SomeClass:
    def some_method(self):
        """Do x and return foo."""

If you would like to know more about docstrings, we recommend to read PEP-257: Docstring Conventions.

Loading history...
Unused Code introduced by
The variable __class__ seems to be unused.
Loading history...
106
107
    def __init__(self, **kwargs):
108
        self._args = kwargs
109
110
    def get(self, key):
0 ignored issues
show
Coding Style introduced by
This method should have a docstring.

The coding style of this project requires that you add a docstring to this code element. Below, you find an example for methods:

class SomeClass:
    def some_method(self):
        """Do x and return foo."""

If you would like to know more about docstrings, we recommend to read PEP-257: Docstring Conventions.

Loading history...
111
        return self._args[key]
112
113
    def __getattr__(self, key):
114
        return self.get(key)
115
116
    def __setattr__(self, name, value):
117
        if name.startswith('_'):
118
            super().__setattr__(name, value)
119
        else:
120
            self._args[name] = value
121
122
    def __getitem__(self, key):
123
        return self.get(key)
124
125
    def __repr__(self):
126
        return repr(self._args)
127
128
129
def main():
0 ignored issues
show
Coding Style introduced by
This function should have a docstring.

The coding style of this project requires that you add a docstring to this code element. Below, you find an example for methods:

class SomeClass:
    def some_method(self):
        """Do x and return foo."""

If you would like to know more about docstrings, we recommend to read PEP-257: Docstring Conventions.

Loading history...
Comprehensibility introduced by
This function exceeds the maximum number of variables (29/15).
Loading history...
130
    parser = argparse.ArgumentParser(
131
        prog='gvm-pyshell',
132
        description=HELP_TEXT,
133
        formatter_class=argparse.RawTextHelpFormatter,
134
        add_help=False,
135
        epilog="""
136
usage: gvm-pyshell [-h] [--version] [connection_type] ...
137
   or: gvm-pyshell connection_type --help""")
138
    subparsers = parser.add_subparsers(metavar='[connection_type]')
139
    subparsers.required = True
140
    subparsers.dest = 'connection_type'
141
142
    parser.add_argument(
143
        '-h', '--help', action='help',
144
        help='Show this help message and exit.')
145
146
    parent_parser = argparse.ArgumentParser(add_help=False)
147
148
    parent_parser.add_argument(
149
        '-c', '--config', nargs='?', const='~/.config/gvm-tools.conf',
150
        help='Configuration file path. Default: ~/.config/gvm-tools.conf')
151
    args_before, remaining_args = parent_parser.parse_known_args()
152
153
    defaults = {
154
        'gmp_username': '',
155
        'gmp_password': ''
156
    }
157
158
    # Retrieve data from config file
159
    if args_before.config:
160
        try:
161
            config = configparser.SafeConfigParser()
162
            path = os.path.expanduser(args_before.config)
163
            config.read(path)
164
            defaults = dict(config.items('Auth'))
165
        except Exception as e: # pylint: disable=broad-except
0 ignored issues
show
Coding Style Naming introduced by
The name e does not conform to the variable naming conventions ((([a-z][a-z0-9_]{2,30})|(_[a-z0-9_]*))$).

This check looks for invalid names for a range of different identifiers.

You can set regular expressions to which the identifiers must conform if the defaults do not match your requirements.

If your project includes a Pylint configuration file, the settings contained in that file take precedence.

To find out more about Pylint, please refer to their site.

Loading history...
166
            print(str(e), file=sys.stderr)
167
168
    parent_parser.set_defaults(**defaults)
169
170
    parent_parser.add_argument(
171
        '--timeout', required=False, default=DEFAULT_TIMEOUT, type=int,
172
        help='Wait <seconds> for response or if value -1, then wait '
173
             'continuously. Default: %(default)s')
174
    parent_parser.add_argument(
175
        '--log', nargs='?', dest='loglevel', const='INFO',
176
        choices=['DEBUG', 'INFO', 'WARNING', 'ERROR', 'CRITICAL'],
177
        help='Activates logging. Default level: INFO.')
178
    parent_parser.add_argument(
179
        '-i', '--interactive', action='store_true', default=False,
180
        help='Start an interactive Python shell.')
181
    parent_parser.add_argument(
182
        '--protocol', required=False, default=DEFAULT_PROTOCOL,
183
        choices=[PROTOCOL_GMP, PROTOCOL_OSP],
184
        help='Protocol to use. Default: %(default)s.')
185
    parent_parser.add_argument('--gmp-username', help='GMP username.')
186
    parent_parser.add_argument('--gmp-password', help='GMP password.')
187
    parent_parser.add_argument(
188
        'scriptname', nargs='?', metavar="SCRIPT",
189
        help='Preload gmp script. Example: myscript.gmp.')
190
    parent_parser.add_argument(
191
        'scriptargs', nargs='*', metavar="ARG",
192
        help='Arguments for the script.')
193
194
    parser_ssh = subparsers.add_parser(
195
        'ssh', help='Use SSH connection for gmp service.',
196
        parents=[parent_parser])
197
    parser_ssh.add_argument('--hostname', required=True,
198
                            help='Hostname or IP-Address.')
199
    parser_ssh.add_argument('--port', required=False,
200
                            default=22, help='Port. Default: %(default)s.')
201
    parser_ssh.add_argument('--ssh-user', default='gmp',
202
                            help='SSH Username. Default: %(default)s.')
203
204
    parser_tls = subparsers.add_parser(
205
        'tls', help='Use TLS secured connection for gmp service.',
206
        parents=[parent_parser])
207
    parser_tls.add_argument('--hostname', required=True,
208
                            help='Hostname or IP-Address.')
209
    parser_tls.add_argument('--port', required=False,
210
                            default=DEFAULT_GVM_PORT,
211
                            help='Port. Default: %(default)s.')
212
    parser_tls.add_argument('--certfile', required=False, default=None,
213
                            help='Path to the client certificate file.')
214
    parser_tls.add_argument('--keyfile', required=False, default=None,
215
                            help='Path to key certificate file.')
216
    parser_tls.add_argument('--cafile', required=False, default=None,
217
                            help='Path to CA certificate file.')
218
    parser_tls.add_argument('--no-credentials', required=False, default=False,
219
                            help='Use only certificates.')
220
221
    parser_socket = subparsers.add_parser(
222
        'socket', help='Use UNIX-Socket connection for gmp service.',
223
        parents=[parent_parser])
224
    parser_socket.add_argument(
225
        '--sockpath', nargs='?',
226
        help='Depreacted. Use --socketpath instead')
227
    parser_socket.add_argument(
228
        '--socketpath', nargs='?', default=DEFAULT_UNIX_SOCKET_PATH,
229
        help='UNIX-Socket path. Default: %(default)s.')
230
231
    parser.add_argument(
232
        '-V', '--version', action='version',
233
        version='%(prog)s {version}'.format(version=__version__),
234
        help='Show program\'s version number and exit')
235
236
    args = parser.parse_args(remaining_args)
237
238
    # Sets the logging
239
    if args.loglevel is not None:
240
        level = logging.getLevelName(args.loglevel)
241
        logging.basicConfig(filename='gvm-pyshell.log', level=level)
242
243
    # If timeout value is -1, then the socket has no timeout for this session
244
    if args.timeout == -1:
245
        args.timeout = None
246
247
    # Open the right connection. SSH at last for default
248 View Code Duplication
    if 'socket' in args.connection_type:
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
249
        socketpath = args.sockpath
250
        if socketpath is None:
251
            socketpath = args.socketpath
252
        else:
253
            print('The --sockpath parameter has been deprecated. Please use '
254
                  '--socketpath instead', file=sys.stderr)
255
256
        connection = UnixSocketConnection(path=socketpath,
257
                                          timeout=args.timeout)
258
    elif 'tls' in args.connection_type:
259
        connection = TLSConnection(
260
            timeout=args.timeout,
261
            hostname=args.hostname,
262
            port=args.port,
263
            certfile=args.certfile,
264
            keyfile=args.keyfile,
265
            cafile=args.cafile,
266
        )
267
    else:
268
        connection = SSHConnection(hostname=args.hostname, port=args.port,
269
                                   timeout=args.timeout, username=args.ssh_user,
270
                                   password='')
271
272
    transform = EtreeCheckCommandTransform()
273
274
    global_vars = {
275
        'help': Help(),
276
    }
277
278
    username = None
279
    password = None
280
281
    if args.protocol == PROTOCOL_OSP:
282
        protocol = Osp(connection, transform=transform)
283
        global_vars['osp'] = protocol
284
        global_vars['__name__'] = '__osp__'
285
    else:
286
        protocol = Gmp(connection, transform=transform)
287
        global_vars['gmp'] = protocol
288
        global_vars['__name__'] = '__gmp__'
289
290
        if args.gmp_username:
291
            (username, password) = authenticate(
292
                protocol, username=args.gmp_username,
293
                password=args.gmp_password)
294
295
    shell_args = Arguments(
296
        username=username, password=password)
297
298
    global_vars['args'] = shell_args
299
300
    with_script = args.scriptname and len(args.scriptname) > 0
301
302
    if with_script:
303
        argv = [os.path.abspath(args.scriptname), *args.scriptargs]
304
        shell_args.argv = argv
0 ignored issues
show
Coding Style introduced by
The attribute argv was defined outside __init__.

It is generally a good practice to initialize all attributes to default values in the __init__ method:

class Foo:
    def __init__(self, x=None):
        self.x = x
Loading history...
305
        # for backwards compatibility we add script here
306
        shell_args.script = argv
0 ignored issues
show
Coding Style introduced by
The attribute script was defined outside __init__.

It is generally a good practice to initialize all attributes to default values in the __init__ method:

class Foo:
    def __init__(self, x=None):
        self.x = x
Loading history...
307
308
    no_script_no_interactive = not args.interactive and not with_script
309
    script_and_interactive = args.interactive and with_script
310
    only_interactive = not with_script and args.interactive
311
    only_script = not args.interactive and with_script
312
313
    if only_interactive or no_script_no_interactive:
314
        enter_interactive_mode(global_vars)
315
316
    if script_and_interactive or only_script:
317
        script_name = args.scriptname
318
        load(script_name, global_vars)
319
320
    if not only_script:
321
        enter_interactive_mode(global_vars)
322
323
    protocol.disconnect()
324
325
326
def enter_interactive_mode(global_vars):
0 ignored issues
show
Coding Style introduced by
This function should have a docstring.

The coding style of this project requires that you add a docstring to this code element. Below, you find an example for methods:

class SomeClass:
    def some_method(self):
        """Do x and return foo."""

If you would like to know more about docstrings, we recommend to read PEP-257: Docstring Conventions.

Loading history...
327
    code.interact(
328
        banner='GVM Interactive Console. Type "help" to get information \
329
about functionality.',
330
        local=dict(global_vars))
331
332
333
def load(path, global_vars):
334
    """Loads a file into the interactive console
335
336
    Loads a file into the interactive console and execute it.
337
    TODO: Needs some security checks.
338
339
    Arguments:
340
        path {str} -- Path of file
341
    """
342
    try:
343
        file = open(path, 'r', newline='').read()
344
345
        exec(file, global_vars) # pylint: disable=exec-used
346
    except OSError as e:
0 ignored issues
show
Coding Style Naming introduced by
The name e does not conform to the variable naming conventions ((([a-z][a-z0-9_]{2,30})|(_[a-z0-9_]*))$).

This check looks for invalid names for a range of different identifiers.

You can set regular expressions to which the identifiers must conform if the defaults do not match your requirements.

If your project includes a Pylint configuration file, the settings contained in that file take precedence.

To find out more about Pylint, please refer to their site.

Loading history...
347
        print(str(e))
348
349
350
if __name__ == '__main__':
351
    main()
352