Passed
Push — master ( 314eaa...e9b707 )
by Jaspar
01:46 queued 19s
created

gvmtools.helper.generate_id()   A

Complexity

Conditions 1

Size

Total Lines 5
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 3
nop 2
dl 0
loc 5
rs 10
c 0
b 0
f 0
1
# -*- coding: utf-8 -*-
2
# Copyright (C) 2018-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
import getpass
20
import os
21
import sys
22
import uuid
23
import string
24
25
from random import choice, randrange
26
from lxml import etree
27
28
from gvm.errors import GvmError
29
from gvm.xml import pretty_print
30
31
32
__all__ = ['authenticate', 'pretty_print', 'run_script']
33
34
35
class Table:
36
    def __init__(self, heading=None, rows=None, divider=' | '):
37
        self.heading = heading or []
38
        self.rows = rows or []
39
        self.divider = divider
40
41
    def _calculate_dimensions(self):
42
        column_sizes = []
43
44
        for column in self.heading:
45
            column_sizes.append(len(column))
46
47
        for row in self.rows:
48
            for i, column in enumerate(row):
49
                dim = column_sizes[i]
50
                column_size = len(column)
51
52
                if dim < column_size:
53
                    column_sizes[i] = column_size
54
55
        return column_sizes
56
57
    def _create_column(self, column, size):
58
        return '{}{}'.format(column, ' ' * (size - len(column)))
59
60
    def _create_row(self, columns):
61
        return self.divider.join(columns)
62
63
    def __str__(self):
64
        column_sizes = self._calculate_dimensions()
65
66
        row_strings = []
67
68
        heading_columns = []
69
        heading_divider_columns = []
70
71
        for i, column in enumerate(self.heading):
72
            column_size = column_sizes[i]
73
74
            heading_columns.append(self._create_column(column, column_size))
75
            heading_divider_columns.append(
76
                self._create_column('-' * column_size, column_size)
77
            )
78
79
        row_strings.append(self._create_row(heading_columns))
80
        row_strings.append(self._create_row(heading_divider_columns))
81
82
        for row in self.rows:
83
            row_columns = []
84
85
            for i, column in enumerate(row):
86
                column_size = column_sizes[i]
87
                row_columns.append(self._create_column(column, column_size))
88
89
            row_strings.append(self._create_row(row_columns))
90
91
        return "\n".join(row_strings)
92
93
94
def yes_or_no(question):
95
    """Asks the user to proceed or not in a gvmtools script
96
97
    Arguments:
98
        question (str): The condition the user should answer
99
    """
100
    reply = str(input(question + ' (y/n): ')).lower().strip()
101
    if reply[0] == ('y'):
102
        return True
103
    if reply[0] == ('n'):
104
        return False
105
    else:
106
        return yes_or_no("Please enter 'y' or 'n'")
107
108
109
def error_and_exit(msg):
110
    """Prints an error message and quits the gvmtools script
111
112
    Arguments:
113
        msg (str): The error message, that will be printed
114
    """
115
    print("\nError: {}\n".format(msg), file=sys.stderr)
116
    sys.exit(1)
117
118
119
def generate_random_ips(count: int):
120
    """Generate count random IPv4s"""
121
    exclude_127 = [i for i in range(1, 256)]
122
    exclude_127.remove(127)
123
    return [
124
        '{}.{}.{}.{}'.format(
125
            choice(exclude_127),
126
            randrange(0, 256),
127
            randrange(0, 256),
128
            randrange(1, 255),
129
        )
130
        for i in range(count)
131
    ]
132
133
134
def generate_id(
135
    size: int = 12, chars: str = string.ascii_uppercase + string.digits
136
):
137
    """Generate a random ID"""
138
    return ''.join(choice(chars) for _ in range(size))
139
140
141
def generate_uuid():
142
    """Generate a random new uuid"""
143
    return str(uuid.uuid4())
144
145
146
def create_xml_tree(xml_doc):
147
    """Creates an XML tree that can be read by an gvmtools script
148
149
    Arguments:
150
        xml_doc (str): Path to the xml document
151
    """
152
    try:
153
        xml_tree = etree.parse(xml_doc)
154
        xml_tree = xml_tree.getroot()
155
    except IOError as err:
156
        error_and_exit("Failed to read xml_file: {} (exit)".format(str(err)))
157
    except etree.Error as err:
158
        error_and_exit("Failed to parse xml_file: {} (exit)".format(str(err)))
159
160
    if len(xml_tree) == 0:
161
        error_and_exit("XML file is empty (exit)")
162
163
    return xml_tree
164
165
166
def do_not_run_as_root():
167
    if hasattr(os, 'geteuid') and os.geteuid() == 0:
168
        raise RuntimeError('This tool MUST NOT be run as root user.')
169
170
171
def authenticate(gmp, username=None, password=None):
172
    """Authentication helper
173
174
    Tries to get authentication username and password from arguments and if not
175
    present asks the username and/or password from the terminal.
176
177
    Arguments:
178
        gmp: A protocol instance
179
        username (:obj:`str`, optional): Username to authenticate with. If None,
180
            username will be read from terminal.
181
        password (:obj:`str`, optional): Password to authenticate with. If None,
182
            password will be read from the terminal.
183
184
    Returns:
185
        tuple: (username, password) tuple
186
187
    Raises:
188
        GmpError: Raises GmpError if authentication fails.
189
    """
190
    if gmp.is_authenticated():
191
        return
192
193
    # Ask for login credentials if none are given.
194
    if not username:
195
        while username is None or len(username) == 0:
196
            username = input('Enter username: ')
197
198
    if not password:
199
        password = getpass.getpass('Enter password for {0}: '.format(username))
200
201
    try:
202
        gmp.authenticate(username, password)
203
        return (username, password)
204
    except GvmError as e:
205
        print('Could not authenticate. Please check your credentials.')
206
        raise e
207
208
209
def run_script(path, global_vars):
210
    """Loads and executes a file as a python script
211
212
    Arguments:
213
        path (str): Path to the script file
214
        vars (dict): Variables passed as globals to the script
215
    """
216
    try:
217
        file = open(path, 'r', newline='').read()
218
    except FileNotFoundError:
219
        print('Script {path} does not exist'.format(path=path), file=sys.stderr)
220
        sys.exit(2)
221
222
    exec(file, global_vars)  # pylint: disable=exec-used
223