diff --git a/tests/test_option_permissions.py b/tests/test_option_permissions.py new file mode 100644 index 0000000..a47398b --- /dev/null +++ b/tests/test_option_permissions.py @@ -0,0 +1,36 @@ +"configuration objects global API" +from .autopath import do_autopath +do_autopath() + +import pytest + +from tiramisu import PermissionsOption + + +def test_permissions(): + PermissionsOption('a', '', 640) + PermissionsOption('a', '', 642) + PermissionsOption('a', '', 751) + PermissionsOption('a', '', 753) + PermissionsOption('a', '', 7555) + PermissionsOption('a', '', 1755) + with pytest.raises(ValueError): + PermissionsOption('a', '', 800) + with pytest.raises(ValueError): + PermissionsOption('a', '', 75) + with pytest.raises(ValueError): + PermissionsOption('a', '', 77775) + with pytest.raises(ValueError): + PermissionsOption('a', '', '755') + with pytest.raises(ValueError): + PermissionsOption('a', '', 'string') + with pytest.raises(ValueError): + PermissionsOption('a', '', 800) + with pytest.raises(ValueError): + PermissionsOption('a', '', 1575) + with pytest.raises(ValueError): + PermissionsOption('a', '', 1557) + with pytest.raises(ValueError): + PermissionsOption('a', '', 777) + with pytest.raises(ValueError): + PermissionsOption('a', '', 1777) diff --git a/tiramisu/option/__init__.py b/tiramisu/option/__init__.py index 3c2fe2b..b55ce22 100644 --- a/tiramisu/option/__init__.py +++ b/tiramisu/option/__init__.py @@ -24,6 +24,7 @@ from .dateoption import DateOption from .filenameoption import FilenameOption from .passwordoption import PasswordOption from .macoption import MACOption +from .permissionsoption import PermissionsOption __all__ = ('Leadership', 'OptionDescription', 'DynOptionDescription', @@ -33,4 +34,4 @@ __all__ = ('Leadership', 'OptionDescription', 'DynOptionDescription', 'IPOption', 'PortOption', 'NetworkOption', 'NetmaskOption', 'BroadcastOption', 'DomainnameOption', 'EmailOption', 'URLOption', 'UsernameOption', 'GroupnameOption', 'FilenameOption', 'PasswordOption', 'submulti', - 'RegexpOption', 'MACOption') + 'RegexpOption', 'MACOption', 'PermissionsOption') diff --git a/tiramisu/option/permissionsoption.py b/tiramisu/option/permissionsoption.py new file mode 100644 index 0000000..5d07ae3 --- /dev/null +++ b/tiramisu/option/permissionsoption.py @@ -0,0 +1,75 @@ +# -*- coding: utf-8 -*- +# Copyright (C) 2023 Team tiramisu (see AUTHORS for all contributors) +# +# This program is free software: you can redistribute it and/or modify it +# under the terms of the GNU Lesser 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 Lesser General Public License for more +# details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with this program. If not, see . +# +# The original `Config` design model is unproudly borrowed from +# the rough pypy's guys: http://codespeak.net/svn/pypy/dist/pypy/config/ +# the whole pypy projet is under MIT licence +# ____________________________________________________________ +import re +import sys + +from ..setting import undefined, Undefined, OptionBag +from ..i18n import _ +from .option import Option +from .intoption import IntOption + + +class PermissionsOption(IntOption): + """Unix file permissions + Valid the representing Unix permissions is an octal (base-8) notation. + This notation consists of at least three digits (owner, group, and others). + If a fourth digit is present to the setuid bit, the setgid bit and the sticky bit attributes. + This option is an integer value. + """ + __slots__ = tuple() + perm_re = re.compile(r"^[0-7]{3,4}$") + _type = 'permissions' + _display_name = _('unix file permissions') + + def __init__(self, + *args, + **kwargs, + ) -> None: + #do not display intoption attributs + super().__init__(*args, + **kwargs) + + def validate(self, + value: str) -> None: + super().validate(value) + if not self.perm_re.search(str(value)): + raise ValueError(_('only 3 or 4 octal digits are allowed')) + + def second_level_validation(self, + value: str, + warnings_only: bool) -> None: + old_digit = 7 + str_value = str(value) + if len(str_value) == 4: + str_value = str_value[1:] + for idx, digit in enumerate(str_value): + new_digit = int(digit) + if old_digit < new_digit: + if idx == 1: + old = _('user') + new = _('group') + else: + old = _('group') + new = _('other') + raise ValueError(_(f'{new} has more right than {old}')) + old_digit = new_digit + if str_value == '777': + raise ValueError(_(f'too weak'))