setools/setoolsgui/apol/permmapedit.py
Chris PeBenito 8e082f70cf Replace license text in sources with SPDX license indentifiers.
Signed-off-by: Chris PeBenito <pebenito@ieee.org>
2021-11-20 14:12:15 -05:00

223 lines
7.5 KiB
Python

# Copyright 2016, Tresys Technology, LLC
#
# SPDX-License-Identifier: LGPL-2.1-only
#
#
import logging
import copy
from PyQt5.QtCore import pyqtSignal, pyqtSlot, Qt
from PyQt5.QtGui import QPalette
from PyQt5.QtWidgets import QDialog, QFrame, QWidget
from ..models import SEToolsListModel
from ..widget import SEToolsWidget
class PermissionMapEditor(SEToolsWidget, QDialog):
"""
A permission map editor. This dialog has two versions,
one for editing the weight/direction and another for
including or excluding permissions in an analysis.
Parameters:
parent The parent Qt widget
edit (bool) If true, the dialog will take
the editor behavior. If False, the dialog
will take the enable/disable permission
behavior.
"""
class_toggle = pyqtSignal(bool)
def __init__(self, parent, edit):
super(PermissionMapEditor, self).__init__(parent)
self.log = logging.getLogger(__name__)
self.parent = parent
self.edit = edit
self.setupUi()
def setupUi(self):
self.load_ui("apol/permmap_editor.ui")
# set up class list
self.class_model = SEToolsListModel(self)
self.classes.setModel(self.class_model)
# permission widgets
self.widgets = []
# set up editor mode
self.enable_all.setHidden(self.edit)
self.disable_all.setHidden(self.edit)
# connect signals
self.classes.selectionModel().selectionChanged.connect(self.class_selected)
self.enable_all.clicked.connect(self.enable_all_perms)
self.disable_all.clicked.connect(self.disable_all_perms)
def show(self, perm_map):
# keep an internal copy because the map is mutable
# and this dialog may be canceled after some edits.
self.perm_map = copy.deepcopy(perm_map)
self.class_model.item_list = sorted(perm_map.classes())
# clear class selection and mappings
# since this widget will typically
# be reused.
self.classes.clearSelection()
self._clear_mappings()
self.enable_all.setToolTip(None)
self.disable_all.setToolTip(None)
if self.edit:
self.setWindowTitle("{0} - Permission Map Editor - apol".format(self.perm_map))
else:
self.setWindowTitle("{0} - Permission Map Viewer - apol".format(self.perm_map))
super(PermissionMapEditor, self).show()
def accept(self):
self.parent.apply_permmap(self.perm_map)
super(PermissionMapEditor, self).accept()
def class_selected(self):
# the .ui is set to 1 selection
for index in self.classes.selectionModel().selectedIndexes():
class_name = self.class_model.data(index, Qt.DisplayRole)
self.log.debug("Setting class to {0}".format(class_name))
self.enable_all.setToolTip("Include all permissions in the {0} class.".format(class_name))
self.disable_all.setToolTip("Exclude all permissions in the {0} class.".format(class_name))
self._clear_mappings()
# populate new mappings
for perm in sorted(self.perm_map.perms(class_name)):
# create permission mapping
mapping = PermissionMapping(self, perm, self.edit)
mapping.setAttribute(Qt.WA_DeleteOnClose)
self.class_toggle.connect(mapping.enabled.setChecked)
self.perm_mappings.addWidget(mapping)
self.widgets.append(mapping)
# add horizonal line
line = QFrame(self)
line.setFrameShape(QFrame.HLine)
line.setFrameShadow(QFrame.Sunken)
self.perm_mappings.addWidget(line)
self.widgets.append(line)
def enable_all_perms(self):
self.class_toggle.emit(True)
def disable_all_perms(self):
self.class_toggle.emit(False)
#
# Internal functions
#
def _clear_mappings(self):
# delete current mappings
for mapping in self.widgets:
mapping.close()
self.widgets.clear()
index_to_setting = ["r", "w", "b", "n"]
index_to_word = ["Read", "Write", "Both", "None"]
setting_to_index = {"r": 0, "w": 1, "b": 2, "n": 3}
class PermissionMapping(SEToolsWidget, QWidget):
"""
A widget representing mapping for a particular permission.
This dialog has two versions, one for editing the weight/direction
and another for including or excluding permissions in an analysis.
Parameters:
parent The parent Qt widget
edit (bool) If true, the widget will take
the editor behavior. If False, the dialog
will take the enable/disable permission
behavior.
"""
def __init__(self, parent, mapping, edit):
super(PermissionMapping, self).__init__(parent)
self.log = logging.getLogger(__name__)
self.parent = parent
self.mapping = mapping
self.edit = edit
self.setupUi()
def setupUi(self):
self.load_ui("apol/permmapping.ui")
self.permission.setText(str(self.mapping.perm))
self.weight.setValue(self.mapping.weight)
self.enabled.setChecked(self.mapping.enabled)
if self.edit:
self.weight.setToolTip("Set the information flow weight of {0}".format(
self.mapping.perm))
self.direction.setToolTip("Set the information flow direction of {0}".format(
self.mapping.perm))
else:
self.enabled.setToolTip("Include or exclude {0} from the analysis.".format(
self.mapping.perm))
self.weight.setEnabled(self.edit)
self.direction.setEnabled(self.edit)
self.enabled.setHidden(self.edit)
# setup color palettes for direction
self.orig_palette = self.direction.palette()
self.error_palette = self.direction.palette()
self.error_palette.setColor(QPalette.Button, Qt.red)
self.error_palette.setColor(QPalette.ButtonText, Qt.white)
# setup direction
self.direction.insertItems(0, index_to_word)
if self.mapping.direction == 'u':
# Temporarily add unmapped value to items
self.direction.insertItem(len(index_to_word), "Unmapped")
self.direction.setCurrentText("Unmapped")
self.direction.setPalette(self.error_palette)
self.unmapped = True
else:
self.direction.setCurrentIndex(setting_to_index[self.mapping.direction])
self.unmapped = False
# connect signals
self.direction.currentIndexChanged.connect(self.set_direction)
self.weight.valueChanged.connect(self.set_weight)
self.enabled.toggled.connect(self.set_enabled)
def set_direction(self, value):
if self.unmapped:
if value == "Unmapped":
return
# Remove unmapped item if setting the mapping.
self.direction.removeItem(len(index_to_word))
self.direction.setPalette(self.orig_palette)
self.unmapped = False
dir_ = index_to_setting[value]
self.log.debug("Setting {0.class_}:{0.perm} direction to {1}".format(self.mapping, dir_))
self.mapping.direction = dir_
def set_weight(self, value):
self.log.debug("Setting {0.class_}:{0.perm} weight to {1}".format(self.mapping, value))
self.mapping.weight = int(value)
def set_enabled(self, value):
self.log.debug("Setting {0.class_}:{0.perm} enabled to {1}".format(self.mapping, value))
self.mapping.enabled = value