From a60d029f394f45a3549f605a76f1638b1d828bd6 Mon Sep 17 00:00:00 2001 From: NaruX Date: Thu, 5 Apr 2018 15:51:51 +0200 Subject: [PATCH] AclManger angepasst, wenn zu leer hinzugef?gt wird AclManager springt bei IP Eingabe weiter und zur?ck IpAclManager ausgelagert in shared shared ?bernehmen (setup.py) Anzeigelevel angepasst Einstellungen werden ?bertragen, da RevPiPyLoad diese dynamisch verarbeitet Codestyle --- doc/aclmanager.html | 175 ++++---------- doc/index-revpipycontrol.shared.html | 20 ++ doc/index.html | 8 + doc/revpipycontrol.shared.ipaclmanager.html | 239 ++++++++++++++++++++ revpipycontrol.api | 25 +- revpipycontrol.e4p | 4 +- revpipycontrol/aclmanager.py | 230 +++++++++---------- revpipycontrol/revpicheckclient.py | 10 +- revpipycontrol/revpioption.py | 18 +- revpipycontrol/revpiprogram.py | 3 +- revpipycontrol/revpipycontrol.py | 3 +- revpipycontrol/shared/__init__.py | 1 + revpipycontrol/shared/ipaclmanager.py | 189 ++++++++++++++++ setup.py | 1 + 14 files changed, 639 insertions(+), 287 deletions(-) create mode 100644 doc/index-revpipycontrol.shared.html create mode 100644 doc/revpipycontrol.shared.ipaclmanager.html create mode 100644 revpipycontrol/shared/__init__.py create mode 100644 revpipycontrol/shared/ipaclmanager.py diff --git a/doc/aclmanager.html b/doc/aclmanager.html index 64d04c9..b765e24 100644 --- a/doc/aclmanager.html +++ b/doc/aclmanager.html @@ -18,9 +18,6 @@ Classes AclManager Hauptfenster des ACL-Managers. - -IpAclManager -Verwaltung fuer IP Adressen und deren ACL Level.

@@ -66,9 +63,15 @@ Methods

_changesdone Prüft ob sich die Einstellungen geändert haben. +_checkback +Springt bei Backspace in vorheriges Feld. + _checkclose Prüft ob Fenster beendet werden soll. +_checkdot +Prüft auf . + _clearfields Leert die Eingabefelder. @@ -149,6 +152,23 @@ Prüft ob sich die Einstellungen geändert haben.
True, wenn min. eine Einstellung geändert wurde
+ +

+AclManager._checkback

+_checkback(event, tkvar, pretxt) +

+Springt bei Backspace in vorheriges Feld. +

+
event
+
+TK Event +
tkvar
+
+TK Variable zum prüfen +
nexttxt
+
+Vorheriges IP Feld für Fokus +

AclManager._checkclose

@@ -160,6 +180,23 @@ Prüft ob Fenster beendet werden soll.
tkinter-Event
+ +

+AclManager._checkdot

+_checkdot(event, tkvar, nexttxt) +

+Prüft auf . und geht weiter. +

+
event
+
+TK Event +
tkvar
+
+TK Variable zum prüfen +
nexttxt
+
+Nächstes IP Feld für Fokus +

AclManager._clearfields

@@ -215,137 +252,5 @@ ACL als
Up
-

- -

IpAclManager

-

-Verwaltung fuer IP Adressen und deren ACL Level. -

-

-Derived from

-None -

-Class Attributes

- - -
acl
regex_acl
-

-Class Methods

- - -
None
-

-Methods

- - - - - - - - - - - - - - - - - - - - - - - -
IpAclManagerInit IpAclManager class.
__get_aclGetter fuer den rohen ACL-String.
__get_regex_aclGibt formatierten RegEx-String zurueck.
__iter__Gibt einzelne ACLs als aus.
__set_aclUebernimmt neue ACL-Liste fuer die Ausertung der Level.
get_acllevelPrueft IP gegen ACL List und gibt ACL-Wert aus.
loadaclLaed ACL String und gibt erfolg zurueck.
-

-Static Methods

- - -
None
- -

-IpAclManager (Constructor)

-IpAclManager(minlevel, maxlevel, acl=None) -

-Init IpAclManager class. -

-
minlevel
-
-Smallest access level (min. 0) -
maxlevel
-
-Biggest access level (max. 9) -
acl
-
-ACL Liste fuer Berechtigungen als -
-
-

-IpAclManager.__get_acl

-__get_acl() -

-Getter fuer den rohen ACL-String. - return ACLs als -

-

-IpAclManager.__get_regex_acl

-__get_regex_acl() -

-Gibt formatierten RegEx-String zurueck. - return RegEx Code als -

-

-IpAclManager.__iter__

-__iter__() -

-Gibt einzelne ACLs als aus. -

-

-IpAclManager.__set_acl

-__set_acl(value) -

-Uebernimmt neue ACL-Liste fuer die Ausertung der Level. -

-
value
-
-Neue ACL-Liste als -
-
-

-IpAclManager.get_acllevel

-get_acllevel(ipaddress) -

-Prueft IP gegen ACL List und gibt ACL-Wert aus. -

-
ipaddress
-
-zum pruefen -
-
-
Returns:
-
- ACL Wert oder -1 wenn nicht gefunden -
-
-

-IpAclManager.loadacl

-loadacl(str_acl) -

-Laed ACL String und gibt erfolg zurueck. -

-
str_acl
-
-ACL als -
-
-
Returns:
-
-True, wenn erfolgreich uebernommen -
-
-
Up

\ No newline at end of file diff --git a/doc/index-revpipycontrol.shared.html b/doc/index-revpipycontrol.shared.html new file mode 100644 index 0000000..00f7dd6 --- /dev/null +++ b/doc/index-revpipycontrol.shared.html @@ -0,0 +1,20 @@ + + +revpipycontrol.shared + + + +

+revpipycontrol.shared

+ + + +

+Modules

+ + + + + +
ipaclmanagerVerwaltet IP Adressen und deren ACLs.
+ \ No newline at end of file diff --git a/doc/index.html b/doc/index.html index aa29915..1a15819 100644 --- a/doc/index.html +++ b/doc/index.html @@ -8,6 +8,14 @@ Table of contents +

+Packages

+ + + + + +
shared

Modules

diff --git a/doc/revpipycontrol.shared.ipaclmanager.html b/doc/revpipycontrol.shared.ipaclmanager.html new file mode 100644 index 0000000..2c5cb69 --- /dev/null +++ b/doc/revpipycontrol.shared.ipaclmanager.html @@ -0,0 +1,239 @@ + + +revpipycontrol.shared.ipaclmanager + + + +

+revpipycontrol.shared.ipaclmanager

+

+Verwaltet IP Adressen und deren ACLs. +

+

+Global Attributes

+ + +
None
+

+Classes

+ + + + + +
IpAclManagerVerwaltung fuer IP Adressen und deren ACL Level.
+

+Functions

+ + + + + +
refullmatchre.fullmatch wegen alter python version aus wheezy nachgebaut.
+

+ +

IpAclManager

+

+Verwaltung fuer IP Adressen und deren ACL Level. +

+

+Derived from

+None +

+Class Attributes

+ + +
acl
filename
regex_acl
+

+Class Methods

+ + +
None
+

+Methods

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
IpAclManagerInit IpAclManager class.
__get_aclGetter fuer den rohen ACL-String.
__get_filenameGetter fuer Dateinamen.
__get_regex_aclGibt formatierten RegEx-String zurueck.
__iter__Gibt einzelne ACLs als aus.
__set_aclUebernimmt neue ACL-Liste fuer die Ausertung der Level.
get_acllevelPrueft IP gegen ACL List und gibt ACL-Wert aus.
loadaclLaed ACL String und gibt erfolg zurueck.
loadaclfileLaed ACL Definitionen aus Datei.
writeaclfileSchreibt ACL Definitionen in Datei.
+

+Static Methods

+ + +
None
+ +

+IpAclManager (Constructor)

+IpAclManager(minlevel, maxlevel, acl=None) +

+Init IpAclManager class. +

+
minlevel
+
+Smallest access level (min. 0) +
maxlevel
+
+Biggest access level (max. 9) +
acl
+
+ACL Liste fuer Berechtigungen als +
+
+

+IpAclManager.__get_acl

+__get_acl() +

+Getter fuer den rohen ACL-String. + return ACLs als +

+

+IpAclManager.__get_filename

+__get_filename() +

+Getter fuer Dateinamen. +

+
Returns:
+
+Filename der ACL +
+
+

+IpAclManager.__get_regex_acl

+__get_regex_acl() +

+Gibt formatierten RegEx-String zurueck. + return RegEx Code als +

+

+IpAclManager.__iter__

+__iter__() +

+Gibt einzelne ACLs als aus. +

+

+IpAclManager.__set_acl

+__set_acl(value) +

+Uebernimmt neue ACL-Liste fuer die Ausertung der Level. +

+
value
+
+Neue ACL-Liste als +
+
+

+IpAclManager.get_acllevel

+get_acllevel(ipaddress) +

+Prueft IP gegen ACL List und gibt ACL-Wert aus. +

+
ipaddress
+
+zum pruefen +
+
+
Returns:
+
+ ACL Wert oder -1 wenn nicht gefunden +
+
+

+IpAclManager.loadacl

+loadacl(str_acl) +

+Laed ACL String und gibt erfolg zurueck. +

+
str_acl
+
+ACL als +
+
+
Returns:
+
+True, wenn erfolgreich uebernommen +
+
+

+IpAclManager.loadaclfile

+loadaclfile(filename) +

+Laed ACL Definitionen aus Datei. +

+
filename
+
+Dateiname fuer Definitionen +
+
+
Returns:
+
+True, wenn Laden erfolgreich war +
+
+

+IpAclManager.writeaclfile

+writeaclfile(filename=None, aclname=None) +

+Schreibt ACL Definitionen in Datei. +

+
filename
+
+Dateiname fuer Definitionen +
+
+
Returns:
+
+True, wenn Schreiben erfolgreich war +
+
+
Up
+

+ +

refullmatch

+refullmatch(regex, string) +

+re.fullmatch wegen alter python version aus wheezy nachgebaut. +

+
regex
+
+RegEx Statement +
string
+
+Zeichenfolge gegen die getestet wird +
+
+
Returns:
+
+True, wenn komplett passt sonst False +
+
+
Up
+
+ \ No newline at end of file diff --git a/revpipycontrol.api b/revpipycontrol.api index 4ce4859..4822d28 100644 --- a/revpipycontrol.api +++ b/revpipycontrol.api @@ -2,7 +2,9 @@ aclmanager.AclManager.__get_acltext?6() aclmanager.AclManager.__set_acltext?6(value) aclmanager.AclManager._ask_delete?5() aclmanager.AclManager._changesdone?5() +aclmanager.AclManager._checkback?5(event, tkvar, pretxt) aclmanager.AclManager._checkclose?5(event=None) +aclmanager.AclManager._checkdot?5(event, tkvar, nexttxt) aclmanager.AclManager._clearfields?5() aclmanager.AclManager._createwidgets?5() aclmanager.AclManager._loadfields?5() @@ -15,15 +17,6 @@ aclmanager.AclManager.acltext?7 aclmanager.AclManager.get_acl?4() aclmanager.AclManager.root?7 aclmanager.AclManager?1(master, minlevel, maxlevel, acl_str="", readonly=False) -aclmanager.IpAclManager.__get_acl?6() -aclmanager.IpAclManager.__get_regex_acl?6() -aclmanager.IpAclManager.__iter__?6() -aclmanager.IpAclManager.__set_acl?6(value) -aclmanager.IpAclManager.acl?7 -aclmanager.IpAclManager.get_acllevel?4(ipaddress) -aclmanager.IpAclManager.loadacl?4(str_acl) -aclmanager.IpAclManager.regex_acl?7 -aclmanager.IpAclManager?1(minlevel, maxlevel, acl=None) aclmanager._?8 mytools.addroot?4(filename) mytools.gettrans?4(proglang=None) @@ -141,3 +134,17 @@ revpipycontrol.RevPiPyControl.visitwebsite?4() revpipycontrol.RevPiPyControl?1(master=None) revpipycontrol._?8 revpipycontrol.pycontrolversion?7 +revpipycontrol.shared.ipaclmanager.IpAclManager.__get_acl?6() +revpipycontrol.shared.ipaclmanager.IpAclManager.__get_filename?6() +revpipycontrol.shared.ipaclmanager.IpAclManager.__get_regex_acl?6() +revpipycontrol.shared.ipaclmanager.IpAclManager.__iter__?6() +revpipycontrol.shared.ipaclmanager.IpAclManager.__set_acl?6(value) +revpipycontrol.shared.ipaclmanager.IpAclManager.acl?7 +revpipycontrol.shared.ipaclmanager.IpAclManager.filename?7 +revpipycontrol.shared.ipaclmanager.IpAclManager.get_acllevel?4(ipaddress) +revpipycontrol.shared.ipaclmanager.IpAclManager.loadacl?4(str_acl) +revpipycontrol.shared.ipaclmanager.IpAclManager.loadaclfile?4(filename) +revpipycontrol.shared.ipaclmanager.IpAclManager.regex_acl?7 +revpipycontrol.shared.ipaclmanager.IpAclManager.writeaclfile?4(filename=None, aclname=None) +revpipycontrol.shared.ipaclmanager.IpAclManager?1(minlevel, maxlevel, acl=None) +revpipycontrol.shared.ipaclmanager.refullmatch?4(regex, string) diff --git a/revpipycontrol.e4p b/revpipycontrol.e4p index fa98f89..11cb786 100644 --- a/revpipycontrol.e4p +++ b/revpipycontrol.e4p @@ -1,7 +1,7 @@ - + en_US @@ -25,6 +25,8 @@ revpipycontrol/revpiinfo.py revpipycontrol/aclmanager.py revpipycontrol/revpilegacy.py + revpipycontrol/shared/ipaclmanager.py + revpipycontrol/shared/__init__.py diff --git a/revpipycontrol/aclmanager.py b/revpipycontrol/aclmanager.py index d773182..72e19b2 100644 --- a/revpipycontrol/aclmanager.py +++ b/revpipycontrol/aclmanager.py @@ -9,117 +9,13 @@ u"""Manager für ACL Einträge.""" import tkinter import tkinter.messagebox as tkmsg from mytools import gettrans -from re import fullmatch +from shared.ipaclmanager import IpAclManager from tkinter import ttk # Übersetzung laden _ = gettrans() -class IpAclManager(): - - """Verwaltung fuer IP Adressen und deren ACL Level.""" - - def __init__(self, minlevel, maxlevel, acl=None): - """Init IpAclManager class. - - @param minlevel Smallest access level (min. 0) - @param maxlevel Biggest access level (max. 9) - @param acl ACL Liste fuer Berechtigungen als - - """ - if type(minlevel) != int: - raise ValueError("parameter minlevel must be ") - if type(maxlevel) != int: - raise ValueError("parameter maxlevel must be ") - if minlevel < 0: - raise ValueError("minlevel must be 0 or more") - if maxlevel > 9: - raise ValueError("maxlevel maximum is 9") - if minlevel > maxlevel: - raise ValueError("minlevel is smaller than maxlevel") - - self.__dict_acl = {} - self.__dict_regex = {} - self.__dict_knownips = {} - self.__re_ipacl = "(([\\d\\*]{1,3}\\.){3}[\\d\\*]{1,3},[" \ - + str(minlevel) + "-" + str(maxlevel) + "] ?)*" - - # Liste erstellen, wenn übergeben - if acl is not None: - self.__set_acl(acl) - - def __iter__(self): - """Gibt einzelne ACLs als aus.""" - for aclip in sorted(self.__dict_acl): - yield (aclip, self.__dict_acl[aclip]) - - def __get_acl(self): - """Getter fuer den rohen ACL-String. - return ACLs als """ - str_acl = "" - for aclip in sorted(self.__dict_acl): - str_acl += "{},{} ".format(aclip, self.__dict_acl[aclip]) - return str_acl.strip() - - def __get_regex_acl(self): - """Gibt formatierten RegEx-String zurueck. - return RegEx Code als """ - return self.__re_ipacl - - def __set_acl(self, value): - """Uebernimmt neue ACL-Liste fuer die Ausertung der Level. - @param value Neue ACL-Liste als """ - if type(value) != str: - raise ValueError("parameter acl must be ") - - value = value.strip() - if fullmatch(self.__re_ipacl, value) is None: - raise ValueError("acl format ist not okay - 1.2.3.4,0 5.6.7.8,1") - - # Klassenwerte übernehmen - self.__dict_acl = {} - self.__dict_regex = {} - self.__dict_knownips = {} - - # Liste neu füllen mit regex Strings - for ip_level in value.split(): - ip, level = ip_level.split(",", 1) - self.__dict_acl[ip] = int(level) - self.__dict_regex[ip] = \ - ip.replace(".", "\\.").replace("*", "\\d{1,3}") - - def get_acllevel(self, ipaddress): - """Prueft IP gegen ACL List und gibt ACL-Wert aus. - @param ipaddress zum pruefen - @return ACL Wert oder -1 wenn nicht gefunden""" - # Bei bereits aufgelösten IPs direkt ACL auswerten - if ipaddress in self.__dict_knownips: - return self.__dict_knownips[ipaddress] - - for aclip in sorted(self.__dict_acl, reverse=True): - if fullmatch(self.__dict_regex[aclip], ipaddress) is not None: - # IP und Level merken - self.__dict_knownips[ipaddress] = self.__dict_acl[aclip] - - # Level zurückgeben - return self.__dict_acl[aclip] - - return -1 - - def loadacl(self, str_acl): - """Laed ACL String und gibt erfolg zurueck. - @param str_acl ACL als - @return True, wenn erfolgreich uebernommen""" - if fullmatch(self.__re_ipacl, str_acl) is None: - return False - self.__set_acl(str_acl) - return True - - acl = property(__get_acl, __set_acl) - regex_acl = property(__get_regex_acl) - - class AclManager(ttk.Frame): u"""Hauptfenster des ACL-Managers.""" @@ -258,22 +154,68 @@ class AclManager(ttk.Frame): self.var_ip4 = tkinter.StringVar(frame) self.var_acl = tkinter.StringVar(frame, self.minlevel) - ip_block = ttk.Entry(frame, width=4) - ip_block["state"] = self.__ro - ip_block["textvariable"] = self.var_ip1 - ip_block.grid(row=row, column=1) - ip_block = ttk.Entry(frame, width=4) - ip_block["state"] = self.__ro - ip_block["textvariable"] = self.var_ip2 - ip_block.grid(row=row, column=3) - ip_block = ttk.Entry(frame, width=4) - ip_block["state"] = self.__ro - ip_block["textvariable"] = self.var_ip3 - ip_block.grid(row=row, column=5) - ip_block = ttk.Entry(frame, width=4) - ip_block["state"] = self.__ro - ip_block["textvariable"] = self.var_ip4 - ip_block.grid(row=row, column=7) + ip_block1 = ttk.Entry(frame, width=4) + ip_block2 = ttk.Entry(frame, width=4) + ip_block3 = ttk.Entry(frame, width=4) + ip_block4 = ttk.Entry(frame, width=4) + + ip_block1.bind( + "", + lambda event, tkvar=self.var_ip1: self._checkdot( + event, tkvar, ip_block2 + ) + ) + ip_block1["state"] = self.__ro + ip_block1["textvariable"] = self.var_ip1 + ip_block1.grid(row=row, column=1) + + ip_block2.bind( + "", + lambda event, tkvar=self.var_ip2: self._checkdot( + event, tkvar, ip_block3 + ) + ) + ip_block2.bind( + "", + lambda event, tkvar=self.var_ip2: self._checkback( + event, tkvar, ip_block1 + ) + ) + ip_block2["state"] = self.__ro + ip_block2["textvariable"] = self.var_ip2 + ip_block2.grid(row=row, column=3) + + ip_block3.bind( + "", + lambda event, tkvar=self.var_ip3: self._checkdot( + event, tkvar, ip_block4 + ) + ) + ip_block3.bind( + "", + lambda event, tkvar=self.var_ip3: self._checkback( + event, tkvar, ip_block2 + ) + ) + ip_block3["state"] = self.__ro + ip_block3["textvariable"] = self.var_ip3 + ip_block3.grid(row=row, column=5) + + ip_block4.bind( + "", + lambda event, tkvar=self.var_ip4: self._checkdot( + event, tkvar, None + ) + ) + ip_block4.bind( + "", + lambda event, tkvar=self.var_ip4: self._checkback( + event, tkvar, ip_block3 + ) + ) + ip_block4["state"] = self.__ro + ip_block4["textvariable"] = self.var_ip4 + ip_block4.grid(row=row, column=7) # Punkte zwischen IP-Feldern for i in range(2, 7, 2): @@ -338,12 +280,44 @@ class AclManager(ttk.Frame): parent=self.master, default="no" ) if ask: - self.__acl.loadacl( - self.__acl.acl.replace( - "{},{}".format(*lst_ipacl), "" - ).replace(" ", " ") - ) - self._refreshacls() + new_acl = self.__acl.acl.replace( + "{},{}".format(*lst_ipacl), "" + ).replace(" ", " ") + + if self.__acl.loadacl(new_acl.strip()): + # Liste neu aufbauen + self._refreshacls() + else: + tkmsg.showerror( + _("Error"), + _("Can not delete ACL! Check format."), + parent=self.master + ) + + def _checkback(self, event, tkvar, pretxt): + u"""Springt bei Backspace in vorheriges Feld. + + @param event TK Event + @param tkvar TK Variable zum prüfen + @param nexttxt Vorheriges IP Feld für Fokus + + """ + if pretxt is not None and event.keycode == 22 and tkvar.get() == "": + pretxt.focus_set() + + def _checkdot(self, event, tkvar, nexttxt): + u"""Prüft auf . und geht weiter. + + @param event TK Event + @param tkvar TK Variable zum prüfen + @param nexttxt Nächstes IP Feld für Fokus + + """ + val = tkvar.get() + if val.find(".") >= 0: + tkvar.set(val[:-1]) + if nexttxt is not None: + nexttxt.focus_set() def _clearfields(self): u"""Leert die Eingabefelder.""" @@ -387,7 +361,7 @@ class AclManager(ttk.Frame): self.var_ip4.get(), self.var_acl.get() ) - if self.__acl.loadacl(self.__acl.acl + " " + new_acl): + if self.__acl.loadacl((self.__acl.acl + " " + new_acl).strip()): self._refreshacls() else: tkmsg.showerror( diff --git a/revpipycontrol/revpicheckclient.py b/revpipycontrol/revpicheckclient.py index 303ad18..f75b103 100644 --- a/revpipycontrol/revpicheckclient.py +++ b/revpipycontrol/revpicheckclient.py @@ -205,7 +205,7 @@ class RevPiCheckClient(tkinter.Frame): def _createwidgets(self): """Erstellt den Fensterinhalt.""" - cFxPxy53 = {"fill": "x", "padx": 5, "pady": 3} + cfxpxy53 = {"fill": "x", "padx": 5, "pady": 3} devgrp = tkinter.LabelFrame(self) devgrp["text"] = _("Devices of RevPi") @@ -236,7 +236,7 @@ class RevPiCheckClient(tkinter.Frame): btn = tkinter.Button(devgrp) btn["command"] = lambda win=win: self.__showwin(win) btn["text"] = "{} | {}".format(dev, self.dict_devices[dev]) - btn.pack(**cFxPxy53) + btn.pack(**cfxpxy53) # Steuerungsfunktionen cntgrp = tkinter.LabelFrame(self) @@ -246,19 +246,19 @@ class RevPiCheckClient(tkinter.Frame): self.btn_refresh = tkinter.Button(cntgrp) self.btn_refresh["text"] = _("Read all IOs") self.btn_refresh["command"] = self.refreshvalues - self.btn_refresh.pack(**cFxPxy53) + self.btn_refresh.pack(**cfxpxy53) self.btn_read = tkinter.Button(cntgrp) self.btn_read["text"] = _("Read just Inputs") self.btn_read["command"] = self.readvalues - self.btn_read.pack(**cFxPxy53) + self.btn_read.pack(**cfxpxy53) self.btn_write = tkinter.Button(cntgrp) self.btn_write["state"] = "normal" if self.xmlmode >= 3 \ else "disabled" self.btn_write["text"] = _("Write Outputs") self.btn_write["command"] = self.writevalues - self.btn_write.pack(**cFxPxy53) + self.btn_write.pack(**cfxpxy53) self.chk_auto = tkinter.Checkbutton(cntgrp) self.chk_auto["command"] = self.toggleauto diff --git a/revpipycontrol/revpioption.py b/revpipycontrol/revpioption.py index cb772e4..4d78532 100644 --- a/revpipycontrol/revpioption.py +++ b/revpipycontrol/revpioption.py @@ -293,14 +293,22 @@ class RevPiOption(tkinter.Frame): if not self._checkvalues(): return None - ask = tkmsg.askyesnocancel( +# ask = tkmsg.askyesnocancel( +# _("Question"), +# _("The settings are now saved on the Revolution Pi. \n\n" +# "Should the new settings take effect immediately? \nThis " +# "means a restart of the service and the PLC program!"), +# parent=self.master +# ) + ask = tkmsg.askokcancel( _("Question"), - _("The settings are now saved on the Revolution Pi. \n\n" - "Should the new settings take effect immediately? \nThis " - "means a restart of the service and the PLC program!"), + _("The settings will be set on the Revolution Pi now. \n\n" + "If you made changes on the 'PCL Program' section, your plc " + "program will restart! \n" + "ACL changes and service settings are applied immediately."), parent=self.master ) - if ask is not None: + if ask: self.dc["autoreload"] = int(self.var_reload.get()) self.dc["autoreloaddelay"] = int(self.var_reload_delay.get()) self.dc["autostart"] = int(self.var_start.get()) diff --git a/revpipycontrol/revpiprogram.py b/revpipycontrol/revpiprogram.py index d15ae4b..899fadf 100644 --- a/revpipycontrol/revpiprogram.py +++ b/revpipycontrol/revpiprogram.py @@ -51,8 +51,7 @@ class RevPiProgram(tkinter.Frame): self.uploaded = False self.revpi = revpi self.xmlcli = xmlcli - self.xmlmode = xmlmode - self.xmlstate = "normal" if xmlmode == 3 else "disabled" + self.xmlstate = "normal" if xmlmode >= 3 else "disabled" # Letzte Einstellungen übernehmen self.opt = self._loaddefault() diff --git a/revpipycontrol/revpipycontrol.py b/revpipycontrol/revpipycontrol.py index e20eb7b..cc6cea3 100755 --- a/revpipycontrol/revpipycontrol.py +++ b/revpipycontrol/revpipycontrol.py @@ -326,7 +326,6 @@ class RevPiPyControl(tkinter.Frame): win.grab_set() # Gegenstelle prüfen und passende Optionen laden - print(self.revpipyversion) if self.revpipyversion[0] == 0 and self.revpipyversion[1] < 6: self.tkoptions = \ revpilegacy.RevPiOption(win, self.cli) @@ -338,7 +337,7 @@ class RevPiPyControl(tkinter.Frame): if self.tkoptions.dc is not None and self.tkoptions.dorestart: # Wenn XML-Modus anders und Dienstneustart - if self.xmlmode != self.tkoptions.dc["xmlrpc"]: + if self.xmlmode != self.cli.xmlmodus(): self.serverdisconnect() self._opt_conn(self.revpiname, True) diff --git a/revpipycontrol/shared/__init__.py b/revpipycontrol/shared/__init__.py new file mode 100644 index 0000000..d059206 --- /dev/null +++ b/revpipycontrol/shared/__init__.py @@ -0,0 +1 @@ +"""Shared modules.""" diff --git a/revpipycontrol/shared/ipaclmanager.py b/revpipycontrol/shared/ipaclmanager.py new file mode 100644 index 0000000..5bf9aea --- /dev/null +++ b/revpipycontrol/shared/ipaclmanager.py @@ -0,0 +1,189 @@ +# -*- coding: utf-8 -*- +# +# IpAclManager +# +# (c) Sven Sager, License: LGPLv3 +# Version 0.1.0 +# +"""Verwaltet IP Adressen und deren ACLs.""" +from os import access, R_OK, W_OK +from re import match as rematch + + +def refullmatch(regex, string): + """re.fullmatch wegen alter python version aus wheezy nachgebaut. + + @param regex RegEx Statement + @param string Zeichenfolge gegen die getestet wird + @return True, wenn komplett passt sonst False + + """ + m = rematch(regex, string) + return m is not None and m.end() == len(string) + + +class IpAclManager(): + + """Verwaltung fuer IP Adressen und deren ACL Level.""" + + def __init__(self, minlevel, maxlevel, acl=None): + """Init IpAclManager class. + + @param minlevel Smallest access level (min. 0) + @param maxlevel Biggest access level (max. 9) + @param acl ACL Liste fuer Berechtigungen als + + """ + if type(minlevel) != int: + raise ValueError("parameter minlevel must be ") + if type(maxlevel) != int: + raise ValueError("parameter maxlevel must be ") + if minlevel < 0: + raise ValueError("minlevel must be 0 or more") + if maxlevel > 9: + raise ValueError("maxlevel maximum is 9") + if minlevel > maxlevel: + raise ValueError("minlevel is smaller than maxlevel") + + self.__dict_acl = {} + self.__dict_regex = {} + self.__dict_knownips = {} + self.__filename = None + self.__re_ipacl = "(([\\d\\*]{1,3}\\.){3}[\\d\\*]{1,3},[" \ + + str(minlevel) + "-" + str(maxlevel) + "] ?)*" + + # Liste erstellen, wenn übergeben + if acl is not None: + self.__set_acl(acl) + + def __iter__(self): + """Gibt einzelne ACLs als aus.""" + for aclip in sorted(self.__dict_acl): + yield (aclip, self.__dict_acl[aclip]) + + def __get_acl(self): + """Getter fuer den rohen ACL-String. + return ACLs als """ + str_acl = "" + for aclip in sorted(self.__dict_acl): + str_acl += "{},{} ".format(aclip, self.__dict_acl[aclip]) + return str_acl.strip() + + def __get_filename(self): + """Getter fuer Dateinamen. + @return Filename der ACL """ + return "" if self.__filename is None else self.__filename + + def __get_regex_acl(self): + """Gibt formatierten RegEx-String zurueck. + return RegEx Code als """ + return self.__re_ipacl + + def __set_acl(self, value): + """Uebernimmt neue ACL-Liste fuer die Ausertung der Level. + @param value Neue ACL-Liste als """ + if type(value) != str: + raise ValueError("parameter acl must be ") + + value = value.strip() + if not refullmatch(self.__re_ipacl, value): + raise ValueError("acl format ist not okay - 1.2.3.4,0 5.6.7.8,1") + + # Klassenwerte übernehmen + self.__dict_acl = {} + self.__dict_regex = {} + self.__dict_knownips = {} + + # Liste neu füllen mit regex Strings + for ip_level in value.split(): + ip, level = ip_level.split(",", 1) + self.__dict_acl[ip] = int(level) + self.__dict_regex[ip] = \ + ip.replace(".", "\\.").replace("*", "\\d{1,3}") + + def get_acllevel(self, ipaddress): + """Prueft IP gegen ACL List und gibt ACL-Wert aus. + @param ipaddress zum pruefen + @return ACL Wert oder -1 wenn nicht gefunden""" + # Bei bereits aufgelösten IPs direkt ACL auswerten + if ipaddress in self.__dict_knownips: + return self.__dict_knownips[ipaddress] + + for aclip in sorted(self.__dict_acl, reverse=True): + if refullmatch(self.__dict_regex[aclip], ipaddress): + # IP und Level merken + self.__dict_knownips[ipaddress] = self.__dict_acl[aclip] + + # Level zurückgeben + return self.__dict_acl[aclip] + + return -1 + + def loadacl(self, str_acl): + """Laed ACL String und gibt erfolg zurueck. + @param str_acl ACL als + @return True, wenn erfolgreich uebernommen""" + if not refullmatch(self.__re_ipacl, str_acl): + return False + self.__set_acl(str_acl) + return True + + def loadaclfile(self, filename): + """Laed ACL Definitionen aus Datei. + @param filename Dateiname fuer Definitionen + @return True, wenn Laden erfolgreich war""" + if type(filename) != str: + raise ValueError("parameter filename must be ") + + # Zugriffsrecht prüfen + if not access(filename, R_OK): + return False + + str_acl = "" + with open(filename, "r") as fh: + while True: + buff = fh.readline() + if buff == "": + break + buff = buff.split("#")[0].strip() + if len(buff) > 0: + str_acl += buff + " " + + acl_okay = self.loadacl(str_acl.strip()) + if acl_okay: + # Dateinamen für Schreiben übernehmen + self.__filename = filename + + return acl_okay + + def writeaclfile(self, filename=None, aclname=None): + """Schreibt ACL Definitionen in Datei. + @param filename Dateiname fuer Definitionen + @return True, wenn Schreiben erfolgreich war""" + if filename is not None and type(filename) != str: + raise ValueError("parameter filename must be ") + if aclname is not None and type(aclname) != str: + raise ValueError("parameter aclname must be ") + + # Dateinamen prüfen + if filename is None and self.__filename is not None: + filename = self.__filename + + # Zugriffsrecht prüfen + if not access(filename, W_OK): + return False + + header = "# {}Access Control List (acl)\n" \ + "# One entry per Line IPADRESS,LEVEL\n" \ + "#\n".format("" if aclname is None else aclname + " ") + + with open(filename, "w") as fh: + fh.write(header) + for aclip in sorted(self.__dict_acl): + fh.write("{},{}\n".format(aclip, self.__dict_acl[aclip])) + + return True + + acl = property(__get_acl, __set_acl) + filename = property(__get_filename) + regex_acl = property(__get_regex_acl) diff --git a/setup.py b/setup.py index fbf68c0..5c40fb6 100644 --- a/setup.py +++ b/setup.py @@ -48,6 +48,7 @@ if platform == "linux": ("share/applications", ["data/revpipycontrol.desktop"]), ("share/icons/hicolor/32x32/apps", ["data/revpipycontrol.png"]), ("share/revpipycontrol", glob("revpipycontrol/*.*")), + ("share/revpipycontrol/shared", glob("revpipycontrol/shared/*.*")), ( "share/revpipycontrol/locale/de/LC_MESSAGES", glob("revpipycontrol/locale/de/LC_MESSAGES/*.mo")