From eb378f46d55a8911e9e84ae42f018e766d68cd65 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Otto=20Kek=C3=A4l=C3=A4inen?= Date: Sun, 3 Feb 2019 20:44:48 +0100 Subject: [PATCH] Clean up and document AppArmor UI module - Add documentation stub for what the UI module is and how JSON works - Make indentation consistent - Use pythonic 'if' clauses - Add two spaces after function definitions (Python style) --- utils/apparmor/ui.py | 55 ++++++++++++++++++++++++++++++++++++-------- 1 file changed, 45 insertions(+), 10 deletions(-) diff --git a/utils/apparmor/ui.py b/utils/apparmor/ui.py index cdb712f3d..28b372012 100644 --- a/utils/apparmor/ui.py +++ b/utils/apparmor/ui.py @@ -32,22 +32,36 @@ _ = init_translation() debug_logger = DebugLogger('UI') # If Python3, wrap input in raw_input so make check passes -if not 'raw_input' in dir(__builtins__): raw_input = input +if 'raw_input' not in dir(__builtins__): + raw_input = input ARROWS = {'A': 'UP', 'B': 'DOWN', 'C': 'RIGHT', 'D': 'LEFT'} UI_mode = 'text' + def write_json(jsonout): - print(json.dumps(jsonout, sort_keys=False, separators=(',', ': '))) - sys.stdout.flush() + print(json.dumps(jsonout, sort_keys=False, separators=(',', ': '))) + sys.stdout.flush() + def set_json_mode(): + """ + Currently this is only used by aa-genprof and aa-logprof, while e.g. + aa-status generates its own JSON ourput. + + Remember to bump the JSON API version number if the output commands + in this file are modified. + + Current known consumers of the JSON output: + - YaST + """ global UI_mode UI_mode = 'json' jsonout = {'dialog': 'apparmor-json-version', 'data': '2.12'} write_json(jsonout) + # reads the response on command line for json and verifies the response # for the dialog type def json_response(dialog_type): @@ -57,6 +71,7 @@ def json_response(dialog_type): raise AppArmorException('Expected response %s got %s.' % (dialog_type, string)) return rh + def getkey(): key = readkey() if key == '\x1B': @@ -67,7 +82,9 @@ def getkey(): key = ARROWS[key] return key.strip() + def UI_Info(text): + """Facility to output normal text""" debug_logger.info(text) if UI_mode == 'json': jsonout = {'dialog': 'info', 'data': text} @@ -75,7 +92,9 @@ def UI_Info(text): else: # text mode sys.stdout.write(text + '\n') + def UI_Important(text): + """Facility to output important text""" debug_logger.debug(text) if UI_mode == 'json': jsonout = {'dialog': 'important', 'data': text} @@ -83,6 +102,7 @@ def UI_Important(text): else: # text mode sys.stdout.write('\n' + text + '\n') + def get_translated_hotkey(translated, cmsg=''): msg = 'PromptUser: ' + _('Invalid hotkey for') @@ -95,6 +115,7 @@ def get_translated_hotkey(translated, cmsg=''): else: raise AppArmorException('%s %s' % (msg, translated)) + def UI_YesNo(text, default): debug_logger.debug('UI_YesNo: %s: %s %s' % (UI_mode, text, default)) default = default.lower() @@ -134,6 +155,7 @@ def UI_YesNo(text, default): ans = default return ans + def UI_YesNoCancel(text, default): debug_logger.debug('UI_YesNoCancel: %s: %s %s' % (UI_mode, text, default)) default = default.lower() @@ -184,6 +206,7 @@ def UI_YesNoCancel(text, default): ans = default return ans + def UI_GetString(text, default): debug_logger.debug('UI_GetString: %s: %s %s' % (UI_mode, text, default)) string = default @@ -201,6 +224,7 @@ def UI_GetString(text, default): readline.set_startup_hook() return string.strip() + def UI_GetFile(file): debug_logger.debug('UI_GetFile: %s' % UI_mode) filename = None @@ -213,24 +237,29 @@ def UI_GetFile(file): filename = sys.stdin.read() return filename + def UI_BusyStart(message): debug_logger.debug('UI_BusyStart: %s' % UI_mode) UI_Info(message) + def UI_BusyStop(): debug_logger.debug('UI_BusyStop: %s' % UI_mode) + def diff(oldprofile, newprofile): difftemp = tempfile.NamedTemporaryFile('w') subprocess.call('diff -u -p %s %s > %s' % (oldprofile, newprofile, difftemp.name), shell=True) return difftemp + def write_profile_to_tempfile(profile): temp = tempfile.NamedTemporaryFile('w') temp.write(profile) temp.flush() return temp + def generate_diff(oldprofile, newprofile): oldtemp = write_profile_to_tempfile(oldprofile) newtemp = write_profile_to_tempfile(newprofile) @@ -239,6 +268,7 @@ def generate_diff(oldprofile, newprofile): newtemp.close() return difftemp + def generate_diff_with_comments(oldprofile, newprofile): if not os.path.exists(oldprofile): raise AppArmorException(_("Can't find existing profile %s to compare changes.") % oldprofile) @@ -247,21 +277,23 @@ def generate_diff_with_comments(oldprofile, newprofile): newtemp.close() return difftemp + def UI_Changes(oldprofile, newprofile, comments=False): - if comments == False: - difftemp = generate_diff(oldprofile, newprofile) - header = 'View Changes' + if not comments: + difftemp = generate_diff(oldprofile, newprofile) + header = 'View Changes' else: - difftemp = generate_diff_with_comments(oldprofile, newprofile) - header = 'View Changes with comments' + difftemp = generate_diff_with_comments(oldprofile, newprofile) + header = 'View Changes with comments' if UI_mode == 'json': - jsonout = {'dialog': 'changes', 'header':header, 'filename': difftemp.name} + jsonout = {'dialog': 'changes', 'header': header, 'filename': difftemp.name} write_json(jsonout) json_response('changes')["response"] # wait for response to delay deletion of difftemp (and ignore response content) else: - subprocess.call('less %s' % difftemp.name, shell=True) + subprocess.call('less %s' % difftemp.name, shell=True) difftemp.close() + CMDS = {'CMD_ALLOW': _('(A)llow'), 'CMD_OTHER': _('(M)ore'), 'CMD_AUDIT_NEW': _('Audi(t)'), @@ -324,6 +356,7 @@ CMDS = {'CMD_ALLOW': _('(A)llow'), 'CMD_IGNORE_ENTRY': _('(I)gnore') } + class PromptQuestion(object): title = None headers = None @@ -494,12 +527,14 @@ class PromptQuestion(object): return ans, selected + def confirm_and_abort(): ans = UI_YesNo(_('Are you sure you want to abandon this set of profile changes and exit?'), 'n') if ans == 'y': UI_Info(_('Abandoning all changes.')) sys.exit(0) + def is_number(number): try: return int(number)