From 83a6e110f61777a5c43bd1d04eb133d438b09db5 Mon Sep 17 00:00:00 2001 From: Adrien Bourmault Date: Tue, 27 Aug 2019 16:49:01 +0200 Subject: [PATCH 01/10] Correcting "token clear in repo" --- src/github.py | 39 +++++++++++++++++++++++++++++++++++++-- src/globs.py | 6 +++--- src/main.py | 14 +++++++------- src/mrz.py | 35 ++++++++++++++++++++--------------- src/version.res | 8 ++++---- 5 files changed, 71 insertions(+), 31 deletions(-) diff --git a/src/github.py b/src/github.py index 1fd0e88..ea4889a 100644 --- a/src/github.py +++ b/src/github.py @@ -25,14 +25,41 @@ """ from requests.auth import HTTPProxyAuth from pypac import PACSession +from Crypto import Random +from Crypto.Cipher import AES from requests import Session -import json +import json, hashlib, base64 import logger # logger.py import globs # globs.py credentials = False +class AESCipher(object): + + def __init__(self, key): + self.bs = 32 + self.key = hashlib.sha256(key.encode()).digest() + + def encrypt(self, raw): + raw = self._pad(raw) + iv = Random.new().read(AES.block_size) + cipher = AES.new(self.key, AES.MODE_CBC, iv) + return base64.b64encode(iv + cipher.encrypt(raw)) + + def decrypt(self, enc): + enc = base64.b64decode(enc) + iv = enc[:AES.block_size] + cipher = AES.new(self.key, AES.MODE_CBC, iv) + return self._unpad(cipher.decrypt(enc[AES.block_size:])).decode('utf-8') + + def _pad(self, s): + return s + (self.bs - len(s) % self.bs) * chr(self.bs - len(s) % self.bs) + + @staticmethod + def _unpad(s): + return s[:-ord(s[len(s) - 1:])] + def reportBug(reason="",log=""): logfile = logger.logCur @@ -45,7 +72,7 @@ def reportBug(reason="",log=""): payload = {'title':"CNIRevelator Bug Report", 'body':"**An error has been reported by a CNIRevelator instance.**\n\n**Here is the full reason of this issue:**\n{}\n\n**The full log is here:** {}".format(reason, log), "assignees":["neox95"], "labels":["bug", "AUTO"]} - handler = session.post('https://api.github.com/repos/neox95/cnirevelator/issues', headers={'Authorization': 'token %s' % globs.CNIRGitToken}, data=json.dumps(payload)) + handler = session.post('https://api.github.com/repos/neox95/cnirevelator/issues', headers={'Authorization': 'token %s' % decryptToken(globs.CNIRGitToken)}, data=json.dumps(payload)) logfile.printdbg(handler.reason) @@ -54,4 +81,12 @@ def reportBug(reason="",log=""): else: return False +def encryptToken(token): + AESObj = AESCipher(globs.CNIRCryptoKey) + return AESObj.encrypt(token) + +def decryptToken(token): + AESObj = AESCipher(globs.CNIRCryptoKey) + return AESObj.decrypt(token) + diff --git a/src/globs.py b/src/globs.py index b7dbe85..14dc82e 100644 --- a/src/globs.py +++ b/src/globs.py @@ -26,13 +26,13 @@ import os # CNIRevelator version -verType = "stable release" -version = [3, 1, 4] +verType = "beta release" +version = [3, 1, 5] verstring_full = "{}.{}.{} {}".format(version[0], version[1], version[2], verType) verstring = "{}.{}".format(version[0], version[1]) CNIRTesserHash = "947224361ffab8c01f05c9394b44b1bd7c8c3d4d" -CNIRGitToken = "ef7737dd1e5ad8a35d3cc5fdbeb273e69a09f25f" +CNIRGitToken = "mJHKXqnazO/xZ9Fs18SDMqcGJ15A27OlZyd27cDe5dhHKklO2YShdWwUgEDUZQI02kpgYaLceMidTK37ZqakW+VYgPPuh0e9Ry2IH0KHc3o=" CNIRFolder = os.path.dirname(os.path.realpath(__file__)) CNIRLColor = "#006699" CNIRName = "CNIRevelator {}".format(verstring) diff --git a/src/main.py b/src/main.py index 6430527..d2ff455 100644 --- a/src/main.py +++ b/src/main.py @@ -172,7 +172,7 @@ class mainWindow(Tk): "SEX" : self.sex, "NAT" : self.nat, "PAYS" : self.pays, - "INDIC" : self.indic, + "INDIC" : self.indic } # The the image viewer @@ -723,12 +723,12 @@ class mainWindow(Tk): #print(docInfos) # display the infos for key in [ e for e in docInfos ]: - #print(docInfos[key]) - if key in ["CODE", "CTRL", "CTRLF"]: + print(key) + if key in ["CODE", "CTRL", "CTRLF", "FACULT"]: continue - if not docInfos[key] == False: - if not docInfos[key] == "": - self.infoList[key]['text'] = docInfos[key] + if not docInfos[key][1] == False: + if not docInfos[key][0] == "": + self.infoList[key]['text'] = docInfos[key][0] self.infoList[key]['background'] = self['background'] self.infoList[key]['foreground'] = "black" else: @@ -738,7 +738,7 @@ class mainWindow(Tk): else: self.infoList[key]['background'] = "red" self.infoList[key]['foreground'] = "white" - self.infoList[key]['text'] = "NC" + self.infoList[key]['text'] = docInfos[key][0] self.compliance = False if self.compliance == True: diff --git a/src/mrz.py b/src/mrz.py index a2013d4..ec06522 100644 --- a/src/mrz.py +++ b/src/mrz.py @@ -490,18 +490,19 @@ def getDocInfos(doc, code): for field in infoTypes: value = code[ field[1][0] : field[1][1] ].replace("<", " ").strip() + res[field[0]] = [0,0] # State code if field[0] == 'PAYS' or field[0] == 'NAT': try: if len(value) == 3 and value[-1] != "<": - res[field[0]] = landcode3[value] + res[field[0]] = (landcode3[value], True) elif len(value) == 3 and value[-1] == "<": - res[field[0]] = landcode2[value[:-1]] + res[field[0]] = (landcode2[value[:-1]], True) else: - res[field[0]] = landcode2[value] + res[field[0]] = (landcode2[value], True) except KeyError: - res[field[0]] = False + res[field[0]] = [value, False] # Dates elif field[0][1:] == 'DATE': @@ -517,39 +518,43 @@ def getDocInfos(doc, code): except ValueError: #print(value) if value != "": - res[field[0]] = False + res[field[0]] = [value, False] else: - res[field[0]] = value + res[field[0]] = [value, True] # Numbers elif field[0][:-1] == 'NOINT': try: - res["NO"] += value + res["NO"][0] += value + res["NO"][1] = True except KeyError: - res["NO"] = value + res["NO"] = [value, True] + elif field[0] == 'NOINT': try: - res["NO"] += value + res["NO"][0] += value + res["NO"][1] = True except KeyError: - res["NO"] = value + res["NO"] = [value, True] elif field[0] == 'FACULT': try: - res["INDIC"] += value + res["INDIC"][0] += value + res["INDIC"][1] = True except KeyError: - res["INDIC"] = value + res["INDIC"] = [value, True] # Sex elif field[0] == 'SEX': if not value in "MF": - res[field[0]] = False + res[field[0]] = [value, False] else: - res[field[0]] = value + res[field[0]] = [value, True] # All other cases else: if value != "": - res[field[0]] = value + res[field[0]] = [value, True] return res diff --git a/src/version.res b/src/version.res index 289e4fc..8da2b40 100644 --- a/src/version.res +++ b/src/version.res @@ -6,8 +6,8 @@ VSVersionInfo( ffi=FixedFileInfo( # filevers and prodvers should be always a tuple with four items: (1, 2, 3, 4) # Set not needed items to zero 0. -filevers=(3, 1, 4, 0), -prodvers=(3, 1, 4, 0), +filevers=(3, 1, 5, 0), +prodvers=(3, 1, 5, 0), # Contains a bitmask that specifies the valid bits 'flags'r mask=0x3f, # Contains a bitmask that specifies the Boolean attributes of the file. @@ -31,12 +31,12 @@ StringFileInfo( u'040904B0', [StringStruct(u'CompanyName', u'Adrien Bourmault (neox95)'), StringStruct(u'FileDescription', u'This file is part of CNIRevelator.'), - StringStruct(u'FileVersion', u'3.1.4'), + StringStruct(u'FileVersion', u'3.1.5'), StringStruct(u'InternalName', u'CNIRevelator'), StringStruct(u'LegalCopyright', u'Copyright (c) Adrien Bourmault (neox95)'), StringStruct(u'OriginalFilename', u'CNIRevelator.exe'), StringStruct(u'ProductName', u'CNIRevelator 3.1'), - StringStruct(u'ProductVersion', u'3.1.4')]) + StringStruct(u'ProductVersion', u'3.1.5')]) ]), VarFileInfo([VarStruct(u'Translation', [1033, 1200])]) ] From c880645949764d5fd2308510b82eb9d926032c89 Mon Sep 17 00:00:00 2001 From: Adrien Bourmault Date: Wed, 28 Aug 2019 16:24:02 +0200 Subject: [PATCH 02/10] Bug reporting bug correction (encrypt the token was the solution) --- src/CNIRevelator.py | 2 ++ src/lang.py | 6 ++++-- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/src/CNIRevelator.py b/src/CNIRevelator.py index 91821ca..76a5c2a 100644 --- a/src/CNIRevelator.py +++ b/src/CNIRevelator.py @@ -84,6 +84,8 @@ def main(): ## BOOTSTRAP OF CNIREVELATOR try: + logfile.printdbg('CNIRevelator log file version {}'.format(globs.verstring_full)) + try: # LANGUAGE lang.readLang() diff --git a/src/lang.py b/src/lang.py index 8de56b4..86fe3a6 100644 --- a/src/lang.py +++ b/src/lang.py @@ -141,7 +141,8 @@ french = \ "Coller :\t\t\t\tCtrl-V \n" "Forcer une nouvelle détection du document :\tEchap\n", -"CHANGELOG" : "Version 3.1.4 \nMise-à-jour mineure avec les progressions suivantes :\n- Correction d'un bug affectant la rotation de documents dans l'afficheur d'images\n- Ajout d'une période de mise-à-jour afin d'éviter de rechercher les mises-à-jour tous les jours\n\n" + \ +"CHANGELOG" : "Version 3.1.5 \nMise-à-jour mineure avec les progressions suivantes :\n- Correction d'un bug affectant le signalement de bug\n\n" + \ +"Version 3.1.4 \nMise-à-jour mineure avec les progressions suivantes :\n- Correction d'un bug affectant la rotation de documents dans l'afficheur d'images\n- Ajout d'une période de mise-à-jour afin d'éviter de rechercher les mises-à-jour tous les jours\n\n" + \ "Version 3.1.3 \nMise-à-jour mineure avec les progressions suivantes :\n- Correction d'un bug de la détection automatique de documents\n- Ajout d'une fonctionnalité de rapport d'erreur\n\n" + \ "Version 3.1.2 \nMise-à-jour mineure avec les progressions suivantes :\n- Montée de version de Tesseract OCR : 5.0\n- Correction de noms des documents\n- Résolution d'un problème avec le système de mise-à-jour\n- Amélioration des effets sur images\n\n" + \ "Version 3.1.1 \nMise-à-jour mineure avec les progressions suivantes :\n- Correction d'un bug sévère du système de mise à jour\n\n" + \ @@ -847,7 +848,8 @@ english = \ "Paste:\t\t\t\tCtrl-V\n" "Force a new document detection:\tEchap\n", -"CHANGELOG" : "Version 3.1.4 \nMinor update with the following progressions:\n- Correction of a bug affecting rotation of document in image viewer\n- Added a new update period to prevent updating everyday\n\n" + \ +"CHANGELOG" : "Version 3.1.5 \nMinor update with the following progressions:\n- Correction of a bug affecting bug reporting\n\n" + \ +"Version 3.1.4 \nMinor update with the following progressions:\n- Correction of a bug affecting rotation of document in image viewer\n- Added a new update period to prevent updating everyday\n\n" + \ "Version 3.1.3 \nMinor update with the following progressions:\n- Correction of a bug affecting automated document detection\n- Added bug reporting functionnality\n\n" + \ "Version 3.1.2 \nMinor update with the following progressions: \n- Tesseract OCR version upgrade : 5.0\n- Correction of document names\n- Fixed a problem with the update system\n- Some enhancements about effects on images\n\n" + \ "Version 3.1.1 \nMinor update with the following progressions: \n- Fixed a severe bug in the update system\n\n" + \ From 535583e010e6a81f349ad27b71d199da4d697380 Mon Sep 17 00:00:00 2001 From: Adrien Bourmault Date: Wed, 28 Aug 2019 16:38:18 +0200 Subject: [PATCH 03/10] Update changelog --- src/lang.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/lang.py b/src/lang.py index 86fe3a6..699596f 100644 --- a/src/lang.py +++ b/src/lang.py @@ -141,7 +141,7 @@ french = \ "Coller :\t\t\t\tCtrl-V \n" "Forcer une nouvelle détection du document :\tEchap\n", -"CHANGELOG" : "Version 3.1.5 \nMise-à-jour mineure avec les progressions suivantes :\n- Correction d'un bug affectant le signalement de bug\n\n" + \ +"CHANGELOG" : "Version 3.1.5 \nMise-à-jour mineure avec les progressions suivantes :\n- Correction d'un bug affectant le signalement de bug\n- Améliorations de l'affichage de la conformité des informations\n\n" + \ "Version 3.1.4 \nMise-à-jour mineure avec les progressions suivantes :\n- Correction d'un bug affectant la rotation de documents dans l'afficheur d'images\n- Ajout d'une période de mise-à-jour afin d'éviter de rechercher les mises-à-jour tous les jours\n\n" + \ "Version 3.1.3 \nMise-à-jour mineure avec les progressions suivantes :\n- Correction d'un bug de la détection automatique de documents\n- Ajout d'une fonctionnalité de rapport d'erreur\n\n" + \ "Version 3.1.2 \nMise-à-jour mineure avec les progressions suivantes :\n- Montée de version de Tesseract OCR : 5.0\n- Correction de noms des documents\n- Résolution d'un problème avec le système de mise-à-jour\n- Amélioration des effets sur images\n\n" + \ @@ -848,7 +848,7 @@ english = \ "Paste:\t\t\t\tCtrl-V\n" "Force a new document detection:\tEchap\n", -"CHANGELOG" : "Version 3.1.5 \nMinor update with the following progressions:\n- Correction of a bug affecting bug reporting\n\n" + \ +"CHANGELOG" : "Version 3.1.5 \nMinor update with the following progressions:\n- Correction of a bug affecting bug reporting\n - Enhancements on information compliance display\n\n" + \ "Version 3.1.4 \nMinor update with the following progressions:\n- Correction of a bug affecting rotation of document in image viewer\n- Added a new update period to prevent updating everyday\n\n" + \ "Version 3.1.3 \nMinor update with the following progressions:\n- Correction of a bug affecting automated document detection\n- Added bug reporting functionnality\n\n" + \ "Version 3.1.2 \nMinor update with the following progressions: \n- Tesseract OCR version upgrade : 5.0\n- Correction of document names\n- Fixed a problem with the update system\n- Some enhancements about effects on images\n\n" + \ From de31c9d79c1fbc71fcc4eb4adfb5d22480eef137 Mon Sep 17 00:00:00 2001 From: Adrien Bourmault Date: Wed, 28 Aug 2019 16:47:02 +0200 Subject: [PATCH 04/10] Update VERSIONS.LST --- VERSIONS.LST | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/VERSIONS.LST b/VERSIONS.LST index d2ca4a2..ae7d4a1 100644 --- a/VERSIONS.LST +++ b/VERSIONS.LST @@ -1,2 +1,2 @@ # ver|url|checksum, and | as separator, one version per || -3.1.4|https://github.com/neox95/CNIRevelator/releases/download/3.1.4e/CNIRevelator.zip|1acf3b6158506218b0b16948af1df51b11d81eea|| +3.1.5|https://github.com/neox95/CNIRevelator/releases/download/3.1.5/CNIRevelator.zip|9efa41460dbe9375f15db8572b9f8d8e43c94a02|| From 102b1d1e67967d5ad36dc484920aea75a7fd29eb Mon Sep 17 00:00:00 2001 From: Adrien Bourmault Date: Thu, 29 Aug 2019 11:04:50 +0200 Subject: [PATCH 05/10] Add files via upload --- src/updater.py | 57 +++++++++++++++++++++++++++----------------------- 1 file changed, 31 insertions(+), 26 deletions(-) diff --git a/src/updater.py b/src/updater.py index 5ca8d0e..8541aa4 100644 --- a/src/updater.py +++ b/src/updater.py @@ -371,25 +371,15 @@ def umain(): # Reading it lastUpdate = datetime.datetime.strptime(configFile.read(),"%d/%m/%Y") except Exception as e: - critical.crashCNIR() - raise IOError(str(e)) + critical.crashCNIR(False) + time.sleep(3) + launcherWindow.exit() + return 1 else: - # Recreating the url file - lastUpdate = currentDate - try: - os.mkdir(globs.CNIRFolder + '\\config') - except: - pass - - with open(globs.CNIRLastUpdate, 'w') as (configFile): - try: - # Writing it - configFile.write("{}/{}/{}".format(currentDate.day, currentDate.month, currentDate.year)) - except Exception as e: - critical.crashCNIR() - raise IOError(str(e)) + lastUpdate = datetime.datetime(1970,1,1) if not globs.CNIRNewVersion and os.path.exists(globs.CNIRFolder + '\\Tesseract-OCR5\\') and (currentDate - lastUpdate).days < 7: + logfile.printdbg("No need to update, {} days remaining".format(7 - (currentDate - lastUpdate).days)) launcherWindow.exit() return 0 @@ -399,7 +389,7 @@ def umain(): # EXECUTING THE UPDATE BATCH success = batch(credentials) except Exception as e: - critical.crashCNIR() + critical.crashCNIR(False) launcherWindow.printmsg('ERROR : ' + str(e)) time.sleep(3) launcherWindow.exit() @@ -408,20 +398,36 @@ def umain(): if success: logfile.printdbg("Software is up-to-date !") launcherWindow.printmsg('Software is up-to-date !') + # Recreating the url file + lastUpdate = currentDate + try: + os.mkdir(globs.CNIRFolder + '\\config') + except: + pass + + with open(globs.CNIRLastUpdate, 'w') as (configFile): + try: + # Writing it + configFile.write("{}/{}/{}".format(currentDate.day, currentDate.month, currentDate.year)) + except Exception as e: + critical.crashCNIR(False) + time.sleep(3) + launcherWindow.exit() + return + if UPDATE_IS_MADE: + launcherWindow.exit() + return 0 + else: logfile.printerr("An error occured. No effective update !") launcherWindow.printmsg(lang.all[globs.CNIRlang]['An error occured. No effective update !']) time.sleep(2) launcherWindow.exit() return 0 - - if UPDATE_IS_MADE: - launcherWindow.exit() - return 0 + except: - critical.crashCNIR() + critical.crashCNIR(False) launcherWindow.exit() - sys.exit(2) return 2 try: @@ -429,7 +435,7 @@ def umain(): # INSTALLING TESSERACT OCR success = tessInstall(globs.CNIRFolder, credentials) except Exception as e: - critical.crashCNIR() + critical.crashCNIR(False) launcherWindow.printmsg('ERROR : ' + str(e)) time.sleep(3) launcherWindow.exit() @@ -446,9 +452,8 @@ def umain(): return 0 except: - critical.crashCNIR() + critical.crashCNIR(False) launcherWindow.exit() - exitProcess(2) return 2 time.sleep(2) From 4f36d5904eb7960b19446d4a8f703f8047f40faa Mon Sep 17 00:00:00 2001 From: Adrien Bourmault Date: Thu, 29 Aug 2019 11:15:07 +0200 Subject: [PATCH 06/10] Update VERSIONS.LST --- VERSIONS.LST | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/VERSIONS.LST b/VERSIONS.LST index ae7d4a1..b403c6a 100644 --- a/VERSIONS.LST +++ b/VERSIONS.LST @@ -1,2 +1,2 @@ # ver|url|checksum, and | as separator, one version per || -3.1.5|https://github.com/neox95/CNIRevelator/releases/download/3.1.5/CNIRevelator.zip|9efa41460dbe9375f15db8572b9f8d8e43c94a02|| +3.1.5|https://github.com/neox95/CNIRevelator/releases/download/3.1.5a/CNIRevelator.zip|566801a17cb85060c66cc9e3d6a344144053271c|| From d1bf646118f96b61bf36f8b5d2824204d23697db Mon Sep 17 00:00:00 2001 From: Adrien Bourmault Date: Thu, 29 Aug 2019 12:54:43 +0200 Subject: [PATCH 07/10] Somes changes on UI and update system --- src/critical.py | 6 ++++++ src/ihm.py | 37 ++++++++++++++++++++++++------------- src/main.py | 15 ++++++++------- src/updater.py | 30 +++++++++++++++++++++++++++--- 4 files changed, 65 insertions(+), 23 deletions(-) diff --git a/src/critical.py b/src/critical.py index 74cb1d2..6b2843e 100644 --- a/src/critical.py +++ b/src/critical.py @@ -49,6 +49,12 @@ def crashCNIR(shutdown=True): showerror(lang.all[globs.CNIRlang]["CNIRevelator Fatal Eror"], lang.all[globs.CNIRlang]["CNIRevelator crashed because a fatal error occured. View log for more infos and please open an issue on Github"]) + # Force new update + try: + os.remove(globs.CNIRLastUpdate) + except: + pass + res = askquestion(lang.all[globs.CNIRlang]["CNIRevelator Fatal Eror"], lang.all[globs.CNIRlang]["Would you like to report this bug ?"]) if res == "yes": # read the log diff --git a/src/ihm.py b/src/ihm.py index ca5e68a..097c9c0 100644 --- a/src/ihm.py +++ b/src/ihm.py @@ -45,13 +45,16 @@ controlKeys = ["Escape", "Right", "Left", "Up", "Down", "Home", "End", "BackSpac class DocumentAsk(Toplevel): def __init__(self, parent, choices): - self.choice = 0 - vals = [0, 1] super().__init__(parent) self.title("{} :".format(lang.all[globs.CNIRlang]["Choose the identity document"])) - ttk.Radiobutton(self, text=choices[0], command=self.register0, value=vals[0]).pack() - ttk.Radiobutton(self, text=choices[1], command=self.register1, value=vals[1]).pack() + self.choice = 0 + vals = [i[2] for i in choices] + for i in range(len(vals)): + a = ttk.Radiobutton(self, text=vals[i], command=self.createRegister(i), value=vals[i]) + a.pack(fill=Y) + if i == 0: + a.invoke() self.button = Button(self, text='OK', command=(self.ok)).pack() self.resizable(width=False, height=False) @@ -68,10 +71,11 @@ class DocumentAsk(Toplevel): y = hs / 2 - h / 2 self.geometry('%dx%d+%d+%d' % (w, h, x, y)) - def register0(self): - self.choice = 0 - def register1(self): - self.choice = 1 + def createRegister(self, i): + def register(): + self.choice = i + return register + def ok(self): self.destroy() @@ -193,7 +197,7 @@ class ChangelogDialog(Toplevel): class langDialog(Toplevel): - def __init__(self, parent): + def __init__(self, parent, currentLang): super().__init__(parent) self.title(lang.all[globs.CNIRlang]["Language"]) @@ -202,7 +206,10 @@ class langDialog(Toplevel): vals = [i for i in lang.all] for i in range(len(lang.all)): - ttk.Radiobutton(self, text=vals[i], command=self.createRegister(i), value=vals[i]).pack(fill=Y) + a = ttk.Radiobutton(self, text=vals[i], command=self.createRegister(i), value=vals[i]) + a.pack(fill=Y) + if i == vals.index(currentLang): + a.invoke() ttk.Button(self, text="OK", command=(self.oki)).pack(fill=Y, pady=5) @@ -231,7 +238,7 @@ class langDialog(Toplevel): class updateSetDialog(Toplevel): - def __init__(self, parent): + def __init__(self, parent, currentChannel): super().__init__(parent) self.title(lang.all[globs.CNIRlang]["Update options"]) @@ -241,7 +248,11 @@ class updateSetDialog(Toplevel): self.vals = ["Stable", "Beta"] vals = self.vals for i in range(len(vals)): - ttk.Radiobutton(self, text=vals[i], command=self.createRegister(i), value=vals[i]).pack(fill=Y) + a = ttk.Radiobutton(self, text=vals[i], command=self.createRegister(i), value=vals[i]) + a.pack(fill=Y) + if i == self.vals.index(currentChannel): + a.invoke() + ttk.Button(self, text="OK", command=(self.oki)).pack(fill=Y, pady=5) @@ -265,7 +276,7 @@ class updateSetDialog(Toplevel): def createRegister(self, i): def register(): - updater.updateChannel(self.vals[i]) + updater.setUpdateChannel(self.vals[i]) return register class LauncherWindow(Tk): diff --git a/src/main.py b/src/main.py index d2ff455..6f4b4dc 100644 --- a/src/main.py +++ b/src/main.py @@ -49,6 +49,7 @@ import mrz # mrz.py import globs # globs.py import pytesseract # pytesseract.py import lang # lang.py +import updater # updater.py # Global handler logfile = logger.logCur @@ -510,9 +511,9 @@ class mainWindow(Tk): # Get the candidates candidates = mrz.allDocMatch(self.mrzChar.split("\n"), final=isFull) - if len(candidates) == 2 and len(self.mrzChar) >= 8: + if len(candidates) >= 2 and len(candidates) < 4 and len(self.mrzChar) >= 8: # Parameters for the choice invite - invite = ihm.DocumentAsk(self, [candidates[0][2], candidates[1][2]]) + invite = ihm.DocumentAsk(self, candidates) invite.transient(self) invite.grab_set() invite.focus_force() @@ -606,9 +607,9 @@ class mainWindow(Tk): # Get the candidates candidates = mrz.allDocMatch(self.mrzChar.split("\n")) - if len(candidates) == 2 and len(self.mrzChar) >= 8: + if len(candidates) >= 2 and len(candidates) < 4 and len(self.mrzChar) >= 8: # Parameters for the choice invite - invite = ihm.DocumentAsk(self, [candidates[0][2], candidates[1][2]]) + invite = ihm.DocumentAsk(self, candidates) invite.transient(self) invite.grab_set() invite.focus_force() @@ -724,7 +725,7 @@ class mainWindow(Tk): # display the infos for key in [ e for e in docInfos ]: print(key) - if key in ["CODE", "CTRL", "CTRLF", "FACULT"]: + if key in ["CODE", "CTRL", "CTRLF", "FACULT", "NOINT"]: continue if not docInfos[key][1] == False: if not docInfos[key][0] == "": @@ -1072,7 +1073,7 @@ class mainWindow(Tk): """ Update Settings """ - changeupdateWin = ihm.updateSetDialog(self) + changeupdateWin = ihm.updateSetDialog(self, updater.getUpdateChannel()) changeupdateWin.transient(self) changeupdateWin.grab_set() changeupdateWin.focus_force() @@ -1082,7 +1083,7 @@ class mainWindow(Tk): """ Lang Settings """ - changelangWin = ihm.langDialog(self) + changelangWin = ihm.langDialog(self, globs.CNIRlang) changelangWin.transient(self) changelangWin.grab_set() changelangWin.focus_force() diff --git a/src/updater.py b/src/updater.py index 8541aa4..5d62988 100644 --- a/src/updater.py +++ b/src/updater.py @@ -88,14 +88,38 @@ def exitProcess(arg): process.terminate() sys.exit(arg) -def updateChannel(choice): +def setUpdateChannel(choice): + """ + Sets the new update channel and forces new update at next launch + """ if choice == "Beta": with open(globs.CNIRUrlConfig, 'w') as (configFile): configFile.write("{}\n0\n0".format(globs.CNIRBetaURL)) - else: + # Force new update + try: + os.remove(globs.CNIRLastUpdate) + except: + pass + elif choice == "Stable": with open(globs.CNIRUrlConfig, 'w') as (configFile): configFile.write("{}\n0\n0".format(globs.CNIRDefaultURL)) - + # Force new update + try: + os.remove(globs.CNIRLastUpdate) + except: + pass + +def getUpdateChannel(): + """ + Returns the current update channel + """ + with open(globs.CNIRUrlConfig, 'r') as (configFile): + url = configFile.read() + if not "master" in url: + return "Beta" + else: + return "Stable" + def getLatestVersion(credentials): """ Returns the latest version of the software From e230d65cd4989ef191f9b220ec89437745abf2b9 Mon Sep 17 00:00:00 2001 From: Adrien Bourmault Date: Thu, 29 Aug 2019 15:00:29 +0200 Subject: [PATCH 08/10] Update VERSIONS.LST --- VERSIONS.LST | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/VERSIONS.LST b/VERSIONS.LST index b403c6a..4bbf951 100644 --- a/VERSIONS.LST +++ b/VERSIONS.LST @@ -1,2 +1,2 @@ # ver|url|checksum, and | as separator, one version per || -3.1.5|https://github.com/neox95/CNIRevelator/releases/download/3.1.5a/CNIRevelator.zip|566801a17cb85060c66cc9e3d6a344144053271c|| +3.1.5|https://github.com/neox95/CNIRevelator/releases/download/3.1.5a/CNIRevelator.zip|afbcbef376ea6c21f5a7cf15cc210afc24616b2b|| From f744c6feddfdb6e594f53ce9501bfda01099a44a Mon Sep 17 00:00:00 2001 From: Adrien Bourmault Date: Fri, 30 Aug 2019 11:18:51 +0200 Subject: [PATCH 09/10] Correcting some bugs and enhance the selection and UI --- src/critical.py | 17 +++++++------- src/downloader.py | 10 +++------ src/github.py | 9 +++++--- src/globs.py | 2 +- src/ihm.py | 1 - src/lang.py | 10 +++++++-- src/main.py | 56 +++++++++++++++++++++++++++++++++------------- src/pytesseract.py | 6 ++--- src/updater.py | 8 +++++-- 9 files changed, 77 insertions(+), 42 deletions(-) diff --git a/src/critical.py b/src/critical.py index 6b2843e..3a4635b 100644 --- a/src/critical.py +++ b/src/critical.py @@ -36,7 +36,7 @@ import logger # logger.py import globs # globs.py import github # github.py -def crashCNIR(shutdown=True): +def crashCNIR(shutdown=True, option="", isVoluntary=False): """ very last solution """ @@ -47,13 +47,14 @@ def crashCNIR(shutdown=True): logfile = logger.logCur logfile.printerr("FATAL ERROR : see traceback below.\n{}".format(traceback.format_exc())) - showerror(lang.all[globs.CNIRlang]["CNIRevelator Fatal Eror"], lang.all[globs.CNIRlang]["CNIRevelator crashed because a fatal error occured. View log for more infos and please open an issue on Github"]) + if not isVoluntary: + showerror(lang.all[globs.CNIRlang]["CNIRevelator Fatal Eror"], lang.all[globs.CNIRlang]["CNIRevelator crashed because a fatal error occured. View log for more infos and please open an issue on Github"] + "\n\n{}\n{}".format(option, traceback.format_exc())) - # Force new update - try: - os.remove(globs.CNIRLastUpdate) - except: - pass + # Force new update + try: + os.remove(globs.CNIRLastUpdate) + except: + pass res = askquestion(lang.all[globs.CNIRlang]["CNIRevelator Fatal Eror"], lang.all[globs.CNIRlang]["Would you like to report this bug ?"]) if res == "yes": @@ -66,7 +67,7 @@ def crashCNIR(shutdown=True): logfile.printerr("Can't read the log file.") # send it - success = github.reportBug(traceback.format_exc(), data) + success = github.reportBug(traceback.format_exc(), data, isVoluntary) if not success: logfile.printerr("Can't send to Github.") diff --git a/src/downloader.py b/src/downloader.py index 85eee66..26dd31c 100644 --- a/src/downloader.py +++ b/src/downloader.py @@ -81,10 +81,11 @@ class newcredentials: self.trying += 1 try: - sessionAnswer = session.get('https://www.google.com') + sessionAnswer = session.get('http://www.google.com') except Exception as e: logfile.printdbg('Network Error : ' + str(e)) - sessionAnswer = '' + self.login = "nointernet" + return logfile.printdbg("Session Answer : " + str(sessionAnswer)) @@ -94,11 +95,6 @@ class newcredentials: self.valid = True return - if str(sessionAnswer) != '' and self.trying > 2: - # because sometimes the proxy does not return an error (especially if we do not provide either credentials) - logfile.printerr('Network Error, or need a proxy !') - return - if self.trying > 4: logfile.printerr('Invalid credentials : access denied, a maximum of 3 trials have been raised !') return diff --git a/src/github.py b/src/github.py index ea4889a..26c324d 100644 --- a/src/github.py +++ b/src/github.py @@ -60,7 +60,7 @@ class AESCipher(object): def _unpad(s): return s[:-ord(s[len(s) - 1:])] -def reportBug(reason="",log=""): +def reportBug(reason="",log="", isVoluntary=False): logfile = logger.logCur @@ -70,11 +70,14 @@ def reportBug(reason="",log=""): session = credentials.sessionHandler - payload = {'title':"CNIRevelator Bug Report", 'body':"**An error has been reported by a CNIRevelator instance.**\n\n**Here is the full reason of this issue:**\n{}\n\n**The full log is here:** {}".format(reason, log), "assignees":["neox95"], "labels":["bug", "AUTO"]} + if not isVoluntary: + payload = {'title':"CNIRevelator Bug Report", 'body':"**An error has been reported by a CNIRevelator instance.**\n\n**Here is the full reason of this issue:**\n{}\n\n**The full log is here:** {}".format(reason, log), "assignees":["neox95"], "labels":["bug", "AUTO"]} + else: + payload = {'title':"CNIRevelator Bug Report", 'body':"**A voluntary bug report has been reported by a CNIRevelator user.**\n\n**Possible reason:**\n{}\n\n**The full log is here:** {}".format(reason, log), "assignees":["neox95"], "labels":["bug", "AUTO"]} handler = session.post('https://api.github.com/repos/neox95/cnirevelator/issues', headers={'Authorization': 'token %s' % decryptToken(globs.CNIRGitToken)}, data=json.dumps(payload)) - logfile.printdbg(handler.reason) + logfile.printdbg("Issue is " + handler.reason) if handler.reason == "Created": return True diff --git a/src/globs.py b/src/globs.py index 14dc82e..efb2971 100644 --- a/src/globs.py +++ b/src/globs.py @@ -26,7 +26,7 @@ import os # CNIRevelator version -verType = "beta release" +verType = "stable release" version = [3, 1, 5] verstring_full = "{}.{}.{} {}".format(version[0], version[1], version[2], verType) verstring = "{}.{}".format(version[0], version[1]) diff --git a/src/ihm.py b/src/ihm.py index 097c9c0..4117d9b 100644 --- a/src/ihm.py +++ b/src/ihm.py @@ -30,7 +30,6 @@ from tkinter import filedialog from tkinter import ttk import PIL.Image, PIL.ImageTk import traceback -import webbrowser import cv2 import critical # critical.py diff --git a/src/lang.py b/src/lang.py index 699596f..0f0914d 100644 --- a/src/lang.py +++ b/src/lang.py @@ -141,7 +141,7 @@ french = \ "Coller :\t\t\t\tCtrl-V \n" "Forcer une nouvelle détection du document :\tEchap\n", -"CHANGELOG" : "Version 3.1.5 \nMise-à-jour mineure avec les progressions suivantes :\n- Correction d'un bug affectant le signalement de bug\n- Améliorations de l'affichage de la conformité des informations\n\n" + \ +"CHANGELOG" : "Version 3.1.5 \nMise-à-jour mineure avec les progressions suivantes :\n- Correction d'un bug affectant le signalement de bug\n- Améliorations de l'affichage de la conformité des informations\n- Ajout d'un nouveau système de selection plus simple et fiable'\n\n" + \ "Version 3.1.4 \nMise-à-jour mineure avec les progressions suivantes :\n- Correction d'un bug affectant la rotation de documents dans l'afficheur d'images\n- Ajout d'une période de mise-à-jour afin d'éviter de rechercher les mises-à-jour tous les jours\n\n" + \ "Version 3.1.3 \nMise-à-jour mineure avec les progressions suivantes :\n- Correction d'un bug de la détection automatique de documents\n- Ajout d'une fonctionnalité de rapport d'erreur\n\n" + \ "Version 3.1.2 \nMise-à-jour mineure avec les progressions suivantes :\n- Montée de version de Tesseract OCR : 5.0\n- Correction de noms des documents\n- Résolution d'un problème avec le système de mise-à-jour\n- Amélioration des effets sur images\n\n" + \ @@ -208,6 +208,9 @@ french = \ "does not contain any non unicode " "character such as accent and " "foreign characters." : "Une erreur critique s'est produite dans le gestionnaire de traitement d'images OpenCV utilisé par CNIRevelator. Veuillez vous assurer que le nom de fichier ne contient pas de caractères non unicode tels que des accents et des caractères étrangers.", +"No Internet Error. No effective " +"update !" : "Aucune connectivité. Pas de mise-à-jour !", +"Project Webpage" : "Site internet du projet", "LANDCODE2" : { 'AW': 'Aruba', @@ -810,6 +813,8 @@ english = \ "the OpenCV image processing " "manager used by CNIRevelator, the " "application will reset itself" : "A critical error has occurred in the OpenCV image processing manager used by CNIRevelator, the application will reset itself", +"No Internet Error. No effective " +"update !" : "No Internet Error. No effective update !", "ABOUT" : 'Software Version: CNIRevelator' + globs.verstring_full + '\n\n' "Copyright © 2018-2019 Adrien Bourmault (neox95)" + "\n\n" @@ -848,7 +853,7 @@ english = \ "Paste:\t\t\t\tCtrl-V\n" "Force a new document detection:\tEchap\n", -"CHANGELOG" : "Version 3.1.5 \nMinor update with the following progressions:\n- Correction of a bug affecting bug reporting\n - Enhancements on information compliance display\n\n" + \ +"CHANGELOG" : "Version 3.1.5 \nMinor update with the following progressions:\n- Correction of a bug affecting bug reporting\n - Enhancements on information compliance display\n- Added new selection system to be more userfriendly\n\n" + \ "Version 3.1.4 \nMinor update with the following progressions:\n- Correction of a bug affecting rotation of document in image viewer\n- Added a new update period to prevent updating everyday\n\n" + \ "Version 3.1.3 \nMinor update with the following progressions:\n- Correction of a bug affecting automated document detection\n- Added bug reporting functionnality\n\n" + \ "Version 3.1.2 \nMinor update with the following progressions: \n- Tesseract OCR version upgrade : 5.0\n- Correction of document names\n- Fixed a problem with the update system\n- Some enhancements about effects on images\n\n" + \ @@ -915,6 +920,7 @@ english = \ "does not contain any non unicode " "character such as accent and " "foreign characters." : "A critical error has occurred in the OpenCV image processing manager used by CNIRevelator. Please be sure that the filename does not contain any non unicode character such as accent and foreign characters.", +"Project Webpage" : "Project website", "LANDCODE2" : { "AW": "Aruba", diff --git a/src/main.py b/src/main.py index 6f4b4dc..a0912e0 100644 --- a/src/main.py +++ b/src/main.py @@ -38,9 +38,9 @@ import re import cv2 import PIL.Image, PIL.ImageTk import os, shutil -import webbrowser import sys, os import numpy +import webbrowser import critical # critical.py import ihm # ihm.py @@ -71,6 +71,7 @@ class mainWindow(Tk): self.Tags = [] self.compliance = True self.corners = [] + self.indicators = [] self.validatedtext = "" # The icon @@ -352,6 +353,7 @@ class mainWindow(Tk): menu3.add_command(label=lang.all[globs.CNIRlang]["Keyboard commands"], command=(self.helpbox)) menu3.add_command(label=lang.all[globs.CNIRlang]["Report a bug"], command=(self.openIssuePage)) menu3.add_separator() + menu3.add_command(label=lang.all[globs.CNIRlang]["Project Webpage"], command=(self.openProjectPage)) menu3.add_command(label=lang.all[globs.CNIRlang]["About CNIRevelator"], command=(self.infobox)) menubar.add_cascade(label=lang.all[globs.CNIRlang]["Help"], menu=menu3) menubar.add_command(label="<|>", command=(self.panelResize)) @@ -410,11 +412,19 @@ class mainWindow(Tk): self.corners.append([canvas.canvasx(event.x), canvas.canvasy(event.y)]) if len(self.corners) == 2: - self.select = self.imageViewer.ZONE.create_rectangle(self.corners[0][0], self.corners[0][1], self.corners[1][0], self.corners[1][1], outline ='cyan', width = 2) + self.select = self.imageViewer.ZONE.create_rectangle(self.corners[0][0], self.corners[0][1], self.corners[1][0], self.corners[1][1], outline ='red', width = 2) #print("Get rectangle : [{}, {}], for [{}, {}]".format(self.corners[0][0], self.corners[0][1], self.corners[1][0], self.corners[1][1])) + + # Reinit if len(self.corners) > 2: self.corners = [] - self.imageViewer.ZONE.delete(self.select) + self.imageViewer.ZONE.delete(self.select) + for k in self.indicators: + self.imageViewer.ZONE.delete(k) + + # Draw indicator + else: + self.indicators.append(self.imageViewer.ZONE.create_oval(canvas.canvasx(event.x)-4, canvas.canvasy(event.y)-4,canvas.canvasx(event.x)+4, canvas.canvasy(event.y)+4, fill='red', outline='red', width = 2)) def goOCRDetection(self): """ @@ -448,10 +458,13 @@ class mainWindow(Tk): cv_img = cv2.resize(cv_img, dim, interpolation = cv2.INTER_AREA) # Crop - x0 = int(self.corners[0][0]) - y0 = int(self.corners[0][1]) - x1 = int(self.corners[1][0]) - y1 = int(self.corners[1][1]) + + coords = self.imageViewer.ZONE.coords(self.select) + + x0 = int(coords[0]) + y0 = int(coords[1]) + x1 = int(coords[2]) + y1 = int(coords[3]) crop_img = cv_img[y0:y1, x0:x1] # Get the text by OCR @@ -724,7 +737,7 @@ class mainWindow(Tk): #print(docInfos) # display the infos for key in [ e for e in docInfos ]: - print(key) + #printkey) if key in ["CODE", "CTRL", "CTRLF", "FACULT", "NOINT"]: continue if not docInfos[key][1] == False: @@ -842,7 +855,7 @@ class mainWindow(Tk): cv_img = cv2.cvtColor(cv_img, cv2.COLOR_BGR2RGB) except: logfile.printerr("Error with : {} in {} with total of {} pages".format(cv2.imreadmulti(self.imageViewer.imagePath), self.imageViewer.imagePath, total)) - showerror(lang.all[globs.CNIRlang]["OpenCV error (image processing)"], lang.all[globs.CNIRlang]["A critical error has occurred in the OpenCV image processing manager used by CNIRevelator. Please be sure that the filename does not contain any non unicode character such as accent and foreign characters."] + "\n\n" + self.imageViewer.imagePath) + critical.crashCNIR(False, "OpenCV openScanFile() error") try: # Get the image dimensions (OpenCV stores image data as NumPy ndarray) @@ -855,6 +868,10 @@ class mainWindow(Tk): # Get the image dimensions (OpenCV stores image data as NumPy ndarray) height, width = cv_img.shape + + # Update shape + self.imageViewer.height, self.imageViewer.width = cv_img.shape[:2] + # Use PIL (Pillow) to convert the NumPy ndarray to a PhotoImage photo = PIL.ImageTk.PhotoImage(image = PIL.Image.fromarray(cv_img)) self.DisplayUpdate(photo) @@ -865,7 +882,7 @@ class mainWindow(Tk): self.resizeScan() def zoomOutScan50(self, quantity = 50): - if self.imageViewer.image: + if self.imageViewer.image and int(self.imageViewer.width * (self.imageViewer.imgZoom - quantity + 100) / 100) > 100: self.imageViewer.imgZoom -= quantity self.resizeScan() @@ -875,7 +892,7 @@ class mainWindow(Tk): self.resizeScan() def zoomOutScan20(self, quantity = 20): - if self.imageViewer.image: + if self.imageViewer.image and int(self.imageViewer.width * (self.imageViewer.imgZoom - quantity + 100) / 100) > 100: self.imageViewer.imgZoom -= quantity self.resizeScan() @@ -885,7 +902,7 @@ class mainWindow(Tk): self.resizeScan() def zoomOutScan(self, quantity = 1): - if self.imageViewer.image: + if self.imageViewer.image and int(self.imageViewer.width * (self.imageViewer.imgZoom - quantity + 100) / 100) > 100: self.imageViewer.imgZoom -= quantity self.resizeScan() @@ -997,6 +1014,9 @@ class mainWindow(Tk): dim = (int(width * (self.imageViewer.imgZoom + 100) / 100), int(height * (self.imageViewer.imgZoom + 100) / 100)) cv_img = cv2.resize(cv_img, dim, interpolation = cv2.INTER_AREA) + # Update shape + self.imageViewer.height, self.imageViewer.width = cv_img.shape[:2] + # Use PIL (Pillow) to convert the NumPy ndarray to a PhotoImage photo = PIL.ImageTk.PhotoImage(image = PIL.Image.fromarray(cv_img)) self.DisplayUpdate( photo) @@ -1019,7 +1039,7 @@ class mainWindow(Tk): self.DisplayUpdate(photo) except Exception as e: logfile.printerr("Critical error with opencv : ".format(e)) - showerror(lang.all[globs.CNIRlang]["OpenCV error (image processing)"], lang.all[globs.CNIRlang]["A critical error has occurred in the OpenCV image processing manager used by CNIRevelator, the application will reset itself"]) + critical.crashCNIR(False, "OpenCV resizeScan() error") self.initialize() ## IHM and user interface related functions @@ -1058,9 +1078,15 @@ class mainWindow(Tk): def openIssuePage(self): """ - Opens the Github Issue Repository page + Sends a bug report """ - webbrowser.open_new("https://github.com/neox95/CNIRevelator/issues") + critical.crashCNIR(shutdown=False, option="Voluntary Bug Report", isVoluntary=True) + + def openProjectPage(self): + """ + Opens the Project Repository webpage + """ + webbrowser.open_new("https://github.com/neox95/CNIRevelator") def showChangeLog(self): changelogWin = ihm.ChangelogDialog(self, ('{} : CNIRevelator {}\n\n{}'.format(lang.all[globs.CNIRlang]["Program version"], globs.verstring_full, lang.all[globs.CNIRlang]["CHANGELOG"]))) diff --git a/src/pytesseract.py b/src/pytesseract.py index 095eb1f..e73562a 100644 --- a/src/pytesseract.py +++ b/src/pytesseract.py @@ -24,7 +24,7 @@ * along with CNIRevelator. If not, see . * ******************************************************************************** """ - +import logger # logger.pu try: import Image @@ -248,7 +248,7 @@ def image_to_string(image, lang=None, config='', nice=0, boxes=False, output_typ Returns the result of a Tesseract OCR run on the provided image to string """ if boxes: - print("\nWarning: Argument 'boxes' is deprecated and will be removed in future versions. Use function image_to_boxes instead.\n") + logfile.printdbg("\nWarning: Argument 'boxes' is deprecated and will be removed in future versions. Use function image_to_boxes instead.\n") return image_to_boxes(image, lang, config, nice, output_type) else: args = [ @@ -317,7 +317,7 @@ def main(): sys.stderr.write('Usage: python pytesseract.py [-l lang] input_file\n') exit(2) try: - print(image_to_string((Image.open(filename)), lang=lang)) + logfile.printdbg(image_to_string((Image.open(filename)), lang=lang)) except IOError: sys.stderr.write('ERROR: Could not open file "%s"\n' % filename) exit(1) diff --git a/src/updater.py b/src/updater.py index 5d62988..bd864c6 100644 --- a/src/updater.py +++ b/src/updater.py @@ -378,8 +378,12 @@ def umain(): credentials = downloader.newcredentials() if not credentials.valid: - logfile.printerr("Credentials Error. No effective update !") - launcherWindow.printmsg(lang.all[globs.CNIRlang]["Credentials Error. No effective update !"]) + if credentials.login == "nointernet": + logfile.printerr("No Internet Error. No effective update !") + launcherWindow.printmsg(lang.all[globs.CNIRlang]["No Internet Error. No effective update !"]) + else: + logfile.printerr("Credentials Error. No effective update !") + launcherWindow.printmsg(lang.all[globs.CNIRlang]["Credentials Error. No effective update !"]) time.sleep(2) launcherWindow.exit() return 0 From 01b4a6ea4bcb9accfd9e33f76eb1a67346fbca8c Mon Sep 17 00:00:00 2001 From: Adrien Bourmault Date: Fri, 30 Aug 2019 11:21:17 +0200 Subject: [PATCH 10/10] Update VERSIONS.LST --- VERSIONS.LST | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/VERSIONS.LST b/VERSIONS.LST index 4bbf951..9593480 100644 --- a/VERSIONS.LST +++ b/VERSIONS.LST @@ -1,2 +1,2 @@ # ver|url|checksum, and | as separator, one version per || -3.1.5|https://github.com/neox95/CNIRevelator/releases/download/3.1.5a/CNIRevelator.zip|afbcbef376ea6c21f5a7cf15cc210afc24616b2b|| +3.1.5|https://github.com/neox95/CNIRevelator/releases/download/3.1.5b/CNIRevelator.zip|5bdaf4042c5d6474bf9f87b43db6516f532938cf||