Merge pull request #1 from neox95/v3.0

v3.0 to master
This commit is contained in:
Adrien Bourmault 2019-07-08 16:28:10 +02:00 committed by GitHub
commit 3e2990dd82
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
23 changed files with 2783 additions and 2725 deletions

6
.gitignore vendored Normal file
View File

@ -0,0 +1,6 @@
*.pyc
*.log
*.spec
build/*
dist/*

View File

@ -1,50 +0,0 @@
"""
********************************************************************************
*** Projet CNI_Revelator ***
GNU GPL * 07/2018
Adrien Bourmault
VARIABLES
********************************************************************************
"""
CST_REV = "8"
CST_VERTITLE = "2.2"
CST_TAB_VER = ["2","2","1"]
CST_VER = "{0}.{1}.{2}".format(CST_TAB_VER[0], CST_TAB_VER[1], CST_TAB_VER[2])
CST_TYPE = "Final Release"
CST_NAME = "CNIRevelator"
CST_TITLE = CST_NAME + " " + CST_VER + " - GNU/GPL Licensing 2018"
CST_MARK = CST_NAME + " " + CST_TYPE + " " + CST_VER + " - by NeoX, GNU/GPL Licensing 2018"
CST_SUM_VER = int(CST_TAB_VER[0])*100 + int(CST_TAB_VER[1])*10 + int(CST_TAB_VER[2])
CST_LINK = <lien vers serveur>
CST_COLOR = "#003380"
import base64
import hashlib
from Crypto import Random
from Crypto.Cipher import AES
from tkinter import *
from tkinter.messagebox import *
from tkinter import filedialog
from tkinter import ttk as ttk
import os
import time
import threading
import sys
import urllib.request as urllib2
import urllib.error as URLExcept
import random
from pypac import PACSession
from requests.auth import HTTPProxyAuth
import subprocess
from datetime import datetime
from PIL import Image, ImageFont, ImageDraw, ImageTk, ImageEnhance, ImageFilter
import math
import warnings
import string
CST_FOLDER = os.getenv('APPDATA') + "/CNIRevelator/"

View File

@ -1,131 +0,0 @@
"""
********************************************************************************
*** Projet CNI_Revelator ***
GNU GPL * 07/2018
Adrien Bourmault
main
********************************************************************************
"""
###IMPORTS GLOBAUX
from CNI_GLOBALVAR import *
##LOGGING
try:
os.remove("error.log")
os.remove("conf.ig")
except:
pass
import logging
CST_NIVEAU_LOG = logging.ERROR
from logging.handlers import RotatingFileHandler
# création de l'objet logger qui va nous servir à écrire dans les logs
logger = logging.getLogger()
# on met le niveau du logger à DEBUG, comme ça il écrit tout
logger.setLevel(CST_NIVEAU_LOG)
# création d'un formateur qui va ajouter le temps, le niveau
# de chaque message quand on écrira un message dans le log
formatter = logging.Formatter('%(asctime)s :: %(levelname)s :: %(message)s')
# création d'un handler qui va rediriger une écriture du log vers
# un fichier en mode 'append', avec 1 backup et une taille max de 1Mo
file_handler = RotatingFileHandler('error.log', 'a', 1000000, 1)
# on lui met le niveau sur DEBUG, on lui dit qu'il doit utiliser le formateur
# créé précédement et on ajoute ce handler au logger
file_handler.setLevel(CST_NIVEAU_LOG)
file_handler.setFormatter(formatter)
logger.addHandler(file_handler)
##History
### IMPORTS LOCAUX
from CNI_classes import *
from CNI_Update import *
### FONCTION PRINCIPALE
def main(logger):
logger.info("main() : " +"**** Creating App_main() ****")
main_w = App_main(logger)
main_w.montext("* " + CST_NAME + " " + CST_VER + " " + CST_TYPE + " Revision " + CST_REV + " *\n")
import CNI_pytesseract as pytesseract
try:
os.environ["PATH"] = CST_FOLDER + "Tesseract-OCR4\\"
os.environ["TESSDATA_PREFIX"] = CST_FOLDER + "Tesseract-OCR4\\tessdata"
tesser_version = pytesseract.get_tesseract_version()
except Exception as e:
logger.error("main() : " +"**** ERROR WITH TESSERACT MODULE " + str(e) + " ****")
else:
text = "Tesseract version " + str(tesser_version) +" Licensed Apache 2004 successfully initiated\n"
main_w.montext(text)
main_w.montext("\n\nEntrez la première ligne de MRZ svp \n")
logger.info("main() : " +"**** Launching App_main() ****")
main_w.mainloop()
logger.info("main() : " +"**** Ending App_main() ****")
##Launcher
logger.info("launcher : " + CST_NAME +" "+ CST_VER)
logger.info("launcher : " +"*****Hello World*****")
logger.info("launcher : " +"*****Launching SoftUpdate()*****")
try:
Answer = SoftUpdate(logger)
except Exception as e:
logger.info("launcher : " +"*****FATAL ERROR*****" + str(e))
os.abort()
logger.info("launcher : " +"*****Ending SoftUpdate()*****")
try:
if Answer == True:
logger.info("launcher : " +"*****Launching main()*****")
State = main(logger)
except Exception as e:
logger.info("launcher : " +"*****FATAL ERROR*****" + str(e))
os.abort()
logger.info("launcher : " +"*****Ending main()*****")
logger.info("launcher : " +"*****Goodbye!*****")
handlers = logger.handlers[:]
for handler in handlers:
handler.close()
logger.removeHandler(handler)
if os.path.getsize("error.log") == 0:
try:
os.remove("error.log")
except:
raise(OSError)
os.abort()
sys.exit(0)

View File

@ -1,568 +0,0 @@
"""
********************************************************************************
*** Projet CNI_Revelator ***
GNU GPL * 07/2018
Adrien Bourmault
UPDATE
********************************************************************************
"""
###IMPORTS GLOBAUX
from CNI_GLOBALVAR import *
###IMPORTS LOCAUX
from CNI_classes import *
###BEGIN
def SoftUpdate(logger): #Fonction de mise à jour de l'application
import zipfile
# zip_ref = zipfile.ZipFile(path_to_zip_file, 'r')
# zip_ref.extractall(directory_to_extract_to)
# zip_ref.close()
logger.info("SoftUpdate() : " +"Verifying local data dir...")
if not os.path.exists(CST_FOLDER):
os.makedirs(CST_FOLDER)
logger.info("SoftUpdate() : " +"Data dir created !")
logger.info("SoftUpdate() : " +"Looking for older version in dir...")
list = os.listdir('.')
for file in list:
if file.startswith("CNIRevelator_"):
temp = ["0","0","0"]
ver = file[13:].split(".")
for i in range(len(ver)):
if ver[i] != "exe" :
try:
temp[i] = ver[i]
except:
None
ver = temp.copy()
try :
sum_ver = int(ver[0])*100 + int(ver[1])*10 + int(ver[2])
if sum_ver < CST_SUM_VER:
os.remove(file)
logger.info("SoftUpdate() : " + "Removed old version : " + str(file) )
except:
logger.error("SoftUpdate() : " +"Failing to remove old version : " + str(file) )
None
def updating(): #Fonction de lancement du thread de maj
def updator(): #Fonction d'exécution de la maj
logger.info("[updator() thread] : " + "Welcome !")
global ret
ret = 11
canvas.itemconfigure(message, text="Recherche de mises-à-jour...")
p.configure(mode = "indeterminate", value = 0, maximum = 20)
p.start()
upwin.update()
logger.info("[updator() thread] : " + "Looking for updates...")
try:#Essai par proxy
def download(url, filename):
try: # if identifiants disponibles dans un fichier
logger.info("[download() thread] : " + "Trying getting credentials in the config file")
with open(CST_FOLDER +'conf.ig', "rb") as config:
AESObj = AESCipher("<clé>")
IPN, IPN_PASS = AESObj.decrypt(config.read()).split("||")[0:2]
logger.info("[download() thread] : " + "Got credentials !")
session = PACSession(proxy_auth=HTTPProxyAuth(IPN, IPN_PASS))
logger.info("[download() thread] : " + "Authenticated to proxy successfully")
except IOError as e: #Else : on vérifie les identifiants de proxy
logger.error("[download() thread] : " + "False or absent credentials in the config file : " + str(e))
NoConnect = True
while NoConnect:
class LoginDialog(Toplevel):
global login
global key
def __init__(self, parent):
super().__init__(parent)
self.title("Connexion")
# ---------------------------------------
Label(self, text="IPN : ").pack()
self.entry_login = Entry(self)
self.entry_login.insert(0, "")
self.entry_login.pack()
# ---------------------------------------
Label(self, text="Mot de passe : ").pack()
self.entry_pass = Entry(self, show='*')
self.entry_pass.insert(0, "")
self.entry_pass.pack()
# ---------------------------------------
Button(self, text="Connexion", command=self.connecti).pack()
self.resizable(width=False, height=False)
#taille souhaite de la fenetre
w = 150
h = 110
#pour centrer la fenetre
#taille de l'ecran
self.update()
ws = self.winfo_screenwidth()
hs = self.winfo_screenheight()
if getattr( sys, 'frozen', False ) :
self.iconbitmap(sys._MEIPASS + "\id-card.ico\id-card.ico")
else:
self.iconbitmap("id-card.ico")
upwin.update()
#calcul la position de la fenetre
x = (ws/2) - (w/2)
y = (hs/2) - (h/2)
#applique la taille et la position
self.geometry('%dx%d+%d+%d' % (w, h, x, y))
def connecti(self):
global login
global key
login = self.entry_login.get().strip()
key = self.entry_pass.get().strip()
self.destroy()
session = PACSession()
if session.get_pac() == None:
IPN = ""
IPN_PASS = ""
NoConnect = False
break
canvas.itemconfigure(message, text="En attente de connexion au serveur proxy...")
global login
global key
login = ""
key = ""
result = LoginDialog(upwin)
result.transient(upwin)
result.grab_set()
upwin.wait_window(result)
IPN = login
IPN_PASS = key
session = PACSession(proxy_auth=HTTPProxyAuth(IPN, IPN_PASS))
Ans = session.get("http://www.google.com")
if str(Ans) == "<Response [407]>":
canvas.itemconfigure(message, text="Identifiants erronés, accès refusé")
logger.info("[download() thread] : " + "407 Error")
time.sleep(1)
elif str(Ans) == "<Response [200]>":
logger.info("[download() thread] : " + "Connection ok !")
NoConnect = False
else:
raise(IOError())
AESObj = AESCipher("<clé>")
with open(CST_FOLDER +"conf.ig","wb+") as f:
logger.info("[download() thread] : " + "Saving credentials in encrypted config file")
f.write(AESObj.encrypt(IPN + "||" + IPN_PASS))
if IPN == "i005316":
canvas.itemconfigure(message, text="Bienvenue Thierry !")
elif IPN == "i020251":
canvas.itemconfigure(message, text="Bienvenue Samia !")
elif IPN == "i018410":
canvas.itemconfigure(message, text="Bienvenue Adrien !")
elif IPN == "i003067":
canvas.itemconfigure(message, text="Bienvenue Remy !")
elif IPN == "i018422":
canvas.itemconfigure(message, text="Bienvenue Eloise !")
time.sleep(1)
try:
Prox_us = session.get_pac().find_proxy_for_url(CST_LINK,"neoxgroup.eu")
PROXY_USABLE = Prox_us[6:-1].split(";")[0]
proxy_server_url = IPN +":"+IPN_PASS+"@" + PROXY_USABLE
ph = urllib2.ProxyHandler( { 'http' : proxy_server_url } )
auth = urllib2.ProxyBasicAuthHandler()
server= urllib2.build_opener( ph, auth, urllib2.HTTPHandler )
urllib2.install_opener(server)
logger.info("[download() thread] : " + "Proxy connection initiated successfully")
except:
logger.info("[download() thread] : " + "Proxy connection not initiated")
try:
urllib2.urlretrieve(url, filename)
return True
except Exception as e:
logger.error("[download() thread] : " + "HTTP ERROR " )
return e
##updator()
logger.info("[updator() thread] : " + "Prepare downloading the version recap file...")
tempfile = CST_FOLDER + 'temp' + str(random.randint(11111,99999)) + ".cniu"
isOk = download(CST_LINK+"Version.txt", tempfile)
if not isOk:
raise(isOk)
urllib2.urlcleanup()
logger.info("[updator() thread] : " + "Opening version recap file...")
file_ver = open(tempfile, "r")
logger.info("[updator() thread] : " + "Reading version recap file...")
version = file_ver.read()
logger.info("[updator() thread] : " + "Closing version recap file...")
repert = version.split("|")
file_ver.close()
logger.info("[updator() thread] : " + "Deleting version recap file...")
os.remove(tempfile)
logger.info("[updator() thread] : " + "Parsing informations about version...")
final_f = "CNI_file"
final_ver = ['0','0','0']
for file in repert:
if str.startswith(file,CST_NAME): #On prend les fichiers d'interêt du répertoire
ver = file.replace(CST_NAME+"_","").split(".") #On ne garde que le numéro de version
temp = ["0","0","0"]
for i in range(len(ver)):
temp[i] = ver[i]
ver = temp.copy()
sum_fver = int(final_ver[0])*100 + int(final_ver[1])*10 + int(final_ver[2])
sum_ver = int(ver[0])*100 + int(ver[1])*10 + int(ver[2])
if sum_ver > sum_fver:
final_ver = ver.copy()
final_f = file
sum_ver = int(final_ver[0])*100 + int(final_ver[1])*10 + int(final_ver[2])
if final_f != "CNI_file" and (sum_ver > CST_SUM_VER):
#On a une maj
logger.info("[updator() thread] : " + "New version of CNIRevelator found !")
canvas.itemconfigure(message, text="Mise à jour disponible ! Préparation du téléchargement...")
logger.info("[updator() thread] : " + "Preparing download")
with open(CST_FOLDER +'conf.ig', "rb") as config:
logger.info("[updator() thread] : " + "Reading credentials for proxy in config file...")
AESObj = AESCipher("<clé>")
IPN, IPN_PASS = AESObj.decrypt(config.read()).split("||")[0:2]
session = PACSession(proxy_auth=HTTPProxyAuth(IPN, IPN_PASS))
try:
Prox_us = session.get_pac().find_proxy_for_url(CST_LINK,"neoxgroup.eu")
PROXY_USABLE = Prox_us[6:-1].split(";")[0]
proxy_server_url = IPN +":"+IPN_PASS+"@" + PROXY_USABLE
ph = urllib2.ProxyHandler( { 'http' : proxy_server_url } )
auth = urllib2.ProxyBasicAuthHandler()
server= urllib2.build_opener( ph, auth, urllib2.HTTPHandler )
logger.info("[updator() thread] : " + "Connection to the proxy initiated successfully !")
except:
canvas.itemconfigure(message, text="Téléchargement en connexion directe...")
server= urllib2.build_opener()
logger.info("[updator() thread] : " + "Direct connection initiated successfully")
logger.info("[updator() thread] : " + "Launching download of " + final_f)
Statut = Download( CST_LINK + final_f, final_f, final_f, server, p, canvas, message, logger )
if Statut.success:
try:
os.rename(final_f, final_f + ".exe")
except IOError:
logger.error("[updator() thread] : " + "Unable to rename the file ! Wait 3 sec and retry")
time.sleep(3)
try:
os.rename(final_f, final_f + ".exe")
except IOError:
logger.critical("[updator() thread] : " + "Unable to rename the file !")
else:
canvas.itemconfigure(message, text="Téléchargement terminé ! Préparation du lancement...")
logger.info("[updator() thread] : " + "Download of " + final_f + "finished successfully")
p.configure(mode = "indeterminate", value = 0, maximum = 20)
p.start()
time.sleep(1)
logger.info("[updator() thread] : " + "Launching " + final_f)
try:
proc = subprocess.Popen(final_f + ".exe", shell=False,stdin=None, stdout=None, stderr=None, close_fds=True)
except:
logger.error("[updator() thread] : " + "Unable to start the new version ! Wait 3 sec and retry")
time.sleep(3)
try:
proc = subprocess.Popen(final_f + ".exe", shell=False,stdin=None, stdout=None, stderr=None, close_fds=True)
except Exception as e:
logger.critical("[updator() thread] : " + "Unable to start the new version ! Stopping : " + str(e))
showerror("Erreur d'appel de procédure distante", "Le lancement du nouveau programme a échoué, vous devez le lancer manuellement une fois cette fenêtre fermée")
ret = 12
else:
canvas.itemconfigure(message, text="Echec de la mise à jour : Erreur HTTP. Préparation du lancement...")
logger.error("[updator() thread] : " + "Update has failed with HTTP error")
time.sleep(1)
else:
canvas.itemconfigure(message, text="Logiciel déjà à jour. Préparation du lancement...")
logger.info("[updator() thread] : " + "CNIRevelator is up to date !")
time.sleep(1)
ret = 11
#Tesseract
if os.path.exists(CST_FOLDER + "Tesseract-OCR4\\tesseract.exe"):
os.environ["PATH"] = CST_FOLDER + "Tesseract-OCR4\\"
os.environ["TESSDATA_PREFIX"] = CST_FOLDER + "Tesseract-OCR4\\tessdata"
else:
final_f = "tesseract_4"
#On a une maj
logger.info("[updator() thread] : " + "Downloading tesseract 4 !")
canvas.itemconfigure(message, text="Mise à jour du module OCR ! Préparation du téléchargement...")
logger.info("[updator() thread] : " + "Preparing download")
with open(CST_FOLDER +'conf.ig', "rb") as config:
logger.info("[updator() thread] : " + "Reading credentials for proxy in config file...")
AESObj = AESCipher("<clé>")
IPN, IPN_PASS = AESObj.decrypt(config.read()).split("||")[0:2]
session = PACSession(proxy_auth=HTTPProxyAuth(IPN, IPN_PASS))
try:
Prox_us = session.get_pac().find_proxy_for_url(CST_LINK,"neoxgroup.eu")
PROXY_USABLE = Prox_us[6:-1].split(";")[0]
proxy_server_url = IPN +":"+IPN_PASS+"@" + PROXY_USABLE
ph = urllib2.ProxyHandler( { 'http' : proxy_server_url } )
auth = urllib2.ProxyBasicAuthHandler()
server= urllib2.build_opener( ph, auth, urllib2.HTTPHandler )
logger.info("[updator() thread] : " + "Connection to the proxy initiated successfully !")
except:
canvas.itemconfigure(message, text="Téléchargement en connexion directe...")
server= urllib2.build_opener()
logger.info("[updator() thread] : " + "Direct connection initiated successfully")
logger.info("[updator() thread] : " + "Launching download of " + final_f)
Statut = Download( CST_LINK + final_f, CST_FOLDER + final_f, final_f, server, p, canvas, message, logger )
if Statut.success:
canvas.itemconfigure(message, text="Téléchargement terminé ! Installation...")
logger.info("[updator() thread] : " + "Download of " + final_f + "finished successfully")
p.configure(mode = "indeterminate", value = 0, maximum = 20)
p.start()
try:
zip_ref = zipfile.ZipFile(CST_FOLDER + final_f, 'r')
zip_ref.extractall(CST_FOLDER)
zip_ref.close()
os.environ["PATH"] = CST_FOLDER + "Tesseract-OCR4\\"
os.environ["TESSDATA_PREFIX"] = CST_FOLDER + "Tesseract-OCR4\\tessdata"
canvas.itemconfigure(message, text="Installation terminée !")
except:
logger.error("[updator() thread] : " + "Unable to install the module. Wait and retry")
time.sleep(3)
try:
zip_ref = zipfile.ZipFile(CST_FOLDER + final_f, 'r')
zip_ref.extractall(CST_FOLDER)
zip_ref.close()
os.environ["PATH"] = CST_FOLDER + "Tesseract-OCR4\\"
os.environ["TESSDATA_PREFIX"] = CST_FOLDER + "Tesseract-OCR4\\tessdata"
canvas.itemconfigure(message, text="Installation terminée !")
except Exception as e:
logger.critical("[updator() thread] : " + "Unable to install the module ! Stopping : " + str(e))
showerror("Erreur d'appel de procédure distante", "L'installation du module OCR a échoué, contactez le développeur.")
ret = 11
else:
logger.critical("[updator() thread] : " + "Unable to download the module ! ")
showerror("Erreur de téléchargement", "L'installation du module OCR a échoué, merci d'indiquer le chemin d'accès au fichier tesseract_4 dans la fenêtre suivante")
path = filedialog.askopenfilename(title = "Indiquez le chemin d'accès à tesseract_4...",filetypes = (("Tesseract_4","*.cni4"), ("Tesseract_4","*.cni4")))
if path != "":
try:
canvas.itemconfigure(message, text="Installation...")
zip_ref = zipfile.ZipFile(path, 'r')
zip_ref.extractall(CST_FOLDER)
zip_ref.close()
logger.error("[updator() thread] : " + "Manual installation successed")
canvas.itemconfigure(message, text="Installation terminée !")
os.environ["PATH"] = CST_FOLDER + "Tesseract-OCR4\\"
os.environ["TESSDATA_PREFIX"] = CST_FOLDER + "Tesseract-OCR4\\tessdata"
except Exception as e:
logger.error("[updator() thread] : " + "Manual installation has failed" + str(e) )
showerror("Erreur de lecture", "Le module OCR n'a pas pu être installé, la saisie automatique de scans ne pourra donc fonctionner")
else:
showerror("Opération annulée", "Le module OCR n'a été installé, la saisie automatique de scans ne pourra donc fonctionner")
except URLExcept.HTTPError as e:
canvas.itemconfigure(message, text="Echec de la mise à jour : Erreur HTTP " + str(e.code) + " . Préparation du lancement...")
logger.error("[updator() thread] : " + "Update has failed with HTTP error" + str(e.code) )
if int(e.code) == 407:
showerror("Erreur 407", "Attention : le système de mise à jour automatique a fait face à une erreur 407, signifiant que la connexion au serveur proxy a été refusée. Vos identifiants vous seront redemandés au prochain démarrage. La mise à jour a échoué.")
logger.info("[updator() thread] : " + "Credential error. Deleting the config file...")
os.remove(CST_FOLDER +"conf.ig")
p.configure(mode = "indeterminate", value = 0, maximum = 20)
p.start()
time.sleep(3)
except Exception as e:
canvas.itemconfigure(message, text="Echec de la mise à jour. Préparation du lancement...")
logger.error("[updator() thread] : " + "Error from the updating system : " + str(e))
p.configure(mode = "indeterminate", value = 0, maximum = 20)
p.start()
time.sleep(2)
p.stop()
upwin.destroy()
root.destroy()
return ret
##updating()
global ret
logger.info("updating() : " + "Launching updator() thread...")
threading.Thread(target=updator, daemon=True).start()
logger.info("updating() [Thread] : " + "Ending updator() thread")
return None
##SoftUpdate()
global ret
ret = 11
global upwin
root = Tk()
root.attributes('-alpha', 0.0) #For icon
#root.lower()
root.iconify()
upwin = Toplevel(root)
upwin.overrideredirect(1)
upwin.configure(bg = CST_COLOR)
upwin.resizable(width=False, height=False)
#taille souhaite de la fenetre
w = 600
h = 300
#pour centrer la fenetre
#taille de l'ecran
upwin.update()
canvas = Canvas(upwin, width=600, height=270, bg=CST_COLOR, highlightthickness=0)
pbar = Canvas(upwin, width=600, height=30, bg=CST_COLOR)
p = ttk.Progressbar(pbar, orient=HORIZONTAL, length=590, mode='determinate')
upwin.update()
ws = upwin.winfo_screenwidth()
hs = upwin.winfo_screenheight()
canvas.create_text(w/2, h/3, text=CST_NAME + " " + CST_VERTITLE, font="Calibri 30 bold", fill="white")
message = canvas.create_text(w/2, h/1.150, text=" ", font="Calibri 9", fill="white")
upwin.update()
#calcul la position de la fenetre
x = (ws/2) - (w/2)
y = (hs/2) - (h/2)
#applique la taille et la position
upwin.geometry('%dx%d+%d+%d' % (w, h, x, y))
canvas.grid()
pbar.grid()
p.grid()
upwin.after(2000, updating)
if getattr( sys, 'frozen', False ) :
root.iconbitmap(sys._MEIPASS + "\id-card.ico\id-card.ico")
else:
root.iconbitmap("id-card.ico")
# On démarre la boucle Tkinter qui s'interrompt quand on ferme la fenêtre
logger.info("SoftUpdate() : " + "Entering upwin mainloop()")
upwin.protocol('WM_DELETE_WINDOW', lambda: root.destroy())
upwin.mainloop()
logger.info("SoftUpdate() : " + "Exiting upwin mainloop()")
if ret == 11:
logger.info("SoftUpdate() : " + "OK to start to main() normally !")
return True
else:
logger.info("SoftUpdate() : " + "Program will stop !")
return False

File diff suppressed because one or more lines are too long

View File

@ -1,413 +0,0 @@
"""
********************************************************************************
*** Projet CNI_Revelator ***
GNU GPL * 07/2018
Adrien Bourmault
Pytesseract modification to comply with Pyinstaller
*****
"""
#!/usr/bin/env python
'''
Python-tesseract. For more information: https://github.com/madmaze/pytesseract
'''
try:
import Image
except ImportError:
from PIL import Image
import os
import sys
import subprocess
import tempfile
import shlex
import string
from glob import iglob
from pkgutil import find_loader
from distutils.version import LooseVersion
from os.path import realpath, normpath, normcase
numpy_installed = find_loader('numpy') is not None
if numpy_installed:
from numpy import ndarray
# CHANGE THIS IF TESSERACT IS NOT IN YOUR PATH, OR IS NAMED DIFFERENTLY
tesseract_cmd = 'tesseract'
RGB_MODE = 'RGB'
OSD_KEYS = {
'Page number': ('page_num', int),
'Orientation in degrees': ('orientation', int),
'Rotate': ('rotate', int),
'Orientation confidence': ('orientation_conf', float),
'Script': ('script', str),
'Script confidence': ('script_conf', float)
}
class Output:
STRING = "string"
BYTES = "bytes"
DICT = "dict"
class TesseractError(RuntimeError):
def __init__(self, status, message):
self.status = status
self.message = message
self.args = (status, message)
class TesseractNotFoundError(EnvironmentError):
def __init__(self):
super(TesseractNotFoundError, self).__init__(
tesseract_cmd + " is not installed or it's not in your path"
)
class TSVNotSupported(EnvironmentError):
def __init__(self):
super(TSVNotSupported, self).__init__(
'TSV output not supported. Tesseract >= 3.05 required'
)
def run_once(func):
def wrapper(*args, **kwargs):
if wrapper._result is wrapper:
wrapper._result = func(*args, **kwargs)
return wrapper._result
wrapper._result = wrapper
return wrapper
def get_errors(error_string):
return u' '.join(
line for line in error_string.decode('utf-8').splitlines()
).strip()
def cleanup(temp_name):
''' Tries to remove files by filename wildcard path. '''
for filename in iglob(temp_name + '*' if temp_name else temp_name):
try:
os.remove(filename)
except OSError:
pass
def prepare(image):
if isinstance(image, Image.Image):
return image
if numpy_installed and isinstance(image, ndarray):
return Image.fromarray(image)
raise TypeError('Unsupported image object')
def save_image(image):
temp_name = tempfile.mktemp(prefix='tess_')
if isinstance(image, str):
return temp_name, realpath(normpath(normcase(image)))
image = prepare(image)
img_extension = image.format
if image.format not in {'JPEG', 'PNG', 'TIFF', 'BMP', 'GIF'}:
img_extension = 'PNG'
if not image.mode.startswith(RGB_MODE):
image = image.convert(RGB_MODE)
if 'A' in image.getbands():
# discard and replace the alpha channel with white background
background = Image.new(RGB_MODE, image.size, (255, 255, 255))
background.paste(image, (0, 0), image)
image = background
input_file_name = temp_name + os.extsep + img_extension
image.save(input_file_name, format=img_extension, **image.info)
return temp_name, input_file_name
def subprocess_args(include_stdout=True):
# The following is true only on Windows.
if hasattr(subprocess, 'STARTUPINFO'):
# On Windows, subprocess calls will pop up a command window by default
# when run from Pyinstaller with the ``--noconsole`` option. Avoid this
# distraction.
si = subprocess.STARTUPINFO()
si.dwFlags |= subprocess.STARTF_USESHOWWINDOW
# Windows doesn't search the path by default. Pass it an environment so
# it will.
env = os.environ
else:
si = None
env = None
# ``subprocess.check_output`` doesn't allow specifying ``stdout``::
#
# Traceback (most recent call last):
# File "test_subprocess.py", line 58, in <module>
# **subprocess_args(stdout=None))
# File "C:\Python27\lib\subprocess.py", line 567, in check_output
# raise ValueError('stdout argument not allowed, it will be overridden.')
# ValueError: stdout argument not allowed, it will be overridden.
#
# So, add it only if it's needed.
if include_stdout:
ret = {'stdout': subprocess.PIPE}
else:
ret = {}
# On Windows, running this from the binary produced by Pyinstaller
# with the ``--noconsole`` option requires redirecting everything
# (stdin, stdout, stderr) to avoid an OSError exception
# "[Error 6] the handle is invalid."
ret.update({'stdin': subprocess.PIPE,
'stderr': subprocess.PIPE,
'startupinfo': si,
'env': env
})
return ret
return kwargs
def run_tesseract(input_filename,
output_filename_base,
extension,
lang,
config='',
nice=0):
cmd_args = []
if not sys.platform.startswith('win32') and nice != 0:
cmd_args += ('nice', '-n', str(nice))
cmd_args += (tesseract_cmd, input_filename, output_filename_base)
if lang is not None:
cmd_args += ('-l', lang)
cmd_args += shlex.split(config)
if extension not in ('box', 'osd', 'tsv'):
cmd_args.append(extension)
try:
proc = subprocess.Popen(cmd_args, **subprocess_args())
except OSError:
raise TesseractNotFoundError()
status_code, error_string = proc.wait(), proc.stderr.read()
proc.stderr.close()
if status_code:
raise TesseractError(status_code, get_errors(error_string))
return True
def run_and_get_output(image,
extension,
lang=None,
config='',
nice=0,
return_bytes=False):
temp_name, input_filename = '', ''
try:
temp_name, input_filename = save_image(image)
kwargs = {
'input_filename': input_filename,
'output_filename_base': temp_name + '_out',
'extension': extension,
'lang': lang,
'config': config,
'nice': nice
}
run_tesseract(**kwargs)
filename = kwargs['output_filename_base'] + os.extsep + extension
with open(filename, 'rb') as output_file:
if return_bytes:
return output_file.read()
return output_file.read().decode('utf-8').strip()
finally:
cleanup(temp_name)
def file_to_dict(tsv, cell_delimiter, str_col_idx):
result = {}
rows = [row.split(cell_delimiter) for row in tsv.split('\n')]
if not rows:
return result
header = rows.pop(0)
if len(rows[-1]) < len(header):
# Fixes bug that occurs when last text string in TSV is null, and
# last row is missing a final cell in TSV file
rows[-1].append('')
if str_col_idx < 0:
str_col_idx += len(header)
for i, head in enumerate(header):
result[head] = [
int(row[i]) if i != str_col_idx else row[i] for row in rows
]
return result
def is_valid(val, _type):
if _type is int:
return val.isdigit()
if _type is float:
try:
float(val)
return True
except ValueError:
return False
return True
def osd_to_dict(osd):
return {
OSD_KEYS[kv[0]][0]: OSD_KEYS[kv[0]][1](kv[1]) for kv in (
line.split(': ') for line in osd.split('\n')
) if len(kv) == 2 and is_valid(kv[1], OSD_KEYS[kv[0]][1])
}
@run_once
def get_tesseract_version():
'''
Returns LooseVersion object of the Tesseract version
'''
try:
return LooseVersion(
subprocess.check_output([tesseract_cmd, '--version'],
**subprocess_args(False)).decode('utf-8').split()[1].lstrip(string.printable[10:])
)
except OSError:
raise TesseractNotFoundError()
def image_to_string(image,
lang=None,
config='',
nice=0,
boxes=False,
output_type=Output.STRING):
'''
Returns the result of a Tesseract OCR run on the provided image to string
'''
if boxes:
# Added for backwards compatibility
print('\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)
args = [image, 'txt', lang, config, nice]
if output_type == Output.DICT:
return {'text': run_and_get_output(*args)}
elif output_type == Output.BYTES:
args.append(True)
return run_and_get_output(*args)
def image_to_boxes(image,
lang=None,
config='',
nice=0,
output_type=Output.STRING):
'''
Returns string containing recognized characters and their box boundaries
'''
config += ' batch.nochop makebox'
args = [image, 'box', lang, config, nice]
if output_type == Output.DICT:
box_header = 'char left bottom right top page\n'
return file_to_dict(box_header + run_and_get_output(*args), ' ', 0)
elif output_type == Output.BYTES:
args.append(True)
return run_and_get_output(*args)
def image_to_data(image,
lang=None,
config='',
nice=0,
output_type=Output.STRING):
'''
Returns string containing box boundaries, confidences,
and other information. Requires Tesseract 3.05+
'''
if get_tesseract_version() < '3.05':
raise TSVNotSupported()
config = '{} {}'.format('-c tessedit_create_tsv=1', config.strip()).strip()
args = [image, 'tsv', lang, config, nice]
if output_type == Output.DICT:
return file_to_dict(run_and_get_output(*args), '\t', -1)
elif output_type == Output.BYTES:
args.append(True)
return run_and_get_output(*args)
def image_to_osd(image,
lang='osd',
config='',
nice=0,
output_type=Output.STRING):
'''
Returns string containing the orientation and script detection (OSD)
'''
config = '{}-psm 0 {}'.format(
'' if get_tesseract_version() < '3.05' else '-',
config.strip()
).strip()
args = [image, 'osd', lang, config, nice]
if output_type == Output.DICT:
return osd_to_dict(run_and_get_output(*args))
elif output_type == Output.BYTES:
args.append(True)
return run_and_get_output(*args)
def main():
if len(sys.argv) == 2:
filename, lang = sys.argv[1], None
elif len(sys.argv) == 4 and sys.argv[1] == '-l':
filename, lang = sys.argv[3], sys.argv[2]
else:
sys.stderr.write('Usage: python pytesseract.py [-l lang] input_file\n')
exit(2)
try:
print(image_to_string(Image.open(filename), lang=lang))
except IOError:
sys.stderr.write('ERROR: Could not open file "%s"\n' % filename)
exit(1)
if __name__ == '__main__':
main()

8
README.MD Normal file
View File

@ -0,0 +1,8 @@
# CNIRevelator
### Analyzer for MRZ Codes on identity cards, passports and others for Windows.
This project is released under GNU General Public License v3 and has dependancies modules released under free licenses including :
Tesseract 4.0 beta, under Apache license 2004
Python Anaconda 3, under Berkeley Software Distribution license 2018-2019

View File

@ -1,12 +0,0 @@
# CNIRevelator
Analyzer for MRZ Codes on identity cards, passports and others
This project is released under GNU General Public License v3 and contains modules released under free licenses including :
Tesseract 4.0 beta, under Apache license 2004
Python Miniconda3, under Berkeley Software Distribution license 2017
It as been developped by NeoX_ in 2018, August.

2
VERSIONS.LST Normal file
View File

@ -0,0 +1,2 @@
# ver|url|checksum, and | as separator, one version per ||
0.0.0|https://www.os-k.eu|1234||0.0.1|https://www.os-k.eu|1234||0.0.2|https://www.os-k.eu|1234

BIN
id-card.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

18
make.bat Normal file
View File

@ -0,0 +1,18 @@
@echo off
title Compilation de CNIRLauncher
call pyinstaller -w -D --exclude-module PyQt5 --bootloader-ignore-signals --add-data "C:\users\adrie\Anaconda3\Lib\site-packages\tld\res\effective_tld_names.dat.txt";"tld\res" --add-data "id-card.ico";"id-card.ico" -i "id-card.ico" -n CNILauncher src\launcher\CNIRLauncher.py
title Compilation de CNIRevelator
call pyinstaller -w -D --exclude-module PyQt5 --bootloader-ignore-signals --add-data "C:\users\adrie\Anaconda3\Lib\site-packages\tld\res\effective_tld_names.dat.txt";"tld\res" --add-data "id-card.ico";"id-card.ico" -i "id-card.ico" -n CNIRevelator src\analyzer\CNI_Revelator.py
copy LICENSE dist\CNIRevelator\
copy id-card.ico dist\CNIRevelator\
robocopy dist\CNILauncher dist\CNIRevelator /E /MOVE
rmdir dist\CNILauncher /Q /S
pause

View File

@ -0,0 +1,59 @@
"""
********************************************************************************
* CNIRevelator *
* *
* Desc: Application launcher & updater *
* *
* Copyright © 2018-2019 Adrien Bourmault (neox95) *
* *
* This file is part of CNIRevelator. *
* *
* CNIRevelator is free software: you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation, either version 3 of the License, or *
* any later version. *
* *
* CNIRevelator 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 General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with CNIRevelator. If not, see <https:*www.gnu.org/licenses/>. *
********************************************************************************
"""
class changelog:
def __init__(self):
self.isOn = False
self.text = "Mise-à-jour de sécurité avec corrections suivantes :\n- ajout de la signature numérique de l'exécutable\n- ajout d'une clé de cryptage plus performante pour le stockage des identifiants\n- passage à la méthode de cryptage AES256\n\nAjout/correction des fonctionnalités suivantes :\n- somme de contrôle des téléchargements pour une meilleure fiabilité\n- amélioration de présentation du log en cas d'erreur\n- correction d'un bug affectant l'analyse des MRZ après la correction manuelle\n\nEt un petit bonjour à tout le monde! ;)"
CST_REV = '0'
CST_VERTITLE = '2.2'
CST_TAB_VER = ['2', '2', '5']
CST_VER = '{0}.{1}.{2}'.format(CST_TAB_VER[0], CST_TAB_VER[1], CST_TAB_VER[2])
CST_TYPE = 'Final Release'
CST_NAME = 'CNIRevelator'
CST_TITLE = CST_NAME + ' ' + CST_VER + ' - GNU/GPL Licensing 2018'
CST_MARK = CST_NAME + ' ' + CST_TYPE + ' ' + CST_VER + ' - by NeoX, GNU/GPL Licensing 2018'
CST_SUM_VER = int(CST_TAB_VER[0]) * 100 + int(CST_TAB_VER[1]) * 10 + int(CST_TAB_VER[2])
CST_LINK = 'http://neoxgroup.eu/ftpaccess/Applicatifs/CNIRevelator/'
CST_COLOR = '#003380'
CST_TesserHash = '5b58db27f7bc08c58a2cb33d01533b034b067cf8'
import base64, hashlib
from Crypto import Random
from Crypto.Cipher import AES
from tkinter import *
from tkinter.messagebox import *
from tkinter import filedialog
from tkinter import ttk
import os, time, threading, sys, urllib.request as urllib2, urllib.error as URLExcept, random
from datetime import datetime
CST_FOLDER = os.getenv('APPDATA') + '/CNIRevelator/'
CST_CRYPTOKEY = '82Xh!efX3#@P~2eG'
CST_CHANGELOG = changelog()

View File

@ -0,0 +1,120 @@
"""
********************************************************************************
* CNIRevelator *
* *
* Desc: Application launcher & updater *
* *
* Copyright © 2018-2019 Adrien Bourmault (neox95) *
* *
* This file is part of CNIRevelator. *
* *
* CNIRevelator is free software: you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation, either version 3 of the License, or *
* any later version. *
* *
* CNIRevelator 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 General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with CNIRevelator. If not, see <https:*www.gnu.org/licenses/>. *
********************************************************************************
"""
from CNI_GLOBALVAR import *
try:
os.remove('error.log')
os.remove('conf.ig')
except:
print("pass log deletion")
pass
if not os.path.exists(CST_FOLDER):
try:
os.makedirs(CST_FOLDER)
except IOError:
print("pass IO ERROR")
pass
print("debug")
import logging
from logging import FileHandler
logger = logging.getLogger()
logger.setLevel(logging.INFO)
formatter = logging.Formatter('%(asctime)s :: %(levelname)s :: %(message)s')
error_handler = FileHandler((CST_FOLDER + '\\error.log'), mode='w', encoding='utf-8', delay=True)
info_handler = FileHandler((CST_FOLDER + '\\cnirevelator.log'), mode='w', encoding='utf-8')
error_handler.setLevel(logging.ERROR)
logger.addHandler(error_handler)
info_handler.setLevel(logging.DEBUG)
info_handler.setFormatter(formatter)
logger.addHandler(info_handler)
from CNI_classes import *
from CNI_Update import *
def main(logger):
logger.error('')
logger.info('main() : **** Creating App_main() ****')
main_w = App_main(logger)
main_w.montext('* ' + CST_NAME + ' ' + CST_VER + ' ' + CST_TYPE + ' Revision ' + CST_REV + ' *\n')
import CNI_pytesseract as pytesseract
try:
os.environ['PATH'] = CST_FOLDER + 'Tesseract-OCR4\\'
os.environ['TESSDATA_PREFIX'] = CST_FOLDER + 'Tesseract-OCR4\\tessdata'
tesser_version = pytesseract.get_tesseract_version()
except Exception as e:
logger.error('main() : **** ERROR WITH TESSERACT MODULE ' + str(e) + ' ****')
else:
text = 'Tesseract version ' + str(tesser_version) + ' Licensed Apache 2004 successfully initiated\n'
main_w.montext(text)
main_w.montext('\n\nEntrez la première ligne de MRZ svp \n')
if CST_CHANGELOG.isOn:
showinfo('Changelog : résumé de mise à jour', ('Version du logiciel : ' + CST_VER + ' ' + CST_TYPE + ' Revision ' + CST_REV + '\n\n' + CST_CHANGELOG.text), parent=main_w)
logger.info('main() : **** Launching App_main() ****')
main_w.mainloop()
logger.info('main() : **** Ending App_main() ****')
logger.info('launcher : ' + CST_NAME + ' ' + CST_VER)
logger.info('launcher : *****Hello World*****')
logger.info('launcher : *****Launching SoftUpdate()*****')
try:
Answer = SoftUpdate(logger)
except Exception as e:
logger.info('launcher : *****FATAL ERROR*****' + str(e))
os.abort()
logger.info('launcher : *****Ending SoftUpdate()*****')
try:
if Answer == True:
logger.info('launcher : *****Launching main()*****')
State = main(logger)
except Exception as e:
logger.info('launcher : *****FATAL ERROR*****' + str(e))
os.abort()
logger.info('launcher : *****Ending main()*****')
logger.info('launcher : *****Goodbye!*****')
handlers = logger.handlers[:]
for handler in handlers:
handler.close()
logger.removeHandler(handler)
try:
with open(CST_FOLDER + '\\error.log') as (echo):
try:
os.remove('error.log')
except OSError:
pass
from shutil import copyfile
temptwo = str(echo.read())
if len(temptwo) != 1:
copyfile(CST_FOLDER + '\\cnirevelator.log', 'error.log')
except IOError:
pass
print("exit")
sys.exit(0)

506
src/analyzer/CNI_Update.py Normal file
View File

@ -0,0 +1,506 @@
"""
********************************************************************************
* CNIRevelator *
* *
* Desc: Application launcher & updater *
* *
* Copyright © 2018-2019 Adrien Bourmault (neox95) *
* *
* This file is part of CNIRevelator. *
* *
* CNIRevelator is free software: you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation, either version 3 of the License, or *
* any later version. *
* *
* CNIRevelator 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 General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with CNIRevelator. If not, see <https:*www.gnu.org/licenses/>. *
********************************************************************************
"""
from CNI_GLOBALVAR import *
from CNI_classes import *
import hashlib
from pypac import PACSession
from requests.auth import HTTPProxyAuth
import subprocess
def SoftUpdate(logger):
global ret
global upwin
import zipfile
for f in os.listdir(CST_FOLDER):
if f[-4:] == '.tif':
try:
os.remove(CST_FOLDER + '\\' + f)
except PermissionError as e:
logger.info('SoftUpdate() : Failing to purge : ' + str(e))
logger.info('SoftUpdate() : Looking for older version in dir...')
list = os.listdir('.')
for file in list:
if file.startswith('CNIRevelator_'):
temp = ['0', '0', '0']
ver = file[13:].split('.')
for i in range(len(ver)):
if ver[i] != 'exe':
try:
temp[i] = ver[i]
except:
pass
ver = temp.copy()
try:
sum_ver = int(ver[0]) * 100 + int(ver[1]) * 10 + int(ver[2])
if sum_ver < CST_SUM_VER:
if file[-3:] == 'exe':
os.remove(file)
logger.info('SoftUpdate() : Removed old version : ' + str(file))
CST_CHANGELOG.isOn = True
except Exception as e:
logger.error('SoftUpdate() : Failing to remove old version ' + str(file) + ' : ' + str(e))
def updating():
def updator():
global ret
logger.info('[updator() thread] : Welcome !')
ret = 11
canvas.itemconfigure(message, text='Recherche de mises-à-jour...')
p.configure(mode='indeterminate', value=0, maximum=20)
p.start()
upwin.update()
logger.info('[updator() thread] : Looking for updates...')
try:
def download(url, filename):
global key
global login
try:
logger.info('[download() thread] : Trying getting credentials in the config file')
with open(CST_FOLDER + 'conf.ig', 'rb') as (config):
AESObj = AESCipher(CST_CRYPTOKEY)
try:
tempone = AESObj.decrypt(config.read())
if tempone != '||':
if tempone.find('||') != -1:
IPN, IPN_PASS = tempone.split('||')[0:2]
else:
raise ValueError('Cryptokey is bad !')
else:
IPN = ''
IPN_PASS = ''
except Exception as e:
raise IOError(str(e))
else:
logger.info('[download() thread] : Got credentials !')
session = PACSession(proxy_auth=(HTTPProxyAuth(IPN, IPN_PASS)))
logger.info('[download() thread] : Authenticated to proxy successfully')
except IOError as e:
logger.error('[download() thread] : False or absent credentials in the config file : ' + str(e))
NoConnect = True
while NoConnect:
class LoginDialog(Toplevel):
def __init__(self, parent):
super().__init__(parent)
self.title('Connexion')
Label(self, text='IPN : ').pack()
self.entry_login = Entry(self)
self.entry_login.insert(0, '')
self.entry_login.pack()
Label(self, text='Mot de passe : ').pack()
self.entry_pass = Entry(self, show='*')
self.entry_pass.insert(0, '')
self.entry_pass.pack()
Button(self, text='Connexion', command=(self.connecti)).pack()
self.resizable(width=False, height=False)
w = 150
h = 110
self.update()
ws = self.winfo_screenwidth()
hs = self.winfo_screenheight()
if getattr(sys, 'frozen', False):
self.iconbitmap(sys._MEIPASS + '\\id-card.ico\\id-card.ico')
else:
self.iconbitmap('id-card.ico')
upwin.update()
x = ws / 2 - w / 2
y = hs / 2 - h / 2
self.geometry('%dx%d+%d+%d' % (w, h, x, y))
def connecti(self):
global key
global login
login = self.entry_login.get().strip()
key = self.entry_pass.get().strip()
self.destroy()
session = PACSession()
if session.get_pac() == None:
IPN = ''
IPN_PASS = ''
NoConnect = False
break
canvas.itemconfigure(message, text='En attente de connexion au serveur proxy...')
login = ''
key = ''
result = LoginDialog(upwin)
result.transient(upwin)
result.grab_set()
upwin.wait_window(result)
IPN = login
IPN_PASS = key
session = PACSession(proxy_auth=(HTTPProxyAuth(IPN, IPN_PASS)))
Ans = session.get('http://www.google.com')
if str(Ans) == '<Response [407]>':
canvas.itemconfigure(message, text='Identifiants erronés, accès refusé')
logger.info('[download() thread] : 407 Error')
time.sleep(1)
else:
if str(Ans) == '<Response [200]>':
logger.info('[download() thread] : Connection ok !')
NoConnect = False
else:
raise IOError()
AESObj = AESCipher(CST_CRYPTOKEY)
with open(CST_FOLDER + 'conf.ig', 'wb+') as (f):
logger.info('[download() thread] : Saving credentials in encrypted config file')
f.write(AESObj.encrypt(IPN + '||' + IPN_PASS))
if IPN == 'i005316':
canvas.itemconfigure(message, text='Bienvenue Thierry !')
else:
if IPN == 'i020251':
canvas.itemconfigure(message, text='Bienvenue Samia !')
else:
if IPN == 'i018410':
canvas.itemconfigure(message, text='Bienvenue Adrien !')
else:
if IPN == 'i003067':
canvas.itemconfigure(message, text='Bienvenue Remy !')
else:
if IPN == 'i018422':
canvas.itemconfigure(message, text='Bienvenue Eloise !')
time.sleep(1)
try:
Prox_us = session.get_pac().find_proxy_for_url(CST_LINK, 'neoxgroup.eu')
PROXY_USABLE = Prox_us[6:-1].split(';')[0]
proxy_server_url = IPN + ':' + IPN_PASS + '@' + PROXY_USABLE
ph = urllib2.ProxyHandler({'http': proxy_server_url})
auth = urllib2.ProxyBasicAuthHandler()
server = urllib2.build_opener(ph, auth, urllib2.HTTPHandler)
urllib2.install_opener(server)
logger.info('[download() thread] : Proxy connection initiated successfully')
except:
logger.info('[download() thread] : Proxy connection not initiated')
try:
urllib2.urlretrieve(url, filename)
return True
except Exception as e:
logger.error('[download() thread] : HTTP ERROR ')
return e
logger.info('[updator() thread] : Prepare downloading the version recap file...')
tempfile = CST_FOLDER + 'temp' + str(random.randint(11111, 99999)) + '.cniu'
isOk = download(CST_LINK + 'cnir.ver', tempfile)
if not isOk:
raise isOk
urllib2.urlcleanup()
logger.info('[updator() thread] : Opening version recap file...')
file_ver = open(tempfile, 'r')
logger.info('[updator() thread] : Reading version recap file...')
version = file_ver.read()
logger.info('[updator() thread] : Closing version recap file...')
repert = version.split('|')
file_ver.close()
logger.info('[updator() thread] : Deleting version recap file...')
os.remove(tempfile)
logger.info('[updator() thread] : Parsing informations about version...')
final_f = 'CNI_file'
final_ver = ['0', '0', '0']
final_hash = ''
for sentence in repert:
try:
file, hashref = sentence.split(':')
except ValueError:
pass
else:
if str.startswith(file, CST_NAME):
ver = file.replace(CST_NAME + '_', '').split('.')
temp = [
'0', '0', '0']
for i in range(len(ver)):
temp[i] = ver[i]
ver = temp.copy()
sum_fver = int(final_ver[0]) * 100 + int(final_ver[1]) * 10 + int(final_ver[2])
sum_ver = int(ver[0]) * 100 + int(ver[1]) * 10 + int(ver[2])
if sum_ver > sum_fver:
final_ver = ver.copy()
final_f = file
final_hash = hashref
sum_ver = int(final_ver[0]) * 100 + int(final_ver[1]) * 10 + int(final_ver[2])
if final_f != 'CNI_file':
if sum_ver > CST_SUM_VER:
logger.info('[updator() thread] : New version of CNIRevelator found !')
canvas.itemconfigure(message, text='Mise à jour disponible ! Préparation du téléchargement...')
logger.info('[updator() thread] : Preparing download')
with open(CST_FOLDER + 'conf.ig', 'rb') as (config):
logger.info('[updator() thread] : Reading credentials for proxy in config file...')
AESObj = AESCipher(CST_CRYPTOKEY)
IPN, IPN_PASS = AESObj.decrypt(config.read()).split('||')[0:2]
session = PACSession(proxy_auth=(HTTPProxyAuth(IPN, IPN_PASS)))
try:
Prox_us = session.get_pac().find_proxy_for_url(CST_LINK, 'neoxgroup.eu')
PROXY_USABLE = Prox_us[6:-1].split(';')[0]
proxy_server_url = IPN + ':' + IPN_PASS + '@' + PROXY_USABLE
ph = urllib2.ProxyHandler({'http': proxy_server_url})
auth = urllib2.ProxyBasicAuthHandler()
server = urllib2.build_opener(ph, auth, urllib2.HTTPHandler)
logger.info('[updator() thread] : Connection to the proxy initiated successfully !')
except:
canvas.itemconfigure(message, text='Téléchargement en connexion directe...')
server = urllib2.build_opener()
logger.info('[updator() thread] : Direct connection initiated successfully')
logger.info('[updator() thread] : Launching download of ' + final_f)
Statut = Download(CST_LINK + final_f, final_f, final_f, server, p, canvas, message, logger)
BLOCKSIZE = 65536
hasher = hashlib.sha1()
try:
with open(final_f, 'rb') as (afile):
buf = afile.read(BLOCKSIZE)
while len(buf) > 0:
hasher.update(buf)
buf = afile.read(BLOCKSIZE)
hashcod = hasher.hexdigest()
if hashcod != final_hash:
Statut.success = False
logger.error('[updator() thread] : Hashcode Error :' + final_f)
try:
os.remove(final_f)
except IOError:
pass
else:
logger.info('[updator() thread] : Hashcode pass :' + final_f)
except FileNotFoundError as e:
logger.error('[updator() thread] : File not found ' + final_f)
if Statut.success:
try:
os.rename(final_f, final_f + '.exe')
except IOError:
logger.error('[updator() thread] : Unable to rename the file ! Wait 3 sec and retry')
time.sleep(3)
try:
os.rename(final_f, final_f + '.exe')
except IOError:
logger.critical('[updator() thread] : Unable to rename the file !')
else:
canvas.itemconfigure(message, text='Téléchargement terminé ! Préparation du lancement...')
logger.info('[updator() thread] : Download of ' + final_f + 'finished successfully')
p.configure(mode='indeterminate', value=0, maximum=20)
p.start()
time.sleep(1)
logger.info('[updator() thread] : Launching ' + final_f)
try:
proc = subprocess.Popen((final_f + '.exe'), shell=False, stdin=None, stdout=None, stderr=None, close_fds=True)
except:
logger.error('[updator() thread] : Unable to start the new version ! Wait 3 sec and retry')
time.sleep(3)
try:
proc = subprocess.Popen((final_f + '.exe'), shell=False, stdin=None, stdout=None, stderr=None, close_fds=True)
except Exception as e:
logger.critical('[updator() thread] : Unable to start the new version ! Stopping : ' + str(e))
showerror("Erreur d'appel de procédure distante", 'Le lancement du nouveau programme a échoué, vous devez le lancer manuellement une fois cette fenêtre fermée', parent=upwin)
ret = 12
else:
canvas.itemconfigure(message, text='Echec de la mise à jour : Erreur HTTP. Préparation du lancement...')
logger.error('[updator() thread] : Update has failed with HTTP error')
time.sleep(1)
canvas.itemconfigure(message, text='Logiciel déjà à jour. Préparation du lancement...')
logger.info('[updator() thread] : CNIRevelator is up to date !')
time.sleep(1)
ret = 11
if os.path.exists(CST_FOLDER + 'Tesseract-OCR4\\tesseract.exe'):
os.environ['PATH'] = CST_FOLDER + 'Tesseract-OCR4\\'
os.environ['TESSDATA_PREFIX'] = CST_FOLDER + 'Tesseract-OCR4\\tessdata'
else:
final_f = 'tesseract_4'
logger.info('[updator() thread] : Downloading tesseract 4 !')
canvas.itemconfigure(message, text='Mise à jour du module OCR ! Préparation du téléchargement...')
logger.info('[updator() thread] : Preparing download')
with open(CST_FOLDER + 'conf.ig', 'rb') as (config):
logger.info('[updator() thread] : Reading credentials for proxy in config file...')
AESObj = AESCipher(CST_CRYPTOKEY)
IPN, IPN_PASS = AESObj.decrypt(config.read()).split('||')[0:2]
session = PACSession(proxy_auth=(HTTPProxyAuth(IPN, IPN_PASS)))
try:
Prox_us = session.get_pac().find_proxy_for_url(CST_LINK, 'neoxgroup.eu')
PROXY_USABLE = Prox_us[6:-1].split(';')[0]
proxy_server_url = IPN + ':' + IPN_PASS + '@' + PROXY_USABLE
ph = urllib2.ProxyHandler({'http': proxy_server_url})
auth = urllib2.ProxyBasicAuthHandler()
server = urllib2.build_opener(ph, auth, urllib2.HTTPHandler)
logger.info('[updator() thread] : Connection to the proxy initiated successfully !')
except:
canvas.itemconfigure(message, text='Téléchargement en connexion directe...')
server = urllib2.build_opener()
logger.info('[updator() thread] : Direct connection initiated successfully')
logger.info('[updator() thread] : Launching download of ' + final_f)
Statut = Download(CST_LINK + final_f, CST_FOLDER + final_f, final_f, server, p, canvas, message, logger)
hashcod = ''
logger.info('[updator() thread] : Verifying hashcode of ' + final_f)
BLOCKSIZE = 65536
hasher = hashlib.sha1()
try:
with open(CST_FOLDER + final_f, 'rb') as (afile):
buf = afile.read(BLOCKSIZE)
while len(buf) > 0:
hasher.update(buf)
buf = afile.read(BLOCKSIZE)
hashcod = hasher.hexdigest()
if hashcod != CST_TesserHash:
Statut.success = False
logger.error('[updator() thread] : Hashcode Error : ' + final_f)
try:
os.remove(CST_FOLDER + final_f)
except IOError:
pass
else:
logger.info('[updator() thread] : Hashcode pass : ' + final_f)
except FileNotFoundError as e:
logger.error('[updator() thread] : File not found ' + final_f)
if Statut.success:
canvas.itemconfigure(message, text='Téléchargement terminé ! Installation...')
logger.info('[updator() thread] : Download of ' + final_f + 'finished successfully')
p.configure(mode='indeterminate', value=0, maximum=20)
p.start()
try:
zip_ref = zipfile.ZipFile(CST_FOLDER + final_f, 'r')
zip_ref.extractall(CST_FOLDER)
zip_ref.close()
os.environ['PATH'] = CST_FOLDER + 'Tesseract-OCR4\\'
os.environ['TESSDATA_PREFIX'] = CST_FOLDER + 'Tesseract-OCR4\\tessdata'
canvas.itemconfigure(message, text='Installation terminée !')
except:
logger.error('[updator() thread] : Unable to install the module. Wait and retry')
time.sleep(3)
try:
zip_ref = zipfile.ZipFile(CST_FOLDER + final_f, 'r')
zip_ref.extractall(CST_FOLDER)
zip_ref.close()
os.environ['PATH'] = CST_FOLDER + 'Tesseract-OCR4\\'
os.environ['TESSDATA_PREFIX'] = CST_FOLDER + 'Tesseract-OCR4\\tessdata'
canvas.itemconfigure(message, text='Installation terminée !')
except Exception as e:
logger.critical('[updator() thread] : Unable to install the module ! Stopping : ' + str(e))
showerror("Erreur d'appel de procédure distante", "L'installation du module OCR a échoué, contactez le développeur.")
ret = 11
else:
logger.critical('[updator() thread] : Unable to download the module ! ')
showerror('Erreur de téléchargement', "L'installation du module OCR a échoué, merci d'indiquer le chemin d'accès au fichier tesseract_4 dans la fenêtre suivante")
path = filedialog.askopenfilename(title="Indiquez le chemin d'accès à tesseract_4...", filetypes=(('Tesseract_4', '*.cni4'),
('Tesseract_4', '*.cni4')))
if path != '':
try:
canvas.itemconfigure(message, text='Installation...')
zip_ref = zipfile.ZipFile(path, 'r')
zip_ref.extractall(CST_FOLDER)
zip_ref.close()
logger.error('[updator() thread] : Manual installation successed')
canvas.itemconfigure(message, text='Installation terminée !')
os.environ['PATH'] = CST_FOLDER + 'Tesseract-OCR4\\'
os.environ['TESSDATA_PREFIX'] = CST_FOLDER + 'Tesseract-OCR4\\tessdata'
except Exception as e:
logger.error('[updator() thread] : Manual installation has failed' + str(e))
showerror('Erreur de lecture', "Le module OCR n'a pas pu être installé, la saisie automatique de scans ne pourra donc fonctionner")
else:
showerror('Opération annulée', "Le module OCR n'a été installé, la saisie automatique de scans ne pourra donc fonctionner")
except URLExcept.HTTPError as e:
canvas.itemconfigure(message, text=('Echec de la mise à jour : Erreur HTTP ' + str(e.code) + ' . Préparation du lancement...'))
logger.error('[updator() thread] : Update has failed with HTTP error' + str(e.code))
if int(e.code) == 407:
showerror('Erreur 407', 'Attention : le système de mise à jour automatique a fait face à une erreur 407, signifiant que la connexion au serveur proxy a été refusée. Vos identifiants vous seront redemandés au prochain démarrage. La mise à jour a échoué.')
logger.info('[updator() thread] : Credential error. Deleting the config file...')
os.remove(CST_FOLDER + 'conf.ig')
p.configure(mode='indeterminate', value=0, maximum=20)
p.start()
time.sleep(3)
except Exception as e:
canvas.itemconfigure(message, text='Echec de la mise à jour. Préparation du lancement...')
logger.error('[updator() thread] : Error from the updating system : ' + str(e))
p.configure(mode='indeterminate', value=0, maximum=20)
p.start()
time.sleep(2)
p.stop()
upwin.destroy()
root.destroy()
return ret
logger.info('updating() : Launching updator() thread...')
threading.Thread(target=updator, daemon=True).start()
logger.info('updating() [Thread] : Ending updator() thread')
ret = 11
root = Tk()
root.attributes('-alpha', 0.0)
root.iconify()
upwin = Toplevel(root)
upwin.overrideredirect(1)
upwin.configure(bg=CST_COLOR)
upwin.resizable(width=False, height=False)
w = 600
h = 300
upwin.update()
canvas = Canvas(upwin, width=600, height=270, bg=CST_COLOR, highlightthickness=0)
pbar = Canvas(upwin, width=600, height=30, bg=CST_COLOR)
p = ttk.Progressbar(pbar, orient=HORIZONTAL, length=590, mode='determinate')
upwin.update()
ws = upwin.winfo_screenwidth()
hs = upwin.winfo_screenheight()
canvas.create_text((w / 2), (h / 3), text=(CST_NAME + ' ' + CST_VERTITLE), font='Calibri 30 bold', fill='white')
message = canvas.create_text((w / 2), (h / 1.15), text=' ', font='Calibri 9', fill='white')
upwin.update()
x = ws / 2 - w / 2
y = hs / 2 - h / 2
upwin.geometry('%dx%d+%d+%d' % (w, h, x, y))
canvas.grid()
pbar.grid()
p.grid()
upwin.after(2000, updating)
if getattr(sys, 'frozen', False):
root.iconbitmap(sys._MEIPASS + '\\id-card.ico\\id-card.ico')
else:
root.iconbitmap('id-card.ico')
logger.info('SoftUpdate() : Entering upwin mainloop()')
upwin.protocol('WM_DELETE_WINDOW', lambda : root.destroy())
upwin.mainloop()
logger.info('SoftUpdate() : Exiting upwin mainloop()')
if ret == 11:
logger.info('SoftUpdate() : OK to start to main() normally !')
return True
else:
logger.info('SoftUpdate() : Program will stop !')
return False

1332
src/analyzer/CNI_classes.py Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,326 @@
"""
********************************************************************************
* CNIRevelator *
* *
* Desc: Pytesseract modification to comply with Pyinstaller *
* *
* Copyright © 2017-2018 Matthias A. Lee (madmaze) *
* Copyright © 2018-2019 Adrien Bourmault (neox95) *
* *
* This file is part of CNIRevelator. *
* *
* CNIRevelator is free software: you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation, either version 3 of the License, or *
* any later version. *
* *
* CNIRevelator 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 General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with CNIRevelator. If not, see <https:*www.gnu.org/licenses/>. *
********************************************************************************
"""
try:
import Image
except ImportError:
from PIL import Image
import os, sys, subprocess, tempfile, shlex, string
from glob import iglob
from pkgutil import find_loader
from distutils.version import LooseVersion
from os.path import realpath, normpath, normcase
numpy_installed = find_loader('numpy') is not None
if numpy_installed:
from numpy import ndarray
tesseract_cmd = 'tesseract'
RGB_MODE = 'RGB'
OSD_KEYS = {'Page number':(
'page_num', int),
'Orientation in degrees':(
'orientation', int),
'Rotate':(
'rotate', int),
'Orientation confidence':(
'orientation_conf', float),
'Script':(
'script', str),
'Script confidence':(
'script_conf', float)}
class Output:
STRING = 'string'
BYTES = 'bytes'
DICT = 'dict'
class TesseractError(RuntimeError):
def __init__(self, status, message):
self.status = status
self.message = message
self.args = (status, message)
class TesseractNotFoundError(EnvironmentError):
def __init__(self):
super(TesseractNotFoundError, self).__init__(tesseract_cmd + " is not installed or it's not in your path")
class TSVNotSupported(EnvironmentError):
def __init__(self):
super(TSVNotSupported, self).__init__('TSV output not supported. Tesseract >= 3.05 required')
def run_once(func):
def wrapper(*args, **kwargs):
if wrapper._result is wrapper:
wrapper._result = func(*args, **kwargs)
return wrapper._result
wrapper._result = wrapper
return wrapper
def get_errors(error_string):
return ' '.join(line for line in error_string.decode('utf-8').splitlines()).strip()
def cleanup(temp_name):
""" Tries to remove files by filename wildcard path. """
for filename in iglob(temp_name + '*' if temp_name else temp_name):
try:
os.remove(filename)
except OSError:
pass
def prepare(image):
if isinstance(image, Image.Image):
return image
if numpy_installed:
if isinstance(image, ndarray):
pass
return Image.fromarray(image)
raise TypeError('Unsupported image object')
def save_image(image):
temp_name = tempfile.mktemp(prefix='tess_')
if isinstance(image, str):
return (temp_name, realpath(normpath(normcase(image))))
else:
image = prepare(image)
img_extension = image.format
if image.format not in frozenset({'BMP', 'JPEG', 'GIF', 'TIFF', 'PNG'}):
img_extension = 'PNG'
if not image.mode.startswith(RGB_MODE):
image = image.convert(RGB_MODE)
if 'A' in image.getbands():
background = Image.new(RGB_MODE, image.size, (255, 255, 255))
background.paste(image, (0, 0), image)
image = background
input_file_name = temp_name + os.extsep + img_extension
(image.save)(input_file_name, format=img_extension, **image.info)
return (
temp_name, input_file_name)
def subprocess_args(include_stdout=True):
if hasattr(subprocess, 'STARTUPINFO'):
si = subprocess.STARTUPINFO()
si.dwFlags |= subprocess.STARTF_USESHOWWINDOW
env = os.environ
else:
si = None
env = None
if include_stdout:
ret = {'stdout': subprocess.PIPE}
else:
ret = {}
ret.update({'stdin':subprocess.PIPE, 'stderr':subprocess.PIPE,
'startupinfo':si,
'env':env})
return ret
def run_tesseract(input_filename, output_filename_base, extension, lang, config='', nice=0):
cmd_args = []
if not sys.platform.startswith('win32'):
if nice != 0:
cmd_args += ('nice', '-n', str(nice))
cmd_args += (tesseract_cmd, input_filename, output_filename_base)
if lang is not None:
cmd_args += ('-l', lang)
cmd_args += shlex.split(config)
if extension not in ('box', 'osd', 'tsv'):
cmd_args.append(extension)
try:
proc = (subprocess.Popen)(cmd_args, **subprocess_args())
except OSError:
raise TesseractNotFoundError()
status_code, error_string = proc.wait(), proc.stderr.read()
proc.stderr.close()
if status_code:
raise TesseractError(status_code, get_errors(error_string))
return True
def run_and_get_output(image, extension, lang=None, config='', nice=0, return_bytes=False):
temp_name, input_filename = ('', '')
try:
temp_name, input_filename = save_image(image)
kwargs = {'input_filename':input_filename,
'output_filename_base':temp_name + '_out',
'extension':extension,
'lang':lang,
'config':config,
'nice':nice}
run_tesseract(**kwargs)
filename = kwargs['output_filename_base'] + os.extsep + extension
with open(filename, 'rb') as (output_file):
if return_bytes:
return output_file.read()
return output_file.read().decode('utf-8').strip()
finally:
cleanup(temp_name)
def file_to_dict(tsv, cell_delimiter, str_col_idx):
result = {}
rows = [row.split(cell_delimiter) for row in tsv.split('\n')]
if not rows:
return result
else:
header = rows.pop(0)
if len(rows[(-1)]) < len(header):
rows[(-1)].append('')
if str_col_idx < 0:
str_col_idx += len(header)
for i, head in enumerate(header):
result[head] = [int(row[i]) if i != str_col_idx else row[i] for row in rows]
return result
def is_valid(val, _type):
if _type is int:
return val.isdigit()
else:
if _type is float:
pass
try:
float(val)
return True
except ValueError:
return False
return True
def osd_to_dict(osd):
return {OSD_KEYS[kv[0]][0]:OSD_KEYS[kv[0]][1](kv[1]) for kv in (line.split(': ') for line in osd.split('\n')) if len(kv) == 2 if is_valid(kv[1], OSD_KEYS[kv[0]][1])}
@run_once
def get_tesseract_version():
"""
Returns LooseVersion object of the Tesseract version
"""
try:
return LooseVersion((subprocess.check_output)([tesseract_cmd, '--version'], **subprocess_args(False)).decode('utf-8').split()[1].lstrip(string.printable[10:]))
except OSError:
raise TesseractNotFoundError()
def image_to_string(image, lang=None, config='', nice=0, boxes=False, output_type=Output.STRING):
"""
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")
return image_to_boxes(image, lang, config, nice, output_type)
else:
args = [
image, 'txt', lang, config, nice]
if output_type == Output.DICT:
return {'text': run_and_get_output(*args)}
if output_type == Output.BYTES:
args.append(True)
return run_and_get_output(*args)
def image_to_boxes(image, lang=None, config='', nice=0, output_type=Output.STRING):
"""
Returns string containing recognized characters and their box boundaries
"""
config += ' batch.nochop makebox'
args = [image, 'box', lang, config, nice]
if output_type == Output.DICT:
box_header = 'char left bottom right top page\n'
return file_to_dict(box_header + run_and_get_output(*args), ' ', 0)
else:
if output_type == Output.BYTES:
args.append(True)
return run_and_get_output(*args)
def image_to_data(image, lang=None, config='', nice=0, output_type=Output.STRING):
"""
Returns string containing box boundaries, confidences,
and other information. Requires Tesseract 3.05+
"""
if get_tesseract_version() < '3.05':
raise TSVNotSupported()
config = '{} {}'.format('-c tessedit_create_tsv=1', config.strip()).strip()
args = [image, 'tsv', lang, config, nice]
if output_type == Output.DICT:
return file_to_dict(run_and_get_output(*args), '\t', -1)
else:
if output_type == Output.BYTES:
args.append(True)
return run_and_get_output(*args)
def image_to_osd(image, lang='osd', config='', nice=0, output_type=Output.STRING):
"""
Returns string containing the orientation and script detection (OSD)
"""
config = '{}-psm 0 {}'.format('' if get_tesseract_version() < '3.05' else '-', config.strip()).strip()
args = [
image, 'osd', lang, config, nice]
if output_type == Output.DICT:
return osd_to_dict(run_and_get_output(*args))
else:
if output_type == Output.BYTES:
args.append(True)
return run_and_get_output(*args)
def main():
if len(sys.argv) == 2:
filename, lang = sys.argv[1], None
else:
if len(sys.argv) == 4:
if sys.argv[1] == '-l':
filename, lang = sys.argv[3], sys.argv[2]
sys.stderr.write('Usage: python pytesseract.py [-l lang] input_file\n')
exit(2)
try:
print(image_to_string((Image.open(filename)), lang=lang))
except IOError:
sys.stderr.write('ERROR: Could not open file "%s"\n' % filename)
exit(1)
if __name__ == '__main__':
main()

View File

@ -0,0 +1,69 @@
"""
********************************************************************************
* CNIRevelator *
* *
* Desc: Application launcher & updater main file *
* *
* Copyright © 2018-2019 Adrien Bourmault (neox95) *
* *
* This file is part of CNIRevelator. *
* *
* CNIRevelator is free software: you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation, either version 3 of the License, or *
* any later version. *
* *
* CNIRevelator 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 General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with CNIRevelator. If not, see <https:*www.gnu.org/licenses/>. *
********************************************************************************
"""
import sys
import os
import subprocess
import threading
import traceback
import updater # updater.py
import ihm # ihm.py
import globs # globs.py
import logger # logger.py
## Global Handlers
logfile = logger.logCur
launcherWindow = ihm.launcherWindowCur
## Main function
def main():
# Starting the main update thread
mainThread.start()
# Hello world
logfile.printdbg('*** CNIRLauncher LOGFILE. Hello World ! ***')
#logfile.printdbg('Files in directory : ' + str(os.listdir(globs.CNIRFolder)))
# Hello user
launcherWindow.progressBar.configure(mode='indeterminate', value=0, maximum=20)
launcherWindow.mainCanvas.itemconfigure(launcherWindow.msg, text='Starting...')
launcherWindow.progressBar.start()
launcherWindow.mainloop()
logfile.printdbg('*** CNIRLauncher LOGFILE. Goodbye World ! ***')
return
## Bootstrap
try:
mainThread = threading.Thread(target=updater.umain, daemon=False)
main()
except Exception:
logfile.printerr("A FATAL ERROR OCCURED : " + str(traceback.format_exc()))
sys.exit(1)
sys.exit(0)

View File

@ -0,0 +1,33 @@
"""
********************************************************************************
* CNIRevelator *
* *
* Desc: Application launcher download stuff *
* *
* Copyright © 2018-2019 Adrien Bourmault (neox95) *
* *
* This file is part of CNIRevelator. *
* *
* CNIRevelator is free software: you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation, either version 3 of the License, or *
* any later version. *
* *
* CNIRevelator 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 General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with CNIRevelator. If not, see <https:*www.gnu.org/licenses/>. *
********************************************************************************
"""
import hashlib
from pypac import PACSession
from requests.auth import HTTPProxyAuth
class newdownload():
def __init__(url):
self.url = url

30
src/launcher/globs.py Normal file
View File

@ -0,0 +1,30 @@
"""
********************************************************************************
* CNIRevelator *
* *
* Desc: Application launcher global variables *
* *
* Copyright © 2018-2019 Adrien Bourmault (neox95) *
* *
* This file is part of CNIRevelator. *
* *
* CNIRevelator is free software: you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation, either version 3 of the License, or *
* any later version. *
* *
* CNIRevelator 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 General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with CNIRevelator. If not, see <https:*www.gnu.org/licenses/>. *
********************************************************************************
"""
import os
CNIRTesserHash = '5b58db27f7bc08c58a2cb33d01533b034b067cf8'
CNIRFolder = os.getcwd()
CNIRLColor = "#006699"
CNIRName = "CNIRevelator Launcher 3"

BIN
src/launcher/id-card.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

119
src/launcher/ihm.py Normal file
View File

@ -0,0 +1,119 @@
"""
********************************************************************************
* CNIRevelator *
* *
* Desc: Application launcher graphical interface *
* *
* Copyright © 2018-2019 Adrien Bourmault (neox95) *
* *
* This file is part of CNIRevelator. *
* *
* CNIRevelator is free software: you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation, either version 3 of the License, or *
* any later version. *
* *
* CNIRevelator 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 General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with CNIRevelator. If not, see <https:*www.gnu.org/licenses/>. *
********************************************************************************
"""
from tkinter import *
from tkinter.messagebox import *
from tkinter import filedialog
from tkinter import ttk
import logger # logger.py
import globs # globs.py
class LoginDialog(Toplevel):
def __init__(self, parent):
super().__init__(parent)
self.title('Connexion')
Label(self, text='IPN : ').pack()
self.entry_login = Entry(self)
self.entry_login.insert(0, '')
self.entry_login.pack()
Label(self, text='Mot de passe : ').pack()
self.entry_pass = Entry(self, show='*')
self.entry_pass.insert(0, '')
self.entry_pass.pack()
Button(self, text='Connexion', command=(self.connecti)).pack()
self.resizable(width=False, height=False)
w = 150
h = 110
self.update()
ws = self.winfo_screenwidth()
hs = self.winfo_screenheight()
if getattr(sys, 'frozen', False):
self.iconbitmap(sys._MEIPASS + '\\id-card.ico\\id-card.ico')
else:
self.iconbitmap('id-card.ico')
upwin.update()
x = ws / 2 - w / 2
y = hs / 2 - h / 2
self.geometry('%dx%d+%d+%d' % (w, h, x, y))
def logingin(self):
global key
global login
login = self.entry_login.get().strip()
key = self.entry_pass.get().strip()
self.destroy()
class LauncherWindow(Tk):
def __init__(self):
# Initialize the tkinter main class
Tk.__init__(self)
self.configure(bg=globs.CNIRLColor)
self.resizable(width=False, height=False)
self.queue = []
# Setting up the geometry
ws = self.winfo_screenwidth()
hs = self.winfo_screenheight()
wheight = hs /4
wwidth = ws /4
#self.update()
# Creating objects
self.mainCanvas = Canvas(self, width=wwidth, height=wheight*9/10, bg=globs.CNIRLColor, highlightthickness=0)
self.pBarZone = Canvas(self, width=wwidth, height=wheight/10, bg=globs.CNIRLColor)
self.progressBar = ttk.Progressbar(self.pBarZone, orient=HORIZONTAL, length=wwidth-10, mode='determinate')
#self.update()
self.mainCanvas.create_text((wwidth / 2), (wheight / 3), text=(globs.CNIRName), font='Helvetica 30', fill='white')
self.msg = self.mainCanvas.create_text((wwidth / 2.05), (wheight / 1.20), text='', font='Helvetica 9', fill='white')
#self.update()
self.wm_title(globs.CNIRName)
# Centering
x = ws / 2 - wwidth / 2
y = hs / 2 - wheight / 2
self.geometry('%dx%d+%d+%d' % (wwidth, wheight, x, y))
self.mainCanvas.grid()
self.pBarZone.grid()
self.progressBar.grid()
#self.after(2000, updating)
if getattr(sys, 'frozen', False):
self.iconbitmap(sys._MEIPASS + '\\id-card.ico\\id-card.ico')
else:
self.iconbitmap('id-card.ico')
logfile = logger.logCur
logfile.printdbg('Launcher IHM successful')
self.protocol('WM_DELETE_WINDOW', lambda : self.destroy())
## Global Handler
launcherWindowCur = LauncherWindow()

64
src/launcher/logger.py Normal file
View File

@ -0,0 +1,64 @@
"""
********************************************************************************
* CNIRevelator *
* *
* Desc: Application launcher logging stuff *
* *
* Copyright © 2018-2019 Adrien Bourmault (neox95) *
* *
* This file is part of CNIRevelator. *
* *
* CNIRevelator is free software: you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation, either version 3 of the License, or *
* any later version. *
* *
* CNIRevelator 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 General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with CNIRevelator. If not, see <https:*www.gnu.org/licenses/>. *
********************************************************************************
"""
import logging
import globs
import os
## The logging class
class NewLoggingSystem:
def __init__(self):
# Deleting the error log
try:
os.remove(globs.CNIRFolder + '\\error.log') # The deletion does not working
except Exception as e:
#print(str(e) + " : " + str(globs.CNIRFolder + '\\error.log'))
pass
# Create new logging handle
logger = logging.getLogger()
logger.setLevel(logging.INFO) # To make sure we can have a debug channel
# Create channels
formatter = logging.Formatter("\n[ %(module)s/%(funcName)s ] %(asctime)s :: %(levelname)s :: %(message)s")
error_handler = logging.FileHandler((globs.CNIRFolder + '\\error.log'), mode='w', encoding='utf-8', delay=True)
info_handler = logging.FileHandler((globs.CNIRFolder + '\\launcher.log'), mode='w', encoding='utf-8')
error_handler.setLevel(logging.ERROR)
error_handler.setFormatter(formatter)
logger.addHandler(error_handler)
info_handler.setLevel(logging.DEBUG)
info_handler.setFormatter(formatter)
logger.addHandler(info_handler)
self.logger = logger
self.printerr = logger.error
self.printdbg = logger.info
## Global Handler
logCur = NewLoggingSystem()

91
src/launcher/updater.py Normal file
View File

@ -0,0 +1,91 @@
"""
********************************************************************************
* CNIRevelator *
* *
* Desc: Application launcher updating system *
* *
* Copyright © 2018-2019 Adrien Bourmault (neox95) *
* *
* This file is part of CNIRevelator. *
* *
* CNIRevelator is free software: you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation, either version 3 of the License, or *
* any later version. *
* *
* CNIRevelator 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 General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with CNIRevelator. If not, see <https:*www.gnu.org/licenses/>. *
********************************************************************************
"""
from win32com.client import Dispatch
import traceback
import sys
import time
import logger # logger.py
import globs # globs.py
import ihm # ihm.py
def createShortcut(path, target='', wDir='', icon=''):
ext = path[-3:]
if ext == 'url':
shortcut = file(path, 'w')
shortcut.write('[InternetShortcut]\n')
shortcut.write('URL=%s' % target)
shortcut.close()
else:
shell = Dispatch('WScript.Shell')
shortcut = shell.CreateShortCut(path)
shortcut.Targetpath = target
shortcut.WorkingDirectory = wDir
if icon == '':
pass
else:
shortcut.IconLocation = icon
shortcut.save()
## Main Batch Function
def batch():
# Global Handlers
logfile = logger.logCur
launcherWindow = ihm.launcherWindowCur
for i in range(0,10000):
if i % 1000 : launcherWindow.mainCanvas.itemconfigure(launcherWindow.msg, text=('Starting... ' + str(i)))
return
## Main Function
def umain():
try:
# Global Handlers
logfile = logger.logCur
launcherWindow = ihm.launcherWindowCur
try:
batch()
except Exception as e:
logfile.printerr("An error occured on the thread : " + str(traceback.format_exc()))
launcherWindow.mainCanvas.itemconfigure(launcherWindow.msg, text=('ERROR : ' + str(e)))
time.sleep(3)
launcherWindow.destroy()
return 1
launcherWindow.mainCanvas.itemconfigure(launcherWindow.msg, text='Software is up-to-date !')
time.sleep(2)
launcherWindow.destroy()
return 0
except:
logfile.printerr("A FATAL ERROR OCCURED : " + str(traceback.format_exc()))
launcherWindow.destroy()
sys.exit(2)
return 2