Coverage for /home/ken/.local/lib/python3.6/site-packages/avendesora/utilities.py: 32%

# Coverage for /home/ken/.local/lib/python3.6/site-packages/avendesora/utilities.py : 32%

## 81 statements 26 run 55 missing 0 excluded

Hot-keys on this page

r m x p toggle line displays

j k next/prev highlighted chunk

0 (zero) top of page

1 (one) first highlighted chunk

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 | # Utilities # License {{{1 # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see http://www.gnu.org/licenses/. # Imports {{{1 from .config import get_setting from .gpg import get_active_file from shlib import Run, to_path from inform import ( codicil, fatal, os_error, output, warn, is_str, is_collection, indent ) from textwrap import dedent, wrap from pkg_resources import resource_filename import hashlib import os # gethostname {{{1 # returns short version of the hostname (the hostname without any domain name) import socket def gethostname(): return socket.gethostname().split('.')[0] # getusername {{{1 import getpass def getusername(): return getpass.getuser() # generate_random_string {{{1 def generate_random_string(length=64): # Generate a random long string to act as the default password from string import ascii_letters, digits, punctuation import random rand = random.SystemRandom() # Create alphabet from letters, digits, and punctuation, but # replace double quote with a space so password can be safely # represented as a double-quoted string. alphabet = (ascii_letters + digits + punctuation).replace('"', ' ') password = '' for i in range(length): password += rand.choice(alphabet) return password # validate_componenets {{{1 def validate_componenets(): # find dictionary file dict_path = get_setting('dictionary_file') if not dict_path.is_file(): # user did not provide a dictionary, so use the internal one dict_path = to_path(resource_filename(__name__, 'words')) # Check that files that are critical to the integrity of the generated # secrets have not changed for path, kind in [ (to_path(resource_filename(__name__, 'secrets.py')), 'secrets_hash'), (to_path(resource_filename(__name__, 'charsets.py')), 'charsets_hash'), (dict_path, 'dict_hash'), ]: try: contents = path.read_text() except OSError as err: fatal(os_error(err)) md5 = hashlib.md5(contents.encode('utf-8')).hexdigest() # Check that file has not changed. if md5 != get_setting(kind): warn("file contents have changed.", culprit=path) codicil( *wrap(dedent("""\ This results in passwords that are inconsistent with those created in the past. Change {hashes} to contain "{kind} = '{md5}'". Then use 'avendesora changed' to assure that nothing has changed. """.format( kind=kind, md5=md5, hashes=get_setting('hashes_file'), ))), sep = '\n' ) # pager {{{1 def pager(text): if get_setting('use_pager'): program = os.environ.get('PAGER', 'less') Run([program], stdin=text, modes='Woes') else: output(text) # two_columns {{{1 def two_columns(col1, col2, width=16, indent=True): indent = get_setting('indent') if indent else '' if len(col1) > width: return '%s%s\n%s%s%s' % ( indent, col1, indent, ' '+width*' ', col2 ) else: return '%s%-*s %s' % (indent, width, col1, col2) # to_python {{{1 def to_python(obj, _level=0): """Recursively convert object to string with reasonable formatting""" def leader(relative_level=0): return (_level+relative_level)*' ' code = [] if type(obj) == dict: code += ['{'] for key in sorted(obj.keys()): value = obj[key] code += ['%s%r: %s,' % ( leader(1), key, to_python(value, _level+1) )] code += ['%s}' % (leader(0))] elif type(obj) == list: code += ['['] for each in obj: code += ['%s%s,' % ( leader(1), to_python(each, _level+1) )] code += ['%s]' % (leader(0))] elif type(obj) == tuple: code += ['('] for each in obj: code += ['%s%s,' % ( leader(1), to_python(each, _level+1) )] code += ['%s)' % (leader(0))] elif type(obj) == set: code += ['set(['] for each in sorted(obj): code += ['%s%s,' % ( leader(1), to_python(each, _level+1) )] code += ['%s])' % (leader(0))] elif is_str(obj) and '\n' in obj: code += ['"""' + indent(dedent(obj), leader(1)) + leader(0) + '"""'] else: code += [repr(obj)] return '\n'.join(code) # error_source {{{1 def error_source(lvl=3): """Source of error Reads stack trace to determine filename and lineno of error. """ import traceback try: # return filename and lineno # context and content are also available return traceback.extract_stack()[-lvl][:2] except SyntaxError: # extract_stack() does not work on binary encrypted files. It generates # a syntax error that indicates that the file encoding is missing # because the function tries to read the file and sees binary data. This # is not a problem with ascii encrypted files as we don't actually show # code, which is gibberish, but does not require an encoding. return get_active_file()