Completed
Push — master ( 988766...6e9c74 )
by
unknown
14s queued 10s
created

gvmtools.cli   A

Complexity

Total Complexity 17

Size/Duplication

Total Lines 263
Duplicated Lines 10.65 %

Importance

Changes 0
Metric Value
eloc 161
dl 28
loc 263
rs 10
c 0
b 0
f 0
wmc 17

1 Function

Rating   Name   Duplication   Size   Complexity  
F main() 28 186 17

How to fix   Duplicated Code   

Duplicated Code

Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.

Common duplication problems, and corresponding solutions are:

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 configparser
21
import getpass
22
import logging
23
import os.path
24
import sys
25
26
from gvm.protocols.latest import Gmp
27
from gvm.connections import (SSHConnection,
28
                             TLSConnection,
29
                             UnixSocketConnection,
30
                             DEFAULT_UNIX_SOCKET_PATH,
31
                             DEFAULT_TIMEOUT,
32
                             DEFAULT_GVM_PORT)
33
from gvm.transforms import CheckCommandTransform
34
35
from gvmtools import get_version
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
HELP_TEXT = """
43
    gvm-cli {version} (C) 2017 Greenbone Networks GmbH
44
45
    This program is a command line tool to access services via
46
    GMP (Greenbone Management Protocol).
47
48
    Examples:
49
50
    gvm-cli socket --xml "<get_version/>"
51
    gvm-cli socket --xml "<commands><authenticate><credentials><username>myuser</username><password>mypass</password></credentials></authenticate><get_tasks/></commands>"
52
    gvm-cli socket --gmp-username foo --gmp-password foo < myfile.xml
53
54
    Further Information about GMP see here:
55
    http://docs.greenbone.net/index.html#api_documentation
56
    Note: "GMP" was formerly known as "OMP".
57
58
    This program is free software: you can redistribute it and/or modify
59
    it under the terms of the GNU General Public License as published by
60
    the Free Software Foundation, either version 3 of the License, or
61
    (at your option) any later version.
62
63
    This program is distributed in the hope that it will be useful,
64
    but WITHOUT ANY WARRANTY; without even the implied warranty of
65
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
66
    GNU General Public License for more details.
67
68
    You should have received a copy of the GNU General Public License
69
    along with this program.  If not, see <http://www.gnu.org/licenses/>.
70
    """.format(version=__version__)
71
72
73
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 (19/15).
Loading history...
74
    parser = argparse.ArgumentParser(
75
        prog='gvm-cli',
76
        description=HELP_TEXT,
77
        formatter_class=argparse.RawTextHelpFormatter,
78
        add_help=False,
79
        epilog="""
80
usage: gvm-cli [-h] [--version] [connection_type] ...
81
   or: gvm-cli connection_type --help""")
82
83
    subparsers = parser.add_subparsers(metavar='[connection_type]')
84
    subparsers.required = True
85
    subparsers.dest = 'connection_type'
86
87
    parser.add_argument(
88
        '-h', '--help', action='help',
89
        help='Show this help message and exit.')
90
91
    parent_parser = argparse.ArgumentParser(add_help=False)
92
    parent_parser.add_argument(
93
        '-c', '--config', nargs='?', const='~/.config/gvm-tools.conf',
94
        help='Configuration file path. Default: ~/.config/gvm-tools.conf')
95
    args, remaining_args = parent_parser.parse_known_args()
96
97
    defaults = {
98
        'gmp_username': '',
99
        'gmp_password': ''
100
    }
101
102
    # Retrieve data from config file
103
    if args.config:
104
        try:
105
            config = configparser.SafeConfigParser()
106
            path = os.path.expanduser(args.config)
107
            config.read(path)
108
            defaults = dict(config.items('Auth'))
109
        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...
110
            print(str(e))
111
112
    parent_parser.set_defaults(**defaults)
113
114
    parent_parser.add_argument(
115
        '--timeout', required=False, default=DEFAULT_TIMEOUT, type=int,
116
        help='Wait <seconds> for response or if value is -1, then wait '
117
             'indefinitely. Default: %(default)s.')
118
    parent_parser.add_argument(
119
        '--log', nargs='?', dest='loglevel', const='INFO',
120
        choices=['DEBUG', 'INFO', 'WARNING', 'ERROR', 'CRITICAL'],
121
        help='Activates logging. Default level: %(default)s.')
122
    parent_parser.add_argument('--gmp-username', help='GMP username.')
123
    parent_parser.add_argument('--gmp-password', help='GMP password.')
124
    parent_parser.add_argument('-X', '--xml', help='The XML request to send.')
125
    parent_parser.add_argument('-r', '--raw', help='Return raw XML.',
126
                               action='store_true', default=False)
127
    parent_parser.add_argument('infile', nargs='?', type=open,
128
                               default=sys.stdin)
129
130
    parser_ssh = subparsers.add_parser(
131
        'ssh', help='Use SSH connection for gmp service.',
132
        parents=[parent_parser])
133
    parser_ssh.add_argument('--hostname', required=True,
134
                            help='Hostname or IP-Address.')
135
    parser_ssh.add_argument('--port', required=False,
136
                            default=22, help='Port. Default: %(default)s.')
137
    parser_ssh.add_argument('--ssh-user', default='gmp',
138
                            help='SSH Username. Default: %(default)s.')
139
    parser_ssh.add_argument('--ssh-password', default='gmp',
140
                            help='SSH Password. Default: %(default)s.')
141
142
    parser_tls = subparsers.add_parser(
143
        'tls', help='Use TLS secured connection for gmp service.',
144
        parents=[parent_parser])
145
    parser_tls.add_argument('--hostname', required=True,
146
                            help='Hostname or IP-Address.')
147
    parser_tls.add_argument('--port', required=False,
148
                            default=DEFAULT_GVM_PORT,
149
                            help='Port. Default: %(default)s.')
150
    parser_tls.add_argument('--certfile', required=False, default=None,
151
                            help='Path to the certificate file.')
152
    parser_tls.add_argument('--keyfile', required=False, default=None,
153
                            help='Path to key certificate file.')
154
    parser_tls.add_argument('--cafile', required=False, default=None,
155
                            help='Path to CA certificate file.')
156
157
    parser_socket = subparsers.add_parser(
158
        'socket', help='Use UNIX-Socket connection for gmp service.',
159
        parents=[parent_parser])
160
    parser_socket.add_argument(
161
        '--sockpath', nargs='?', default=None,
162
        help='Depreacted. Use --socketpath instead')
163
    parser_socket.add_argument(
164
        '--socketpath', nargs='?', default=DEFAULT_UNIX_SOCKET_PATH,
165
        help='UNIX-Socket path. Default: %(default)s.')
166
167
    parser.add_argument(
168
        '-V', '--version', action='version',
169
        version='%(prog)s {version}'.format(version=__version__),
170
        help='Show program\'s version number and exit')
171
172
    args = parser.parse_args(remaining_args)
173
174
    # Sets the logging
175
    if args.loglevel is not None:
176
        level = logging.getLevelName(args.loglevel)
177
        logging.basicConfig(filename='gvm-cli.log', level=level)
178
179
    # If timeout value is -1, then the socket has no timeout for this session
180
    if args.timeout == -1:
181
        args.timeout = None
182
183
    xml = ''
184
185
    if args.xml is not None:
186
        xml = args.xml
187
    else:
188
        # If this returns False, then some data are in sys.stdin
189
        if not args.infile.isatty():
190
            try:
191
                xml = args.infile.read()
192
            except (EOFError, BlockingIOError) 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...
193
                print(e)
194
195
    # If no command was given, program asks for one
196
    if len(xml) == 0:
0 ignored issues
show
Unused Code introduced by
Do not use len(SEQUENCE) as condition value
Loading history...
197
        xml = input()
198
199
    # Remove all newlines if the commands come from file
200
    xml = xml.replace('\n', '').replace('\r', '')
201
202
    # Ask for password if none are given
203
    if args.gmp_username and not args.gmp_password:
204
        args.gmp_password = getpass.getpass('Enter password for ' +
205
                                            args.gmp_username + ': ')
206
207
    # Open the right connection. SSH at last for default
208 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...
209
        socketpath = args.sockpath
210
        if socketpath is None:
211
            socketpath = args.socketpath
212
        else:
213
            print('The --sockpath parameter has been deprecated. Please use '
214
                  '--socketpath instead', file=sys.stderr)
215
216
        connection = UnixSocketConnection(
217
            timeout=args.timeout,
218
            path=socketpath
219
        )
220
    elif 'tls' in args.connection_type:
221
        connection = TLSConnection(
222
            timeout=args.timeout,
223
            hostname=args.hostname,
224
            port=args.port,
225
            certfile=args.certfile,
226
            keyfile=args.keyfile,
227
            cafile=args.cafile,
228
        )
229
    else:
230
        connection = SSHConnection(
231
            timeout=args.timeout,
232
            hostname=args.hostname,
233
            port=args.port,
234
            username=args.ssh_user,
235
            password=args.ssh_password
236
        )
237
238
    if args.raw:
239
        transform = None
240
    else:
241
        transform = CheckCommandTransform()
242
243
    gvm = Gmp(connection, transform=transform)
244
245
    if args.gmp_username:
246
        gvm.authenticate(args.gmp_username, args.gmp_password)
247
248
    try:
249
        result = gvm.send_command(xml)
250
251
        print(result)
252
    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...
253
        print(e)
254
        sys.exit(1)
255
256
    gvm.disconnect()
257
258
    sys.exit(0)
259
260
261
if __name__ == '__main__':
262
    main()
263