Clean up item model classes.

* Remove "Model" from names of model classes.
* Remove remaining *_detail() functions.
* Add typing.
* Make models dir a package.
* Update for superclass data() method as fallback.
* Switch to match/case statements.

Signed-off-by: Chris PeBenito <pebenito@ieee.org>
This commit is contained in:
Chris PeBenito 2023-08-03 14:40:51 -04:00 committed by Chris PeBenito
parent f9d0a7f1f3
commit 2d755c46ca
31 changed files with 819 additions and 713 deletions

View File

@ -3,6 +3,6 @@
from .boolean import boolean_detail, boolean_detail_action, boolean_tooltip
from .objclass import objclass_detail, objclass_detail_action, objclass_tooltip
from .role import role_detail, role_detail_action, role_tooltip
from .typeattr import typeattr_detail, typeattr_tooltip
from .typeattr import (typeattr_detail, typeattr_detail_action, typeattr_tooltip)
from .type import (type_detail, type_or_attr_detail, type_detail_action,
type_or_attr_detail_action, type_tooltip, type_or_attr_tooltip)

View File

@ -49,4 +49,4 @@ def role_tooltip(role: "Role") -> str:
return f"{role} is a role associated with {n_types} types."
else:
return f"{role} is a role associated with types: " \
f"{', '.join(t.name for t in role.expand())}"
f"{', '.join(t.name for t in role.types())}"

View File

@ -30,6 +30,16 @@ def typeattr_detail(attr: "TypeAttribute", parent: "Optional[QtWidgets.QWidget]"
parent)
def typeattr_detail_action(attr: "TypeAttribute",
parent: QtWidgets.QWidget | None = None) -> QtWidgets.QAction:
"""Return a QAction that, when triggered, opens an detail popup for the attr."""
a = QtWidgets.QAction(f"Properties of {attr}")
a.triggered.connect(lambda _: typeattr_detail(attr, parent))
return a
def typeattr_tooltip(attr: "TypeAttribute") -> str:
"""Return tooltip text for this type attribute."""
n_types = len(attr)

View File

@ -5,8 +5,7 @@ from typing import TYPE_CHECKING
from PyQt5 import QtCore, QtGui, QtWidgets
import setools
from . import criteria, tab
from .models.mlsrule import MLSRuleTableModel
from . import criteria, models, tab
if TYPE_CHECKING:
from typing import Optional
@ -130,7 +129,7 @@ class MLSRuleQueryTab(tab.TableResultTabWidget):
self.criteria = (rt, src, dst, tclass, dflt)
# Set result table's model
self.table_results_model = MLSRuleTableModel(self.table_results)
self.table_results_model = models.MLSRuleTable(self.table_results)
if __name__ == '__main__':

View File

@ -0,0 +1,24 @@
# SPDX-License-Identifier: LGPL-2.1-only
from .boolean import BooleanList
from .bounds import BoundsTable
from .common import CommonTable
from .constraint import ConstraintTable
from .default import DefaultTable
from .fsuse import FSUseTable
from .genfscon import GenfsconTable
from .ibendportcon import IbendportconTable
from .ibpkeycon import IbpkeyconTable
from .initsid import InitialSIDTable
from .mls import MLSComponentTable
from .mlsrule import MLSRuleTable
from .netifcon import NetifconTable
from .nodecon import NodeconTable
from .objclass import ObjClassTable
from .portcon import PortconTable
from .rbacrule import RBACRuleTable
from .role import RoleTable
from .terule import TERuleTable
from .type import TypeTable
from .typeattr import TypeAttributeTable
from .user import UserTable

View File

@ -3,20 +3,16 @@
# SPDX-License-Identifier: LGPL-2.1-only
#
#
from typing import TYPE_CHECKING
from PyQt5 import QtCore, QtWidgets
from PyQt5 import QtCore
import setools
from . import modelroles
from .list import SEToolsListModel
from .table import SEToolsTableModel
from .. import details
if TYPE_CHECKING:
from setools import Boolean
class BooleanList(SEToolsListModel["Boolean"]):
class BooleanList(SEToolsListModel[setools.Boolean]):
"""List-based model for Booleans."""
@ -27,32 +23,35 @@ class BooleanList(SEToolsListModel["Boolean"]):
row = index.row()
item = self.item_list[row]
if role == modelroles.ContextMenuRole:
return (details.boolean_detail_action(item), )
elif role == QtCore.Qt.ItemDataRole.ToolTipRole:
return details.boolean_tooltip(item)
match role:
case modelroles.ContextMenuRole:
return (details.boolean_detail_action(item), )
case QtCore.Qt.ItemDataRole.ToolTipRole:
return details.boolean_tooltip(item)
return super().data(index, role)
class BooleanTableModel(SEToolsTableModel):
class BooleanTable(SEToolsTableModel):
"""Table-based model for booleans."""
headers = ["Name", "Default State"]
def data(self, index, role):
if self.item_list and index.isValid():
row = index.row()
col = index.column()
boolean = self.item_list[row]
def data(self, index: QtCore.QModelIndex, role: int = QtCore.Qt.ItemDataRole.DisplayRole):
if not self.item_list or not index.isValid():
return None
if role == QtCore.Qt.ItemDataRole.DisplayRole:
if col == 0:
return boolean.name
elif col == 1:
return str(boolean.state)
row = index.row()
col = index.column()
boolean = self.item_list[row]
elif role == QtCore.Qt.ItemDataRole.UserRole:
# get the whole rule for boolean boolean
return boolean
match role:
case QtCore.Qt.ItemDataRole.DisplayRole:
match col:
case 0:
return boolean.name
case 1:
return str(boolean.state)
return super().data(index, role)

View File

@ -3,30 +3,34 @@
# SPDX-License-Identifier: LGPL-2.1-only
#
#
from PyQt5.QtCore import Qt
from PyQt5 import QtCore
import setools
from .table import SEToolsTableModel
class BoundsTableModel(SEToolsTableModel):
class BoundsTable(SEToolsTableModel[setools.Bounds]):
"""Table-based model for *bounds."""
headers = ["Rule Type", "Parent", "Child"]
def data(self, index, role):
if self.item_list and index.isValid():
row = index.row()
col = index.column()
item = self.item_list[row]
def data(self, index: QtCore.QModelIndex, role: int = QtCore.Qt.ItemDataRole.DisplayRole):
if not self.item_list or not index.isValid():
return None
if role == Qt.ItemDataRole.DisplayRole:
if col == 0:
return item.ruletype.name
elif col == 1:
return item.parent.name
elif col == 2:
return item.child.name
row = index.row()
col = index.column()
item = self.item_list[row]
elif role == Qt.ItemDataRole.UserRole:
return item
match role:
case QtCore.Qt.ItemDataRole.DisplayRole:
match col:
case 0:
return item.ruletype.name
case 1:
return item.parent.name
case 2:
return item.child.name
return super().data(index, role)

View File

@ -3,50 +3,32 @@
# SPDX-License-Identifier: LGPL-2.1-only
#
#
from PyQt5.QtCore import Qt
from PyQt5.QtGui import QPalette, QTextCursor
from PyQt5 import QtCore
import setools
from setools.exception import NoCommon
from .details import DetailsPopup
from .table import SEToolsTableModel
def common_detail(parent, common):
"""
Create a dialog box for common perm set details.
Parameters:
parent The parent Qt Widget
class_ The type
"""
detail = DetailsPopup(parent, "Common detail: {0}".format(common))
detail.append_header("Permissions ({0}):".format(len(common.perms)))
for p in sorted(common.perms):
detail.append(" {0}".format(p))
detail.show()
class CommonTableModel(SEToolsTableModel):
class CommonTable(SEToolsTableModel[setools.Common]):
"""Table-based model for common permission sets."""
headers = ["Name", "Permissions"]
def data(self, index, role):
if self.item_list and index.isValid():
row = index.row()
col = index.column()
item = self.item_list[row]
def data(self, index: QtCore.QModelIndex, role: int = QtCore.Qt.ItemDataRole.DisplayRole):
if not self.item_list or not index.isValid():
return None
if role == Qt.ItemDataRole.DisplayRole:
if col == 0:
return item.name
elif col == 1:
return ", ".join(sorted(item.perms))
row = index.row()
col = index.column()
item = self.item_list[row]
elif role == Qt.ItemDataRole.UserRole:
return item
match role:
case QtCore.Qt.ItemDataRole.DisplayRole:
match col:
case 0:
return item.name
case 1:
return ", ".join(sorted(item.perms))
return super().data(index, role)

View File

@ -3,36 +3,40 @@
# SPDX-License-Identifier: LGPL-2.1-only
#
#
from PyQt5.QtCore import Qt
from setools.exception import ConstraintUseError
from PyQt5 import QtCore
import setools
from .table import SEToolsTableModel
class ConstraintTableModel(SEToolsTableModel):
class ConstraintTable(SEToolsTableModel[setools.Constraint]):
"""A table-based model for constraints."""
headers = ["Rule Type", "Class", "Permissions", "Expression"]
def data(self, index, role):
if self.item_list and index.isValid():
row = index.row()
col = index.column()
rule = self.item_list[row]
def data(self, index: QtCore.QModelIndex, role: int = QtCore.Qt.ItemDataRole.DisplayRole):
if not self.item_list or not index.isValid():
return None
if role == Qt.ItemDataRole.DisplayRole:
if col == 0:
return rule.ruletype.name
elif col == 1:
return rule.tclass.name
elif col == 2:
try:
return ", ".join(sorted(rule.perms))
except ConstraintUseError:
return None
elif col == 3:
return str(rule.expression)
row = index.row()
col = index.column()
rule = self.item_list[row]
elif role == Qt.ItemDataRole.UserRole:
return rule
match role:
case QtCore.Qt.ItemDataRole.DisplayRole:
match col:
case 0:
return rule.ruletype.name
case 1:
return rule.tclass.name
case 2:
if rule.ruletype in (setools.ConstraintRuletype.constrain,
setools.ConstraintRuletype.mlsconstrain):
return ", ".join(sorted(rule.perms))
else:
return None
case 3:
return str(rule.expression)
return super().data(index, role)

View File

@ -5,33 +5,38 @@
#
from contextlib import suppress
from PyQt5.QtCore import Qt
from PyQt5 import QtCore
import setools
from .table import SEToolsTableModel
class DefaultTableModel(SEToolsTableModel):
class DefaultTable(SEToolsTableModel[setools.Default]):
"""Table-based model for default_*."""
headers = ["Rule Type", "Class", "Default", "Default Range"]
def data(self, index, role):
if self.item_list and index.isValid():
row = index.row()
col = index.column()
item = self.item_list[row]
def data(self, index: QtCore.QModelIndex, role: int = QtCore.Qt.ItemDataRole.DisplayRole):
if not self.item_list or not index.isValid():
return None
if role == Qt.ItemDataRole.DisplayRole:
if col == 0:
return item.ruletype.name
elif col == 1:
return item.tclass.name
elif col == 2:
return item.default.name
elif col == 3:
with suppress(AttributeError):
return item.default_range.name
row = index.row()
col = index.column()
item = self.item_list[row]
elif role == Qt.ItemDataRole.UserRole:
return item
match role:
case QtCore.Qt.ItemDataRole.DisplayRole:
match col:
case 0:
return item.ruletype.name
case 1:
return item.tclass.name
case 2:
return item.default.name
case 3:
with suppress(AttributeError):
return item.default_range.name # type: ignore
return None
return super().data(index, role)

View File

@ -3,30 +3,34 @@
# SPDX-License-Identifier: LGPL-2.1-only
#
#
from PyQt5.QtCore import Qt
from PyQt5 import QtCore
import setools
from .table import SEToolsTableModel
class FSUseTableModel(SEToolsTableModel):
class FSUseTable(SEToolsTableModel[setools.FSUse]):
"""Table-based model for fs_use_*."""
headers = ["Ruletype", "FS Type", "Context"]
def data(self, index, role):
if self.item_list and index.isValid():
row = index.row()
col = index.column()
rule = self.item_list[row]
def data(self, index: QtCore.QModelIndex, role: int = QtCore.Qt.ItemDataRole.DisplayRole):
if not self.item_list or not index.isValid():
return None
if role == Qt.ItemDataRole.DisplayRole:
if col == 0:
return rule.ruletype.name
elif col == 1:
return rule.fs
elif col == 2:
return str(rule.context)
row = index.row()
col = index.column()
rule = self.item_list[row]
elif role == Qt.ItemDataRole.UserRole:
return rule
match role:
case QtCore.Qt.ItemDataRole.DisplayRole:
match col:
case 0:
return rule.ruletype.name
case 1:
return rule.fs
case 2:
return str(rule.context)
return super().data(index, role)

View File

@ -5,12 +5,13 @@
#
import stat
from PyQt5.QtCore import Qt
from PyQt5 import QtCore
import setools
from .table import SEToolsTableModel
class GenfsconTableModel(SEToolsTableModel):
class GenfsconTable(SEToolsTableModel[setools.Genfscon]):
"""Table-based model for genfscons."""
@ -26,21 +27,24 @@ class GenfsconTableModel(SEToolsTableModel):
stat.S_IFLNK: "Symbolic Link",
stat.S_IFSOCK: "Socket"}
def data(self, index, role):
if self.item_list and index.isValid():
row = index.row()
col = index.column()
rule = self.item_list[row]
def data(self, index: QtCore.QModelIndex, role: int = QtCore.Qt.ItemDataRole.DisplayRole):
if not self.item_list or not index.isValid():
return None
if role == Qt.ItemDataRole.DisplayRole:
if col == 0:
return rule.fs
elif col == 1:
return rule.path
elif col == 2:
return self._filetype_to_text[rule.filetype]
elif col == 3:
return str(rule.context)
row = index.row()
col = index.column()
rule = self.item_list[row]
elif role == Qt.ItemDataRole.UserRole:
return rule
match role:
case QtCore.Qt.ItemDataRole.DisplayRole:
match col:
case 0:
return rule.fs
case 1:
return rule.path
case 2:
return self._filetype_to_text[rule.filetype]
case 3:
return str(rule.context)
return super().data(index, role)

View File

@ -3,30 +3,34 @@
# SPDX-License-Identifier: LGPL-2.1-only
#
#
from PyQt5.QtCore import Qt
from PyQt5 import QtCore
import setools
from .table import SEToolsTableModel
class IbendportconTableModel(SEToolsTableModel):
class IbendportconTable(SEToolsTableModel[setools.Ibendportcon]):
"""Table-based model for ibendportcons."""
headers = ["Device", "Endport", "Context"]
def data(self, index, role):
if self.item_list and index.isValid():
row = index.row()
col = index.column()
rule = self.item_list[row]
def data(self, index: QtCore.QModelIndex, role: int = QtCore.Qt.ItemDataRole.DisplayRole):
if not self.item_list or not index.isValid():
return None
if role == Qt.ItemDataRole.DisplayRole:
if col == 0:
return rule.name
elif col == 1:
return str(rule.port)
elif col == 2:
return str(rule.context)
row = index.row()
col = index.column()
rule = self.item_list[row]
elif role == Qt.ItemDataRole.UserRole:
return rule
match role:
case QtCore.Qt.ItemDataRole.DisplayRole:
match col:
case 0:
return rule.name
case 1:
return str(rule.port)
case 2:
return str(rule.context)
return super().data(index, role)

View File

@ -3,34 +3,37 @@
# SPDX-License-Identifier: LGPL-2.1-only
#
#
from PyQt5.QtCore import Qt
from PyQt5 import QtCore
import setools
from .table import SEToolsTableModel
class IbpkeyconTableModel(SEToolsTableModel):
class IbpkeyconTable(SEToolsTableModel[setools.Ibpkeycon]):
"""Table-based model for ibpkeycons."""
headers = ["Subnet Prefix", "Partition Keys", "Context"]
def data(self, index, role):
if self.item_list and index.isValid():
row = index.row()
col = index.column()
rule = self.item_list[row]
def data(self, index: QtCore.QModelIndex, role: int = QtCore.Qt.ItemDataRole.DisplayRole):
if not self.item_list or not index.isValid():
return None
if role == Qt.ItemDataRole.DisplayRole:
if col == 0:
return str(rule.subnet_prefix)
elif col == 1:
low, high = rule.pkeys
if low == high:
return "{0:#x}".format(low)
else:
return "{0:#x}-{1:#x}".format(low, high)
elif col == 2:
return str(rule.context)
row = index.row()
col = index.column()
rule = self.item_list[row]
elif role == Qt.ItemDataRole.UserRole:
return rule
match role:
case QtCore.Qt.ItemDataRole.DisplayRole:
match col:
case 0:
return str(rule.subnet_prefix)
case 1:
low, high = rule.pkeys
if low == high:
return f"{low:#x}"
return f"{low:#x}-{high:#x}"
case 2:
return str(rule.context)
return super().data(index, role)

View File

@ -3,28 +3,32 @@
# SPDX-License-Identifier: LGPL-2.1-only
#
#
from PyQt5.QtCore import Qt
from PyQt5 import QtCore
import setools
from .table import SEToolsTableModel
class InitialSIDTableModel(SEToolsTableModel):
class InitialSIDTable(SEToolsTableModel[setools.InitialSID]):
"""Table-based model for initial SIDs."""
headers = ["SID", "Context"]
def data(self, index, role):
if self.item_list and index.isValid():
row = index.row()
col = index.column()
rule = self.item_list[row]
def data(self, index: QtCore.QModelIndex, role: int = QtCore.Qt.ItemDataRole.DisplayRole):
if not self.item_list or not index.isValid():
return None
if role == Qt.ItemDataRole.DisplayRole:
if col == 0:
return rule.name
elif col == 1:
return str(rule.context)
row = index.row()
col = index.column()
rule = self.item_list[row]
elif role == Qt.ItemDataRole.UserRole:
return rule
match role:
case QtCore.Qt.ItemDataRole.DisplayRole:
match col:
case 0:
return rule.name
case 1:
return str(rule.context)
return super().data(index, role)

View File

@ -14,6 +14,7 @@ from .typing import MetaclassFix
T = typing.TypeVar("T")
# pylint: disable=invalid-metaclass
class SEToolsListModel(QtCore.QAbstractListModel, typing.Generic[T], metaclass=MetaclassFix):
"""

View File

@ -3,71 +3,31 @@
# SPDX-License-Identifier: LGPL-2.1-only
#
#
from PyQt5.QtCore import Qt
from PyQt5.QtGui import QPalette, QTextCursor
from PyQt5 import QtCore
from .details import DetailsPopup
from .table import SEToolsTableModel
def _mls_detail(parent, obj, objtype):
"""
Create a dialog box for category or sensitivity details.
Parameters:
parent The parent Qt Widget
type_ The type
"""
detail = DetailsPopup(parent, "{0} detail: {1}".format(objtype, obj))
aliases = sorted(obj.aliases())
detail.append_header("Aliases ({0}):".format(len(aliases)))
for a in aliases:
detail.append(" {0}".format(a))
detail.show()
def category_detail(parent, obj):
"""
Create a dialog box for category details.
Parameters:
parent The parent Qt Widget
type_ The type
"""
_mls_detail(parent, obj, "Category")
def sensitivity_detail(parent, obj):
"""
Create a dialog box for sensitivity details.
Parameters:
parent The parent Qt Widget
type_ The type
"""
_mls_detail(parent, obj, "Sensitivity")
class MLSComponentTableModel(SEToolsTableModel):
class MLSComponentTable(SEToolsTableModel):
"""Table-based model for sensitivities and categories."""
headers = ["Name", "Aliases"]
def data(self, index, role):
if self.item_list and index.isValid():
row = index.row()
col = index.column()
item = self.item_list[row]
def data(self, index: QtCore.QModelIndex, role: int = QtCore.Qt.ItemDataRole.DisplayRole):
if not self.item_list or not index.isValid():
return None
if role == Qt.ItemDataRole.DisplayRole:
if col == 0:
return item.name
elif col == 1:
return ", ".join(sorted(a for a in item.aliases()))
row = index.row()
col = index.column()
item = self.item_list[row]
elif role == Qt.ItemDataRole.UserRole:
return item
match role:
case QtCore.Qt.ItemDataRole.DisplayRole:
match col:
case 0:
return item.name
case 1:
return ", ".join(sorted(a for a in item.aliases()))
return super().data(index, role)

View File

@ -3,15 +3,15 @@
# SPDX-License-Identifier: LGPL-2.1-only
#
#
from PyQt5 import QtCore, QtWidgets
from setools import MLSRuletype
from PyQt5 import QtCore
import setools
from . import modelroles
from .table import SEToolsTableModel
from .. import details
class MLSRuleTableModel(SEToolsTableModel):
class MLSRuleTable(SEToolsTableModel[setools.MLSRule]):
"""A table-based model for MLS rules."""
@ -25,66 +25,75 @@ class MLSRuleTableModel(SEToolsTableModel):
col = index.column()
rule = self.item_list[row]
if role == QtCore.Qt.ItemDataRole.DisplayRole:
if col == 0:
return rule.ruletype.name
elif col == 1:
return rule.source.name
elif col == 2:
return rule.target.name
elif col == 3:
return rule.tclass.name
elif col == 4:
return str(rule.default)
match role:
case QtCore.Qt.ItemDataRole.DisplayRole:
match col:
case 0:
return rule.ruletype.name
case 1:
return rule.source.name
case 2:
return rule.target.name
case 3:
return rule.tclass.name
case 4:
return str(rule.default)
elif role == modelroles.ContextMenuRole:
if col == 1:
return (details.type_or_attr_detail_action(rule.source), )
elif col == 2:
return (details.type_or_attr_detail_action(rule.target), )
elif col == 3:
return (details.objclass_detail_action(rule.tclass), )
case modelroles.ContextMenuRole:
match col:
case 1:
return (details.type_or_attr_detail_action(rule.source), )
case 2:
return (details.type_or_attr_detail_action(rule.target), )
case 3:
return (details.objclass_detail_action(rule.tclass), )
return ()
case QtCore.Qt.ItemDataRole.ToolTipRole:
match col:
case 1:
return details.type_or_attr_tooltip(rule.source)
case 2:
return details.type_or_attr_tooltip(rule.target)
case 3:
return details.objclass_tooltip(rule.tclass)
elif role == QtCore.Qt.ItemDataRole.ToolTipRole:
if col in (1, 2):
if col == 1:
return details.type_or_attr_tooltip(rule.source)
else:
return details.type_or_attr_tooltip(rule.target)
elif col == 3:
return details.objclass_tooltip(rule.tclass)
case QtCore.Qt.ItemDataRole.WhatsThisRole:
match col:
case 0:
column_whatsthis = \
f"""
<p>The Rule Type column is the type of the rule; it is one of:</p>
<ul>
{"".join(f"<li>{t.name}</li>" for t in setools.MLSRuletype)}
</ul>
"""
case 1:
column_whatsthis = \
"""
<p>This is the source type or type attribute (subject) in the rule.</p>
"""
case 2:
column_whatsthis = \
"""
<p>This is the target type or type attribute (object) in the rule.</p>
"""
case 3:
column_whatsthis = "<p>This is the object class of the rule.</p>"
case 4:
column_whatsthis = \
"""
<p>Default Range: This the the default range specified in the rule.</p>
"""
case _:
column_whatsthis = ""
return None
elif role == QtCore.Qt.ItemDataRole.WhatsThisRole:
if col == 0:
column_whatsthis = \
return \
f"""
<p>The Rule Type column is the type of the rule; it is one of:</p>
<ul>
{"".join(f"<li>{t.name}</li>" for t in MLSRuletype)}
</ul>
<b><p>Table Representation of Multi-Level Security Rules</p></b>
<p>Each part of the rule is represented as a column in the table.</p>
{column_whatsthis}
"""
elif col == 1:
column_whatsthis = \
"<p>This is the source type or type attribute (subject) in the rule.</p>"
elif col == 2:
column_whatsthis = \
"<p>This is the target type or type attribute (object) in the rule.</p>"
elif col == 3:
column_whatsthis = "<p>This is the object class of the rule.</p>"
elif col == 4:
column_whatsthis = \
"""<p>Default Range: This the the default range specified in the rule.</p>"""
return \
f"""
<b><p>Table Representation of Multi-Level Security Rules</p></b>
<p>Each part of the rule is represented as a column in the table.</p>
{column_whatsthis}
"""
return super().data(index, role)

View File

@ -3,30 +3,34 @@
# SPDX-License-Identifier: LGPL-2.1-only
#
#
from PyQt5.QtCore import Qt
from PyQt5 import QtCore
import setools
from .table import SEToolsTableModel
class NetifconTableModel(SEToolsTableModel):
class NetifconTable(SEToolsTableModel[setools.Netifcon]):
"""Table-based model for netifcons."""
headers = ["Device", "Device Context", "Packet Context"]
def data(self, index, role):
if self.item_list and index.isValid():
row = index.row()
col = index.column()
rule = self.item_list[row]
def data(self, index: QtCore.QModelIndex, role: int = QtCore.Qt.ItemDataRole.DisplayRole):
if not self.item_list or not index.isValid():
return None
if role == Qt.ItemDataRole.DisplayRole:
if col == 0:
return rule.netif
elif col == 1:
return str(rule.context)
elif col == 2:
return str(rule.packet)
row = index.row()
col = index.column()
rule = self.item_list[row]
elif role == Qt.ItemDataRole.UserRole:
return rule
match role:
case QtCore.Qt.ItemDataRole.DisplayRole:
match col:
case 0:
return rule.netif
case 1:
return str(rule.context)
case 2:
return str(rule.packet)
return super().data(index, role)

View File

@ -3,28 +3,32 @@
# SPDX-License-Identifier: LGPL-2.1-only
#
#
from PyQt5.QtCore import Qt
from PyQt5 import QtCore
import setools
from .table import SEToolsTableModel
class NodeconTableModel(SEToolsTableModel):
class NodeconTable(SEToolsTableModel[setools.Nodecon]):
"""Table-based model for nodecons."""
headers = ["Network", "Context"]
def data(self, index, role):
if self.item_list and index.isValid():
row = index.row()
col = index.column()
rule = self.item_list[row]
def data(self, index: QtCore.QModelIndex, role: int = QtCore.Qt.ItemDataRole.DisplayRole):
if not self.item_list or not index.isValid():
return None
if role == Qt.ItemDataRole.DisplayRole:
if col == 0:
return str(rule.network.with_netmask)
elif col == 1:
return str(rule.context)
row = index.row()
col = index.column()
rule = self.item_list[row]
elif role == Qt.ItemDataRole.UserRole:
return rule
match role:
case QtCore.Qt.ItemDataRole.DisplayRole:
match col:
case 0:
return str(rule.network.with_netmask)
case 1:
return str(rule.context)
return super().data(index, role)

View File

@ -4,21 +4,17 @@
#
#
from itertools import chain
from typing import TYPE_CHECKING
from PyQt5 import QtCore, QtWidgets
from setools.exception import NoCommon
from PyQt5 import QtCore
import setools
from . import modelroles
from .list import SEToolsListModel
from .table import SEToolsTableModel
from .. import details
if TYPE_CHECKING:
from setools import ObjClass
class ObjClassList(SEToolsListModel["ObjClass"]):
class ObjClassList(SEToolsListModel[setools.ObjClass]):
"""List-based model for object classes."""
@ -29,36 +25,39 @@ class ObjClassList(SEToolsListModel["ObjClass"]):
row = index.row()
item = self.item_list[row]
if role == modelroles.ContextMenuRole:
return (details.objclass_detail_action(item), )
elif role == QtCore.Qt.ItemDataRole.ToolTipRole:
return details.objclass_tooltip(item)
match role:
case modelroles.ContextMenuRole:
return (details.objclass_detail_action(item), )
case QtCore.Qt.ItemDataRole.ToolTipRole:
return details.objclass_tooltip(item)
return super().data(index, role)
class ObjClassTableModel(SEToolsTableModel["ObjClass"]):
class ObjClassTable(SEToolsTableModel[setools.ObjClass]):
"""Table-based model for object classes."""
headers = ["Name", "Permissions"]
def data(self, index, role):
if self.item_list and index.isValid():
row = index.row()
col = index.column()
item = self.item_list[row]
def data(self, index: QtCore.QModelIndex, role: int = QtCore.Qt.ItemDataRole.DisplayRole):
if not self.item_list or not index.isValid():
return None
if role == QtCore.Qt.ItemDataRole.DisplayRole:
if col == 0:
return item.name
elif col == 1:
try:
com_perms = item.common.perms
except NoCommon:
com_perms = []
row = index.row()
col = index.column()
item = self.item_list[row]
return ", ".join(sorted(chain(com_perms, item.perms)))
match role:
case QtCore.Qt.ItemDataRole.DisplayRole:
match col:
case 0:
return item.name
case 1:
try:
return ", ".join(sorted(chain(item.common.perms, item.perms)))
except setools.exception.NoCommon:
return ", ".join(sorted(item.perms))
elif role == QtCore.Qt.ItemDataRole.UserRole:
return item
return super().data(index, role)

View File

@ -3,34 +3,37 @@
# SPDX-License-Identifier: LGPL-2.1-only
#
#
from PyQt5.QtCore import Qt
from PyQt5 import QtCore
import setools
from .table import SEToolsTableModel
class PortconTableModel(SEToolsTableModel):
class PortconTable(SEToolsTableModel[setools.Portcon]):
"""Table-based model for portcons."""
headers = ["Port/Port Range", "Protocol", "Context"]
def data(self, index, role):
if self.item_list and index.isValid():
row = index.row()
col = index.column()
rule = self.item_list[row]
def data(self, index: QtCore.QModelIndex, role: int = QtCore.Qt.ItemDataRole.DisplayRole):
if not self.item_list or not index.isValid():
return None
if role == Qt.ItemDataRole.DisplayRole:
if col == 0:
low, high = rule.ports
if low == high:
return str(low)
else:
return "{0}-{1}".format(low, high)
elif col == 1:
return rule.protocol.name
elif col == 2:
return str(rule.context)
row = index.row()
col = index.column()
rule = self.item_list[row]
elif role == Qt.ItemDataRole.UserRole:
return rule
match role:
case QtCore.Qt.ItemDataRole.DisplayRole:
match col:
case 0:
low, high = rule.ports
if low == high:
return str(low)
return f"{low}-{high}"
case 1:
return rule.protocol.name
case 2:
return str(rule.context)
return super().data(index, role)

View File

@ -3,16 +3,15 @@
# SPDX-License-Identifier: LGPL-2.1-only
#
#
from PyQt5 import QtCore, QtWidgets
from setools import AnyRBACRule, Role, Type
from setools.exception import RuleUseError
from PyQt5 import QtCore
import setools
from . import modelroles
from .table import SEToolsTableModel
from .. import details
class RBACRuleTableModel(SEToolsTableModel[AnyRBACRule]):
class RBACRuleTable(SEToolsTableModel[setools.AnyRBACRule]):
"""A table-based model for RBAC rules."""
@ -26,105 +25,97 @@ class RBACRuleTableModel(SEToolsTableModel[AnyRBACRule]):
col = index.column()
rule = self.item_list[row]
if role == QtCore.Qt.ItemDataRole.DisplayRole:
if col == 0:
return rule.ruletype.name
elif col == 1:
return rule.source.name
elif col == 2:
return rule.target.name
elif col == 3:
try:
return rule.tclass.name
except RuleUseError:
# role allow
return None
elif col == 4:
try:
return rule.default.name
except RuleUseError:
# role allow
return None
match role:
case QtCore.Qt.ItemDataRole.DisplayRole:
match col:
case 0:
return rule.ruletype.name
case 1:
return rule.source.name
case 2:
return rule.target.name
case 3:
if rule.ruletype == setools.RBACRuletype.role_transition:
return rule.tclass.name
case 4:
if rule.ruletype == setools.RBACRuletype.role_transition:
return rule.default.name
elif role == modelroles.ContextMenuRole:
if col in (1, 2, 4):
if col == 1:
obj = rule.source
elif col == 2:
obj = rule.target
else:
try:
obj = rule.default
except RuleUseError:
return ()
return None
if isinstance(obj, Role):
return (details.role_detail_action(obj), )
else:
return (details.type_or_attr_detail_action(obj), )
case modelroles.ContextMenuRole:
match col:
case 1:
return (details.role_detail_action(rule.source), )
case 2:
if rule.ruletype == setools.RBACRuletype.role_transition:
return (details.type_or_attr_detail_action(rule.target), )
return (details.role_detail_action(rule.target), )
case 3:
if rule.ruletype == setools.RBACRuletype.role_transition:
return (details.objclass_detail_action(rule.tclass), )
case 4:
if rule.ruletype == setools.RBACRuletype.role_transition:
return (details.role_detail_action(rule.default), )
elif col == 3:
try:
return (details.objclass_detail_action(rule.tclass), )
except RuleUseError:
pass
case QtCore.Qt.ItemDataRole.ToolTipRole:
match col:
case 1:
return details.role_tooltip(rule.source)
case 2:
if rule.ruletype == setools.RBACRuletype.role_transition:
return details.type_or_attr_tooltip(rule.target)
return details.role_tooltip(rule.target)
case 3:
return details.objclass_tooltip(rule.tclass)
case 4:
if rule.ruletype == setools.RBACRuletype.role_transition:
return details.role_tooltip(rule.default)
return ()
case QtCore.Qt.ItemDataRole.WhatsThisRole:
match col:
case 0:
column_whatsthis = f"<p>{rule.ruletype} is the type of the rule.</p>"
case 1:
column_whatsthis = \
f"<p>{rule.source} is the source role (subject) in the rule.</p>"
case 2:
if rule.ruletype == setools.RBACRuletype.role_transition:
column_whatsthis = \
f"""
<p>{rule.target} is the target type/attribute (object) in the rule.
</p>"""
else:
column_whatsthis = \
f"<p>{rule.target} is the target role (object) in the rule.</p>"
case 3:
if rule.ruletype == setools.RBACRuletype.role_transition:
column_whatsthis = \
f"<p>{rule.tclass} is the object class of the rule.</p>"
else:
column_whatsthis = \
f"""
<p>The object class column does not apply to {rule.ruletype} rules.
</p>"""
case 4:
if rule.ruletype == setools.RBACRuletype.role_transition:
column_whatsthis = \
f"<p>{rule.default} is the default role in the rule.<p>"
else:
column_whatsthis = \
f"""
<p>The default role column does not apply to {rule.ruletype} rules.
</p>"""
case _:
column_whatsthis = ""
elif role == QtCore.Qt.ItemDataRole.ToolTipRole:
if col in (1, 2):
if col == 1:
obj = rule.source
elif col == 2:
obj = rule.target
else:
try:
obj = rule.default
except RuleUseError:
return None
return \
f"""
<b><p>Table Representation of Role-based Access Control (RBAC) Rules</p></b>
if isinstance(obj, Role):
return details.role_tooltip(obj)
else:
return details.type_or_attr_tooltip(obj)
elif col == 3:
return details.objclass_tooltip(rule.tclass)
<p>Each part of the rule is represented as a column in the table.</p>
return None
elif role == QtCore.Qt.ItemDataRole.WhatsThisRole:
if col == 0:
column_whatsthis = f"<p>{rule.ruletype} is the type of the rule.</p>"
elif col == 1:
column_whatsthis = \
f"<p>{rule.source} is the source role (subject) in the rule.</p>"
elif col == 2:
if isinstance(rule.target, Role):
column_whatsthis = \
f"<p>{rule.target} is the target role (object) in the rule.</p>"
else:
column_whatsthis = \
f"<p>{rule.target} is the target type/attribute (object) in the rule.</p>"
elif col == 3:
try:
column_whatsthis = f"<p>{rule.tclass} is the object class of the rule.</p>"
except RuleUseError:
column_whatsthis = \
f"<p>The object class column does not apply to {rule.ruletype} rules.</p>"
elif col == 4:
try:
column_whatsthis = f"<p>{rule.default} is the default role in the rule.<p>"
except RuleUseError:
column_whatsthis = \
f"<p>The default role column does not apply to {rule.ruletype} rules.</p>"
return \
f"""
<b><p>Table Representation of Role-based Access Control (RBAC) Rules</p></b>
<p>Each part of the rule is represented as a column in the table.</p>
{column_whatsthis}
"""
{column_whatsthis}
"""
return super().data(index, role)

View File

@ -3,34 +3,60 @@
# SPDX-License-Identifier: LGPL-2.1-only
#
#
from PyQt5.QtCore import Qt
from PyQt5.QtGui import QPalette, QTextCursor
from setools.exception import MLSDisabled
from PyQt5 import QtCore
import setools
from .. import details
from . import modelroles
from .table import SEToolsTableModel
class RoleTableModel(SEToolsTableModel):
class RoleTable(SEToolsTableModel[setools.Role]):
"""Table-based model for roles."""
headers = ["Name", "Types"]
def data(self, index, role):
def data(self, index: QtCore.QModelIndex, role: int = QtCore.Qt.ItemDataRole.DisplayRole):
if not self.item_list or not index.isValid():
return None
# There are two roles here.
# The parameter, role, is the Qt role
# The below item is a role in the list.
if self.item_list and index.isValid():
row = index.row()
col = index.column()
item = self.item_list[row]
row = index.row()
col = index.column()
item = self.item_list[row]
if role == Qt.ItemDataRole.DisplayRole:
if col == 0:
return item.name
elif col == 1:
return ", ".join(sorted(t.name for t in item.types()))
elif role == Qt.ItemDataRole.UserRole:
# get the whole object
return item
match role:
case QtCore.Qt.ItemDataRole.DisplayRole:
match col:
case 0:
return item.name
case 1:
return ", ".join(sorted(t.name for t in item.types()))
case modelroles.ContextMenuRole:
if col == 1:
return (details.type_detail_action(t) for t in sorted(item.types()))
case QtCore.Qt.ItemDataRole.WhatsThisRole:
match col:
case 0:
column_whatsthis = "<p>This is the name of the role.</p>"
case 1:
column_whatsthis = \
"<p>This is the list of types associated with this role.</p>"
case _:
column_whatsthis = ""
return \
f"""
<b><p>Table Representation of Roles</p></b>
<p>Each part of the declaration is represented as a column in the table.</p>
{column_whatsthis}
"""
return super().data(index, role)

View File

@ -14,6 +14,7 @@ from .typing import MetaclassFix
T = typing.TypeVar("T")
# pylint: disable=invalid-metaclass
class SEToolsTableModel(QtCore.QAbstractTableModel, typing.Generic[T], metaclass=MetaclassFix):
"""Base class for SETools table models, modeling a list in a tabular form."""

View File

@ -5,8 +5,8 @@
#
from contextlib import suppress
from PyQt5 import QtCore, QtWidgets
from setools import AnyTERule, TERuletype, TypeAttribute
from PyQt5 import QtCore
import setools
from setools.exception import RuleNotConditional, RuleUseError
from . import modelroles
@ -14,7 +14,7 @@ from .table import SEToolsTableModel
from .. import details
class TERuleTableModel(SEToolsTableModel[AnyTERule]):
class TERuleTable(SEToolsTableModel[setools.AnyTERule]):
"""A table-based model for TE rules."""
@ -29,107 +29,114 @@ class TERuleTableModel(SEToolsTableModel[AnyTERule]):
col = index.column()
rule = self.item_list[row]
if role == QtCore.Qt.ItemDataRole.DisplayRole:
if col == 0:
return rule.ruletype.name
elif col == 1:
return rule.source.name
elif col == 2:
return rule.target.name
elif col == 3:
return rule.tclass.name
elif col == 4:
try:
if rule.extended:
return f"{rule.xperm_type}: {rule.perms:,}" # type: ignore
else:
return ", ".join(sorted(rule.perms)) # type: ignore
except RuleUseError:
return rule.default.name # type: ignore
elif col == 5:
with suppress(RuleNotConditional):
return str(rule.conditional)
elif col == 6:
with suppress(RuleNotConditional):
return str(rule.conditional_block)
match role:
case QtCore.Qt.ItemDataRole.DisplayRole:
match col:
case 0:
return rule.ruletype.name
case 1:
return rule.source.name
case 2:
return rule.target.name
case 3:
return rule.tclass.name
case 4:
try:
if rule.extended:
return f"{rule.xperm_type}: {rule.perms:,}" # type: ignore
else:
return ", ".join(sorted(rule.perms)) # type: ignore
except RuleUseError:
return rule.default.name # type: ignore
case 5:
with suppress(RuleNotConditional):
return str(rule.conditional)
case 6:
with suppress(RuleNotConditional):
return str(rule.conditional_block)
return None
return None
elif role == modelroles.ContextMenuRole:
if col == 1:
return (details.type_or_attr_detail_action(rule.source), )
elif col == 2:
return (details.type_or_attr_detail_action(rule.target), )
elif col == 3:
return (details.objclass_detail_action(rule.tclass), )
elif col == 4:
with suppress(RuleUseError):
return (details.type_detail_action(rule.default), )
case modelroles.ContextMenuRole:
match col:
case 1:
return (details.type_or_attr_detail_action(rule.source), )
case 2:
return (details.type_or_attr_detail_action(rule.target), )
case 3:
return (details.objclass_detail_action(rule.tclass), )
case 4:
with suppress(RuleUseError):
return (details.type_detail_action(rule.default), )
return ()
case QtCore.Qt.ItemDataRole.ToolTipRole:
match col:
case 1:
return details.type_or_attr_tooltip(rule.source)
case 2:
return details.type_or_attr_tooltip(rule.target)
case 3:
return details.objclass_tooltip(rule.tclass)
elif role == QtCore.Qt.ItemDataRole.ToolTipRole:
if col in (1, 2):
if col == 1:
return details.type_or_attr_tooltip(rule.source)
else:
return details.type_or_attr_tooltip(rule.target)
elif col == 3:
return details.objclass_tooltip(rule.tclass)
case QtCore.Qt.ItemDataRole.WhatsThisRole:
match col:
case 0:
column_whatsthis = \
f"""
<p>The Rule Type column is the type of the rule; it is one of:</p>
<ul>
{"".join(f"<li>{t.name}</li>" for t in setools.TERuletype)}
</ul>
"""
case 1:
column_whatsthis = \
"""
<p>This is the source type or type attribute (subject) in the rule.</p>
"""
case 2:
column_whatsthis = \
"""
<p>This is the target type or type attribute (object) in the rule.</p>
"""
case 3:
column_whatsthis = "<p>This is the object class of the rule.</p>"
case 4:
column_whatsthis = \
"""
<p>Permissions/Default Type: The value of this depends on the rule
type:</p>
<ul>
<li>Allow and allow-like rules: These are the permissions set in the
rule.</li>
<li>type_* rules: This the the default type specified in the rule.</li>
</ul>
</li>
"""
case 5:
column_whatsthis = \
"""
<p>This is the conditional expression that enables/disables
this rule. If this is blank, the rule is unconditional.</p>
"""
case 6:
column_whatsthis = \
"""
<p>This contains the conditional branch that that rule resides in.
"True" means the rule is enabled when the conditional expression is
true; also known as the "if" block. "False" means the rule is enabled
when the conditional expression is false; also known as the "else"
block. If this is blank, the rule is unconditional.</p>
"""
case _:
column_whatsthis = ""
return None
elif role == QtCore.Qt.ItemDataRole.WhatsThisRole:
if col == 0:
column_whatsthis = \
return \
f"""
<p>The Rule Type column is the type of the rule; it is one of:</p>
<ul>
{"".join(f"<li>{t.name}</li>" for t in TERuletype)}
</ul>
"""
elif col == 1:
column_whatsthis = \
"<p>This is the source type or type attribute (subject) in the rule.</p>"
elif col == 2:
column_whatsthis = \
"<p>This is the target type or type attribute (object) in the rule.</p>"
elif col == 3:
column_whatsthis = "<p>This is the object class of the rule.</p>"
elif col == 4:
column_whatsthis = \
"""
<p>Permissions/Default Type: The value of this depends on the rule type:</p>
<ul>
<li>Allow and allow-like rules: These are the permissions set in the rule.
</li>
<li>type_* rules: This the the default type specified in the rule.</li>
</ul>
</li>
"""
elif col == 5:
column_whatsthis = \
"""
<p>This is the conditional expression that enables/disables
this rule. If this is blank, the rule is unconditional.</p>
"""
elif col == 6:
column_whatsthis = \
"""
<p>This contains the conditional branch that that rule resides in.
"True" means the rule is enabled when the conditional expression is true;
also known as the "if" block. "False" means the rule is enabled when the
conditional expression is false; also known as the "else" block. If this
is blank, the rule is unconditional.</p>
"""
<b><p>Table Representation of Type Enforcement Rules</p></b>
return \
f"""
<b><p>Table Representation of Type Enforcement Rules</p></b>
<p>Each part of the rule is represented as a column in the table.</p>
<p>Each part of the rule is represented as a column in the table.</p>
{column_whatsthis}
"""
{column_whatsthis}
"""
return super().data(index, role)

View File

@ -3,32 +3,67 @@
# SPDX-License-Identifier: LGPL-2.1-only
#
#
from PyQt5.QtCore import Qt
from PyQt5 import QtCore
import setools
from .. import details
from . import modelroles
from .table import SEToolsTableModel
class TypeTableModel(SEToolsTableModel):
class TypeTable(SEToolsTableModel[setools.Type]):
"""Table-based model for types."""
headers = ["Name", "Attributes", "Aliases", "Permissive"]
def data(self, index, role):
if self.item_list and index.isValid():
row = index.row()
col = index.column()
item = self.item_list[row]
def data(self, index: QtCore.QModelIndex, role: int = QtCore.Qt.ItemDataRole.DisplayRole):
if not self.item_list or not index.isValid():
return None
if role == Qt.ItemDataRole.DisplayRole:
if col == 0:
return item.name
elif col == 1:
return ", ".join(sorted(a.name for a in item.attributes()))
elif col == 2:
return ", ".join(sorted(a for a in item.aliases()))
elif col == 3 and item.ispermissive:
return "Permissive"
row = index.row()
col = index.column()
item = self.item_list[row]
elif role == Qt.ItemDataRole.UserRole:
return item
match role:
case QtCore.Qt.ItemDataRole.DisplayRole:
match col:
case 0:
return item.name
case 1:
return ", ".join(sorted(a.name for a in item.attributes()))
case 2:
return ", ".join(sorted(a for a in item.aliases()))
case 3:
return "Permissive" if item.ispermissive else None
case modelroles.ContextMenuRole:
if col == 1:
return (details.typeattr_detail_action(ta) for ta in sorted(item.attributes()))
case QtCore.Qt.ItemDataRole.WhatsThisRole:
match col:
case 0:
column_whatsthis = "<p>This is the name of the type.</p>"
case 1:
column_whatsthis = \
"<p>This is the list of attributes this type belongs to.</p>"
case 2:
column_whatsthis = \
"<p>This is the list of alias names for this type.</p>"
case 3:
column_whatsthis = \
"<p>This indicates whether the type is permissive.</p>"
case _:
column_whatsthis = ""
return \
f"""
<b><p>Table Representation of SELinux Types</p></b>
<p>Each part of the declaration is represented as a column in the table.</p>
{column_whatsthis}
"""
return super().data(index, role)

View File

@ -3,31 +3,57 @@
# SPDX-License-Identifier: LGPL-2.1-only
#
#
from PyQt5.QtCore import Qt
from PyQt5.QtGui import QPalette, QTextCursor
from setools.exception import MLSDisabled
from PyQt5 import QtCore
import setools
from .. import details
from . import modelroles
from .table import SEToolsTableModel
class TypeAttributeTableModel(SEToolsTableModel):
class TypeAttributeTable(SEToolsTableModel[setools.TypeAttribute]):
"""Table-based model for roles."""
headers = ["Name", "Types"]
def data(self, index, role):
if self.item_list and index.isValid():
row = index.row()
col = index.column()
item = self.item_list[row]
def data(self, index: QtCore.QModelIndex, role: int = QtCore.Qt.ItemDataRole.DisplayRole):
if not self.item_list or not index.isValid():
return None
if role == Qt.ItemDataRole.DisplayRole:
if col == 0:
return item.name
elif col == 1:
return ", ".join(sorted(t.name for t in item.expand()))
row = index.row()
col = index.column()
attr = self.item_list[row]
elif role == Qt.ItemDataRole.UserRole:
return item
match role:
case QtCore.Qt.ItemDataRole.DisplayRole:
match col:
case 0:
return attr.name
case 1:
return ", ".join(sorted(a.name for a in sorted(attr.expand())))
case modelroles.ContextMenuRole:
if col == 1:
return (details.type_detail_action(t) for t in sorted(attr.expand()))
case QtCore.Qt.ItemDataRole.WhatsThisRole:
match col:
case 0:
column_whatsthis = "<p>This is the name of the type attribute.</p>"
case 1:
column_whatsthis = \
"<p>This is the list of types associated with the attribute.</p>"
case _:
column_whatsthis = ""
return \
f"""
<b><p>Table Representation of SELinux users</p></b>
<p>Each part of the declaration is represented as a column in the table.</p>
{column_whatsthis}
"""
return super().data(index, role)

View File

@ -3,78 +3,74 @@
# SPDX-License-Identifier: LGPL-2.1-only
#
#
from PyQt5.QtCore import Qt, QModelIndex
from setools.exception import MLSDisabled
import typing
from .details import DetailsPopup
from PyQt5 import QtCore
import setools
from .. import details
from . import modelroles
from .table import SEToolsTableModel
def user_detail(parent, user):
"""
Create a dialog box for user details.
Parameters:
parent The parent Qt Widget
user The user
"""
detail = DetailsPopup(parent, "User detail: {0}".format(user))
roles = sorted(user.roles)
detail.append_header("Roles ({0}):".format(len(roles)))
for role in roles:
detail.append(" {0}".format(role))
try:
level = user.mls_level
range_ = user.mls_range
except MLSDisabled:
pass
else:
detail.append_header("\nDefault MLS Level:")
detail.append(" {0}".format(level))
detail.append_header("\nMLS Range:")
detail.append(" {0}".format(range_))
detail.show()
class UserTableModel(SEToolsTableModel):
class UserTable(SEToolsTableModel[setools.User]):
"""Table-based model for users."""
headers = ["Name", "Roles", "Default Level", "Range"]
def __init__(self, parent, mls):
super(UserTableModel, self).__init__(parent)
self.col_count = 4 if mls else 2
def __init__(self, mls: bool = False, parent: QtCore.QObject | None = None):
super().__init__(parent)
self.mls: typing.Final[bool] = mls
def columnCount(self, parent=QModelIndex()):
return self.col_count
def columnCount(self, parent=QtCore.QModelIndex()) -> int:
return 4 if self.mls else 2
def data(self, index, role):
if self.resultlist and index.isValid():
if role == Qt.ItemDataRole.DisplayRole:
row = index.row()
col = index.column()
user = self.item_list[row]
def data(self, index: QtCore.QModelIndex, role: int = QtCore.Qt.ItemDataRole.DisplayRole):
if not self.item_list or not index.isValid():
return None
if col == 0:
return user.name
elif col == 1:
return ", ".join(sorted(r.name for r in user.roles))
elif col == 2:
try:
row = index.row()
col = index.column()
user = self.item_list[row]
match role:
case QtCore.Qt.ItemDataRole.DisplayRole:
match col:
case 0:
return user.name
case 1:
return ", ".join(sorted(r.name for r in user.roles))
case 2:
return str(user.mls_level)
except MLSDisabled:
return None
elif col == 3:
try:
case 3:
return str(user.mls_range)
except MLSDisabled:
return None
elif role == Qt.ItemDataRole.UserRole:
return user
case modelroles.ContextMenuRole:
if col == 1:
return (details.role_detail_action(r) for r in sorted(user.roles))
case QtCore.Qt.ItemDataRole.WhatsThisRole:
match col:
case 0:
column_whatsthis = "<p>This is the name of the user.</p>"
case 1:
column_whatsthis = \
"<p>This is the list of roles associated with the user.</p>"
case 2:
column_whatsthis = "<p>This is the default MLS level of the user.</p>"
case 3:
column_whatsthis = "<p>This is allowed range for the user.</p>"
case _:
column_whatsthis = ""
return \
f"""
<b><p>Table Representation of SELinux users</p></b>
<p>Each part of the declaration is represented as a column in the table.</p>
{column_whatsthis}
"""
return super().data(index, role)

View File

@ -6,8 +6,7 @@ from typing import TYPE_CHECKING
from PyQt5 import QtCore, QtGui, QtWidgets
import setools
from . import criteria, tab
from .models.rbacrule import RBACRuleTableModel
from . import criteria, models, tab
if TYPE_CHECKING:
from typing import Optional
@ -118,7 +117,7 @@ class RBACRuleQueryTab(tab.TableResultTabWidget):
self.criteria = (rt, src, dst, tclass, dflt)
# Set result table's model
self.table_results_model = RBACRuleTableModel(self.table_results)
self.table_results_model = models.RBACRuleTable(self.table_results)
if __name__ == '__main__':

View File

@ -6,8 +6,7 @@ from typing import TYPE_CHECKING
from PyQt5 import QtCore, QtGui, QtWidgets
import setools
from . import criteria, tab
from .models.terule import TERuleTableModel
from . import criteria, models, tab
if TYPE_CHECKING:
from typing import Optional
@ -165,7 +164,7 @@ class TERuleQueryTab(tab.TableResultTabWidget):
self.criteria = (rt, src, dst, tclass, perms, dflt, bools)
# Set result table's model
self.table_results_model = TERuleTableModel(self.table_results)
self.table_results_model = models.TERuleTable(self.table_results)
# Connect signals
tclass.selectionChanged.connect(perms.set_classes)