From 66445b0fcd03b6084bfa329d43b1f8f7e712db75 Mon Sep 17 00:00:00 2001 From: "Anders H. Rebner" <anderhre@stud.ntnu.no> Date: Wed, 1 Apr 2020 12:50:48 +0200 Subject: [PATCH] #86 Autentifiseringstavlemodul bruker coder, coder modifisert --- soitool/coder.py | 67 +++++++++++++++--- .../modules/module_authentification_board.py | 70 ++++++------------- test/test_module_authentification_board.py | 5 +- 3 files changed, 84 insertions(+), 58 deletions(-) diff --git a/soitool/coder.py b/soitool/coder.py index 533e259..da8d361 100644 --- a/soitool/coder.py +++ b/soitool/coder.py @@ -1,11 +1,12 @@ -"""Generate codes.""" -import string +"""Generate codes. -# https://realpython.com/lessons/cryptographically-secure-random-data-python/ +Source: # https://realpython.com/lessons/cryptographically-secure-random-data-python/ +""" +import string import secrets -def get_code(code_length, mode="ascii"): +def get_code(code_length, mode="ascii", space_interval=0): """ Generate a single random code. @@ -13,18 +14,18 @@ def get_code(code_length, mode="ascii"): ---------- code_length : int The length of the code - mode : string 'ascii' for letters (default), 'digits' for digits and 'combo' - for combination of letters and digits. + for combination of letters and digits, by default 'ascii'. + space_interval : int or None + Spaces will be inserted to code each interval if not 0, by default 0. Return ------ code : string - The code + The code. """ code = "" - i = 0 if mode == "ascii": characters = string.ascii_uppercase @@ -37,10 +38,22 @@ def get_code(code_length, mode="ascii"): "Invalid value for argument 'mode': " "'{}'".format(mode) ) + if not isinstance(space_interval, int): + raise ValueError( + "Invalid value for argument 'separate_interval': " + "'{}'".format(space_interval) + ) + + i = 0 while i < code_length: letter = secrets.choice(characters) code += letter i += 1 + + # Add spaces to code if interval is given + if space_interval > 0: + code = insert_spaces(code, space_interval) + return code @@ -93,3 +106,41 @@ def get_code_length_needed(number_of_entries): code_length = code_length + 1 return code_length + + +def insert_spaces(code, interval): + """Add spaces between code-character each interval. + + Parameters + ---------- + code : string + Code to add spaces to. + interval : int + Interval for inserting spaces. + + Returns + ------- + string + Code separated with spaces. + """ + # Choose starting point for separating code with spaces, depending on + # SEPARATE_INTERVAL and CODE_LENGTH being even or odd numbers. + # If code is 1234567 and interval is 3, code will be 1234 567 instead + # of 123 456 7 after space separation. + code_length = len(code) + if ( + interval % 2 == 0 + and code_length % 2 == 0 + or interval % 2 != 0 + and code_length % 2 != 0 + ): + start = interval - 1 + else: + start = interval + + # Convert to list to add spaces in-between characters + code = list(code) + for i in range(start, code_length - interval, interval): + code[i] += " " + + return "".join(code) diff --git a/soitool/modules/module_authentification_board.py b/soitool/modules/module_authentification_board.py index 3f463ad..e3fabaa 100644 --- a/soitool/modules/module_authentification_board.py +++ b/soitool/modules/module_authentification_board.py @@ -1,9 +1,9 @@ """Module containing SOI-module 'Autentifiseringstavle'.""" import string -from random import choices from PySide2.QtWidgets import QTableWidget, QTableWidgetItem from PySide2 import QtGui from PySide2.QtCore import Qt +from soitool.coder import get_code from soitool.modules.module_base import ( ModuleBase, get_table_size, @@ -13,10 +13,11 @@ from soitool.modules.module_base import ( START_NO_OF_AUTHENTICATION_CODES = 10 CODE_LENGTH = 26 -CODE_CHARACTERS = string.ascii_uppercase # Codes consist of these characters +CODE_CHARACTERS = "ascii" # Has to be 'ascii', 'digits' or 'combo' +# Codes will consist of A-Z if 'ascii', 0-9 if 'digits' and A-Z+0-9 if 'combo'. ROW_IDENTIFIERS = string.ascii_uppercase # Characters for first column, # it's length determines maximum number of codes (rows). -SEPARATE_INTERVAL = 5 # Adds space between sets of characters, 0 => no spaces +SPACE_INTERVAL = 5 # Adds space between sets of characters, 0 => no spaces # If code is 123456 and interval is 2, code will be 12 34 56 # If code is 1234567 and interval is 2, code will be 123 45 67 @@ -32,7 +33,7 @@ class AuthentificationBoardModule(ModuleBase, QTableWidget, metaclass=Meta): By default, the widget initializes with a headline, a row-count of START_NO_OF_AUTHENTIFICATION_CODES and three columns. - Row x in the first column contains the character CODE_CHARACTERS[x]. + Row x in the first column contains the character ROW_IDENTIFIERS[x]. Row x in the second column contains the character x. Row x in the third column contains an authentification code. @@ -53,6 +54,18 @@ class AuthentificationBoardModule(ModuleBase, QTableWidget, metaclass=Meta): QTableWidget.__init__(self) ModuleBase.__init__(self) + if CODE_CHARACTERS == "ascii": + self.code_characters = string.ascii_uppercase + elif CODE_CHARACTERS == "digits": + self.code_characters = string.digits + elif CODE_CHARACTERS == "combo": + self.code_characters = string.ascii_uppercase + string.digits + else: + raise ValueError( + "Invalid value for CONSTANT 'CODE_CHARACTERS': " + "'{}'".format(CODE_CHARACTERS) + ) + # Remove headers and scrollbars self.horizontalHeader().hide() self.verticalHeader().hide() @@ -140,30 +153,10 @@ class AuthentificationBoardModule(ModuleBase, QTableWidget, metaclass=Meta): # Randomly generate a new code until it is unique unique_code = False while not unique_code: - code = choices(CODE_CHARACTERS, k=CODE_LENGTH) + code = get_code(CODE_LENGTH, CODE_CHARACTERS, SPACE_INTERVAL) unique_code = code not in existing_codes - # Choose starting point for separating code with spaces, depending on - # SEPARATE_INTERVAL and CODE_LENGTH being even or odd numbers. - # If code is 1234567 and interval is 3, code will be 1234 567 instead - # of 123 456 7 after space separation. - if ( - SEPARATE_INTERVAL % 2 == 0 - and CODE_LENGTH % 2 == 0 - or SEPARATE_INTERVAL % 2 != 0 - and CODE_LENGTH % 2 != 0 - ): - start = SEPARATE_INTERVAL - 1 - else: - start = SEPARATE_INTERVAL - - # Separate code with spaces - for i in range( - start, len(code) - SEPARATE_INTERVAL, SEPARATE_INTERVAL - ): - code[i] += " " - - return "".join(code) + return code def keyPressEvent(self, event): """Add or remove row when 'Ctrl + +' and 'Ctrl + -' are pressed.""" @@ -193,7 +186,7 @@ class AuthentificationBoardModule(ModuleBase, QTableWidget, metaclass=Meta): # Loop through all rows starting with the new row for i in range(row_index + 1, self.rowCount()): # Insert row identifier in first column - item_first = QTableWidgetItem(CODE_CHARACTERS[i - 1]) + item_first = QTableWidgetItem(self.code_characters[i - 1]) item_first.setFlags(item_first.flags() ^ Qt.ItemIsEditable) self.setItem(i, 0, item_first) @@ -223,7 +216,7 @@ class AuthentificationBoardModule(ModuleBase, QTableWidget, metaclass=Meta): # 'Decrease' row identifiers below the removed row # If first row is removed, identifier A,B,C becomes A,B (not B,C) for i in range(row_index, self.rowCount()): - self.item(i, 0).setText(CODE_CHARACTERS[i - 1]) + self.item(i, 0).setText(self.code_characters[i - 1]) self.item(i, 1).setText(str(i - 1)) resize_table(self, resize_column=False) @@ -296,24 +289,7 @@ def generate_authentification_codes(amount=START_NO_OF_AUTHENTICATION_CODES): """ codes = [] for _ in range(amount): - code = choices(CODE_CHARACTERS, k=CODE_LENGTH) - # Choose starting point for separating code with spaces, depending on - # SEPARATE_INTERVAL and CODE_LENGTH being even or odd numbers. - # If code is 1234567 and interval is 3, code will be 1234 567 instead - # of 123 456 7 after space separation. - if ( - SEPARATE_INTERVAL % 2 == 0 - and CODE_LENGTH % 2 == 0 - or SEPARATE_INTERVAL % 2 != 0 - and CODE_LENGTH % 2 != 0 - ): - start = SEPARATE_INTERVAL - 1 - else: - start = SEPARATE_INTERVAL - for i in range( - start, len(code) - SEPARATE_INTERVAL, SEPARATE_INTERVAL - ): - code[i] += " " - codes.append("".join(code)) + code = get_code(CODE_LENGTH, CODE_CHARACTERS, SPACE_INTERVAL) + codes.append(code) return codes diff --git a/test/test_module_authentification_board.py b/test/test_module_authentification_board.py index 19a1773..9ef4b5f 100644 --- a/test/test_module_authentification_board.py +++ b/test/test_module_authentification_board.py @@ -10,7 +10,6 @@ from soitool.modules.module_authentification_board import ( HEADLINE_TEXT, ROW_IDENTIFIERS, CODE_LENGTH, - CODE_CHARACTERS, ) from soitool.soi import SOI @@ -50,10 +49,10 @@ class TestDefaultAuthentificationBoardModule(unittest.TestCase): # Assert cell content in third column is correct code = self.module.item(1, 2).text() self.assertTrue(len(code) >= CODE_LENGTH) - # Assert all code characters are taken from list CODE_CHARACTERS + # Assert all code characters are taken from list code_characters for _, character in enumerate(code): if character != " ": - self.assertTrue(character in CODE_CHARACTERS) + self.assertTrue(character in self.module.code_characters) # Assert all codes are unique code_list = self.module.get_codes() code_set = set(code_list) -- GitLab