io4it 3.0.2__tar.gz → 3.0.2.2__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (93) hide show
  1. {io4it-3.0.2 → io4it-3.0.2.2}/PKG-INFO +1 -1
  2. {io4it-3.0.2 → io4it-3.0.2.2}/io4it.egg-info/PKG-INFO +1 -1
  3. {io4it-3.0.2 → io4it-3.0.2.2}/io4it.egg-info/SOURCES.txt +1 -1
  4. io4it-3.0.2/orangecontrib/IO4IT/utils/offuscation_basique.py → io4it-3.0.2.2/orangecontrib/IO4IT/utils/keys_manager.py +192 -18
  5. {io4it-3.0.2 → io4it-3.0.2.2}/orangecontrib/IO4IT/utils/mail.py +15 -15
  6. {io4it-3.0.2 → io4it-3.0.2.2}/orangecontrib/IO4IT/utils/utils_md.py +9 -4
  7. {io4it-3.0.2 → io4it-3.0.2.2}/orangecontrib/IO4IT/widgets/OWChatGpt.py +4 -4
  8. {io4it-3.0.2 → io4it-3.0.2.2}/orangecontrib/IO4IT/widgets/OWDeep_Search.py +3 -3
  9. {io4it-3.0.2 → io4it-3.0.2.2}/orangecontrib/IO4IT/widgets/OWExportMarkdown.py +24 -24
  10. {io4it-3.0.2 → io4it-3.0.2.2}/orangecontrib/IO4IT/widgets/OWExtractTablesDocxToXlsx.py +4 -1
  11. {io4it-3.0.2 → io4it-3.0.2.2}/orangecontrib/IO4IT/widgets/OWInboxMailMonitoring.py +5 -5
  12. {io4it-3.0.2 → io4it-3.0.2.2}/orangecontrib/IO4IT/widgets/OWPdfType.py +92 -51
  13. {io4it-3.0.2 → io4it-3.0.2.2}/orangecontrib/IO4IT/widgets/OWSpeechToText.py +3 -0
  14. {io4it-3.0.2 → io4it-3.0.2.2}/orangecontrib/IO4IT/widgets/OWWebSearch.py +3 -3
  15. io4it-3.0.2.2/orangecontrib/IO4IT/widgets/designer/owpdftype.ui +131 -0
  16. {io4it-3.0.2 → io4it-3.0.2.2}/setup.py +1 -1
  17. io4it-3.0.2/orangecontrib/IO4IT/widgets/designer/owpdftype.ui +0 -86
  18. {io4it-3.0.2 → io4it-3.0.2.2}/io4it.egg-info/dependency_links.txt +0 -0
  19. {io4it-3.0.2 → io4it-3.0.2.2}/io4it.egg-info/entry_points.txt +0 -0
  20. {io4it-3.0.2 → io4it-3.0.2.2}/io4it.egg-info/namespace_packages.txt +0 -0
  21. {io4it-3.0.2 → io4it-3.0.2.2}/io4it.egg-info/requires.txt +0 -0
  22. {io4it-3.0.2 → io4it-3.0.2.2}/io4it.egg-info/top_level.txt +0 -0
  23. {io4it-3.0.2 → io4it-3.0.2.2}/orangecontrib/IO4IT/__init__.py +0 -0
  24. {io4it-3.0.2 → io4it-3.0.2.2}/orangecontrib/IO4IT/ocr_function/__init__.py +0 -0
  25. {io4it-3.0.2 → io4it-3.0.2.2}/orangecontrib/IO4IT/ocr_function/word_converter.py +0 -0
  26. {io4it-3.0.2 → io4it-3.0.2.2}/orangecontrib/IO4IT/utils/__init__.py +0 -0
  27. {io4it-3.0.2 → io4it-3.0.2.2}/orangecontrib/IO4IT/utils/config.json +0 -0
  28. {io4it-3.0.2 → io4it-3.0.2.2}/orangecontrib/IO4IT/utils/pool_exec_utils.py +0 -0
  29. {io4it-3.0.2 → io4it-3.0.2.2}/orangecontrib/IO4IT/utils/secret_manager.py +0 -0
  30. {io4it-3.0.2 → io4it-3.0.2.2}/orangecontrib/IO4IT/widgets/OWDoclingASR.py +0 -0
  31. {io4it-3.0.2 → io4it-3.0.2.2}/orangecontrib/IO4IT/widgets/OWDoclingToMarkdown.py +0 -0
  32. {io4it-3.0.2 → io4it-3.0.2.2}/orangecontrib/IO4IT/widgets/OWMD2HTML.py +0 -0
  33. {io4it-3.0.2 → io4it-3.0.2.2}/orangecontrib/IO4IT/widgets/OWMarkdownLoader.py +0 -0
  34. {io4it-3.0.2 → io4it-3.0.2.2}/orangecontrib/IO4IT/widgets/OWMarkdownizer.py +0 -0
  35. {io4it-3.0.2 → io4it-3.0.2.2}/orangecontrib/IO4IT/widgets/OWOfficeNormalizer.py +0 -0
  36. {io4it-3.0.2 → io4it-3.0.2.2}/orangecontrib/IO4IT/widgets/OWParserHTML.py +0 -0
  37. {io4it-3.0.2 → io4it-3.0.2.2}/orangecontrib/IO4IT/widgets/OWProcessPoolExecutor.py +0 -0
  38. {io4it-3.0.2 → io4it-3.0.2.2}/orangecontrib/IO4IT/widgets/OWS3Uploader.py +0 -0
  39. {io4it-3.0.2 → io4it-3.0.2.2}/orangecontrib/IO4IT/widgets/OWS3downloader.py +0 -0
  40. {io4it-3.0.2 → io4it-3.0.2.2}/orangecontrib/IO4IT/widgets/OWS3list.py +0 -0
  41. {io4it-3.0.2 → io4it-3.0.2.2}/orangecontrib/IO4IT/widgets/OWmailLoader.py +0 -0
  42. {io4it-3.0.2 → io4it-3.0.2.2}/orangecontrib/IO4IT/widgets/OWmailSender.py +0 -0
  43. {io4it-3.0.2 → io4it-3.0.2.2}/orangecontrib/IO4IT/widgets/OWwordpdf2docx.py +0 -0
  44. {io4it-3.0.2 → io4it-3.0.2.2}/orangecontrib/IO4IT/widgets/__init__.py +0 -0
  45. {io4it-3.0.2 → io4it-3.0.2.2}/orangecontrib/IO4IT/widgets/designer/__init__.py +0 -0
  46. {io4it-3.0.2 → io4it-3.0.2.2}/orangecontrib/IO4IT/widgets/designer/nogui.ui +0 -0
  47. {io4it-3.0.2 → io4it-3.0.2.2}/orangecontrib/IO4IT/widgets/designer/ow_file_ext_selector.ui +0 -0
  48. {io4it-3.0.2 → io4it-3.0.2.2}/orangecontrib/IO4IT/widgets/designer/owchatgpt.ui +0 -0
  49. {io4it-3.0.2 → io4it-3.0.2.2}/orangecontrib/IO4IT/widgets/designer/owdeepsearch.ui +0 -0
  50. {io4it-3.0.2 → io4it-3.0.2.2}/orangecontrib/IO4IT/widgets/designer/owdoclingasr.ui +0 -0
  51. {io4it-3.0.2 → io4it-3.0.2.2}/orangecontrib/IO4IT/widgets/designer/owdoclingtomarkdown.ui +0 -0
  52. {io4it-3.0.2 → io4it-3.0.2.2}/orangecontrib/IO4IT/widgets/designer/owdocxtoxlsx.ui +0 -0
  53. {io4it-3.0.2 → io4it-3.0.2.2}/orangecontrib/IO4IT/widgets/designer/owexportmarkdown.ui +0 -0
  54. {io4it-3.0.2 → io4it-3.0.2.2}/orangecontrib/IO4IT/widgets/designer/owinboxmailmonitoring.ui +0 -0
  55. {io4it-3.0.2 → io4it-3.0.2.2}/orangecontrib/IO4IT/widgets/designer/owmailloader.ui +0 -0
  56. {io4it-3.0.2 → io4it-3.0.2.2}/orangecontrib/IO4IT/widgets/designer/owmailsender.ui +0 -0
  57. {io4it-3.0.2 → io4it-3.0.2.2}/orangecontrib/IO4IT/widgets/designer/owmarkdownizer.ui +0 -0
  58. {io4it-3.0.2 → io4it-3.0.2.2}/orangecontrib/IO4IT/widgets/designer/owmarkdownloader.ui +0 -0
  59. {io4it-3.0.2 → io4it-3.0.2.2}/orangecontrib/IO4IT/widgets/designer/owmd2html.ui +0 -0
  60. {io4it-3.0.2 → io4it-3.0.2.2}/orangecontrib/IO4IT/widgets/designer/owofficenormalizer.ui +0 -0
  61. {io4it-3.0.2 → io4it-3.0.2.2}/orangecontrib/IO4IT/widgets/designer/owparserhtml.ui +0 -0
  62. {io4it-3.0.2 → io4it-3.0.2.2}/orangecontrib/IO4IT/widgets/designer/owprocesspoolexecutor.ui +0 -0
  63. {io4it-3.0.2 → io4it-3.0.2.2}/orangecontrib/IO4IT/widgets/designer/owspeechtotext.ui +0 -0
  64. {io4it-3.0.2 → io4it-3.0.2.2}/orangecontrib/IO4IT/widgets/designer/owvisualizationer.ui +0 -0
  65. {io4it-3.0.2 → io4it-3.0.2.2}/orangecontrib/IO4IT/widgets/designer/owwebsearch.ui +0 -0
  66. {io4it-3.0.2 → io4it-3.0.2.2}/orangecontrib/IO4IT/widgets/designer/wordpdf2docx.ui +0 -0
  67. {io4it-3.0.2 → io4it-3.0.2.2}/orangecontrib/IO4IT/widgets/icons/__init__.py +0 -0
  68. {io4it-3.0.2 → io4it-3.0.2.2}/orangecontrib/IO4IT/widgets/icons/chatgpt.png +0 -0
  69. {io4it-3.0.2 → io4it-3.0.2.2}/orangecontrib/IO4IT/widgets/icons/check_pdf.png +0 -0
  70. {io4it-3.0.2 → io4it-3.0.2.2}/orangecontrib/IO4IT/widgets/icons/deepsearch.svg +0 -0
  71. {io4it-3.0.2 → io4it-3.0.2.2}/orangecontrib/IO4IT/widgets/icons/dep_md_old.png +0 -0
  72. {io4it-3.0.2 → io4it-3.0.2.2}/orangecontrib/IO4IT/widgets/icons/download.png +0 -0
  73. {io4it-3.0.2 → io4it-3.0.2.2}/orangecontrib/IO4IT/widgets/icons/export_md.png +0 -0
  74. {io4it-3.0.2 → io4it-3.0.2.2}/orangecontrib/IO4IT/widgets/icons/extract_table.png +0 -0
  75. {io4it-3.0.2 → io4it-3.0.2.2}/orangecontrib/IO4IT/widgets/icons/file_extensor.png +0 -0
  76. {io4it-3.0.2 → io4it-3.0.2.2}/orangecontrib/IO4IT/widgets/icons/html.png +0 -0
  77. {io4it-3.0.2 → io4it-3.0.2.2}/orangecontrib/IO4IT/widgets/icons/list_aws.png +0 -0
  78. {io4it-3.0.2 → io4it-3.0.2.2}/orangecontrib/IO4IT/widgets/icons/load_md.png +0 -0
  79. {io4it-3.0.2 → io4it-3.0.2.2}/orangecontrib/IO4IT/widgets/icons/mail_loader.png +0 -0
  80. {io4it-3.0.2 → io4it-3.0.2.2}/orangecontrib/IO4IT/widgets/icons/mail_writer.png +0 -0
  81. {io4it-3.0.2 → io4it-3.0.2.2}/orangecontrib/IO4IT/widgets/icons/md.png +0 -0
  82. {io4it-3.0.2 → io4it-3.0.2.2}/orangecontrib/IO4IT/widgets/icons/monitor-email.svg +0 -0
  83. {io4it-3.0.2 → io4it-3.0.2.2}/orangecontrib/IO4IT/widgets/icons/office_normalizer.png +0 -0
  84. {io4it-3.0.2 → io4it-3.0.2.2}/orangecontrib/IO4IT/widgets/icons/owmd2html.svg +0 -0
  85. {io4it-3.0.2 → io4it-3.0.2.2}/orangecontrib/IO4IT/widgets/icons/process_pool_executor.png +0 -0
  86. {io4it-3.0.2 → io4it-3.0.2.2}/orangecontrib/IO4IT/widgets/icons/speech_to_text.png +0 -0
  87. {io4it-3.0.2 → io4it-3.0.2.2}/orangecontrib/IO4IT/widgets/icons/upload.png +0 -0
  88. {io4it-3.0.2 → io4it-3.0.2.2}/orangecontrib/IO4IT/widgets/icons/visualizationer.png +0 -0
  89. {io4it-3.0.2 → io4it-3.0.2.2}/orangecontrib/IO4IT/widgets/icons/websearch.png +0 -0
  90. {io4it-3.0.2 → io4it-3.0.2.2}/orangecontrib/IO4IT/widgets/icons/wordpdf2docx.png +0 -0
  91. {io4it-3.0.2 → io4it-3.0.2.2}/orangecontrib/IO4IT/widgets/icons_dev/__init__.py +0 -0
  92. {io4it-3.0.2 → io4it-3.0.2.2}/orangecontrib/__init__.py +0 -0
  93. {io4it-3.0.2 → io4it-3.0.2.2}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: io4it
3
- Version: 3.0.2
3
+ Version: 3.0.2.2
4
4
  Home-page:
5
5
  Author:
6
6
  Author-email:
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: io4it
3
- Version: 3.0.2
3
+ Version: 3.0.2.2
4
4
  Home-page:
5
5
  Author:
6
6
  Author-email:
@@ -11,8 +11,8 @@ orangecontrib/IO4IT/__init__.py
11
11
  orangecontrib/IO4IT/ocr_function/__init__.py
12
12
  orangecontrib/IO4IT/ocr_function/word_converter.py
13
13
  orangecontrib/IO4IT/utils/__init__.py
14
+ orangecontrib/IO4IT/utils/keys_manager.py
14
15
  orangecontrib/IO4IT/utils/mail.py
15
- orangecontrib/IO4IT/utils/offuscation_basique.py
16
16
  orangecontrib/IO4IT/utils/pool_exec_utils.py
17
17
  orangecontrib/IO4IT/utils/secret_manager.py
18
18
  orangecontrib/IO4IT/utils/utils_md.py
@@ -135,7 +135,40 @@ def enregistrer_config_imap4_ssl(agent, my_domain, password, interval_second, al
135
135
  print(f"❌ Erreur lors de l'enregistrement : {e}")
136
136
  return 1
137
137
 
138
+ def enregistrer_config_imap4_ssl_secure(agent, my_domain, password, interval_second, alias=""):
139
+ try:
140
+ dossier = get_keys_dir("IMAP4_SSL")
141
+ # Crée le dossier s'il n'existe pas
142
+ if not os.path.exists(dossier):
143
+ os.makedirs(dossier)
138
144
 
145
+
146
+ # Nom du fichier (remplace @ par _at_ pour éviter les problèmes)
147
+ nom_fichier = os.path.join(dossier, f"{agent}{my_domain.replace('@', '_at_')}.sec")
148
+ service_name = f"IMAP4_SSL__{agent}{my_domain.replace('@', '_at_')}"
149
+ if alias == "''" or alias == "\"\"":
150
+ alias = ""
151
+
152
+ # Contenu à écrire dans le fichier
153
+ contenu = {
154
+ "agent": agent,
155
+ "domain": my_domain,
156
+ "interval_second": interval_second,
157
+ "password": password,
158
+ "alias": alias
159
+ }
160
+ sm = secret_manager.SecretManager(service_name)
161
+ sm.store(contenu)
162
+ # Écriture du fichier
163
+ with open(nom_fichier, "w", encoding="utf-8") as f:
164
+ pass
165
+
166
+ print(f"✅ Fichier enregistré : {nom_fichier}")
167
+ return 0
168
+
169
+ except Exception as e:
170
+ print(f"❌ Erreur lors de l'enregistrement : {e}")
171
+ return 1
139
172
  def enregistrer_config_owa(mail, alias, server, username, password, interval):
140
173
  try:
141
174
  dossier = get_keys_dir("MICROSOFT_EXCHANGE_OWA")
@@ -178,10 +211,6 @@ def enregistrer_config_owa_secure(mail, alias, server, username, password, inter
178
211
  if not os.path.exists(dossier):
179
212
  os.makedirs(dossier)
180
213
 
181
- # Récupère l'adresse MAC et chiffre le mot de passe
182
- key = get_user_key()
183
- mdp_chiffre = xor_crypt(password, key)
184
-
185
214
  # Nom du fichier (remplace @ par _at_ pour éviter les problèmes)
186
215
  nom_fichier = os.path.join(dossier, f"{alias.replace('@', '_at_')}.sec")
187
216
  service_name=f"MICROSOFT_EXCHANGE_OWA__{alias.replace('@', '_at_')}"
@@ -214,6 +243,25 @@ def enregistrer_config_owa_secure(mail, alias, server, username, password, inter
214
243
  # Fonction pour lire le fichier de configuration et déchiffrer le mot de passe
215
244
  def lire_config_imap4_ssl(chemin_fichier):
216
245
  # renvoie une liste =["agent","domain",mdp,"interval_second"]
246
+ if len(chemin_fichier)<5:
247
+ print(f"❌ Error path not correct", chemin_fichier)
248
+ return None
249
+ if chemin_fichier.endswith(".sec"):
250
+ try:
251
+ service = "IMAP4_SSL__" + chemin_fichier[:-4]
252
+ sm = secret_manager.SecretManager(service)
253
+ contenu = sm.load_all()
254
+ return [
255
+ contenu["agent"],
256
+ contenu["domain"],
257
+ contenu["password"],
258
+ int(contenu["interval_second"]),
259
+ contenu.get("alias", "")
260
+ ]
261
+
262
+ except Exception as e:
263
+ print(f"❌ Erreur lors de la lecture : {e}")
264
+ return None
217
265
  try:
218
266
  chemin_fichier = os.path.join(get_keys_dir("IMAP4_SSL"), chemin_fichier)
219
267
  # Lecture du fichier JSON
@@ -318,9 +366,14 @@ def enregistrer_config_cli_imap4_ssl():
318
366
  mdp = input("📨mot de passe? : ").strip()
319
367
  interval = int(input("⏱️ Intervalle en secondes : ").strip())
320
368
  alias = input("Nom de l'alias : ").strip()
321
- if 0 != enregistrer_config_imap4_ssl(agent, domaine, mdp, interval, alias):
369
+ store = ask_secure()
370
+ if not store:
371
+ if 0 != enregistrer_config_imap4_ssl(agent, domaine, mdp, interval, alias):
372
+ print("erreur!")
373
+ return
374
+ if 0 != enregistrer_config_imap4_ssl_secure(agent, domaine, mdp, interval, alias):
322
375
  print("erreur!")
323
-
376
+ return
324
377
 
325
378
  def enregistrer_config_cli_owa():
326
379
  print("\n📝 Écriture d’un fichier de configuration owa :")
@@ -335,7 +388,6 @@ def enregistrer_config_cli_owa():
335
388
  if alias == "''" or alias == "\"\"" or alias == "":
336
389
  alias = mail
337
390
  if not store:
338
- print("not secure")
339
391
  if 0 != enregistrer_config_owa(mail, alias, server, username, mdp, interval):
340
392
  print("erreur!")
341
393
  return
@@ -354,8 +406,8 @@ def enregistrer_config_cli_oauth2():
354
406
  client_secret_enc = xor_crypt(client_secret, key)
355
407
  tenant_id_enc = xor_crypt(tenant_id, key)
356
408
  nom_fichier = input("💾 Nom du fichier à enregistrer (ex: config_oauth2.json) : ").strip()
357
- choix_enregistrement = input("Voulez vous enregistrer en offuscation basique (1) ou enregistrer une clée dans "
358
- "le trousseau (2) ?")
409
+ choix_enregistrement = input("Voulez vous enregistrer en non securisé (1) ou enregistrer une clée dans "
410
+ "le trousseau (secure) (2) ?")
359
411
  match choix_enregistrement:
360
412
  case "1":
361
413
  config = {
@@ -393,7 +445,7 @@ def enregistrer_config_cli_oauth2():
393
445
 
394
446
 
395
447
  def lire_config_cli_oauth2():
396
- chemin_fichier = input("📄 non fichier json (pas le chemin!) JSON : ").strip()
448
+ chemin_fichier = input("📄 nom fichier json (pas le chemin!) JSON : ").strip()
397
449
  config = lire_config_oauth2(chemin_fichier)
398
450
  if config == None:
399
451
  print("erreur")
@@ -402,7 +454,7 @@ def lire_config_cli_oauth2():
402
454
 
403
455
 
404
456
  def lecture_config_cli_owa():
405
- chemin_fichier = input("📄 non fichier json (pas le chemin!) JSON ou sec : ").strip()
457
+ chemin_fichier = input("📄 nom fichier json ou sec (pas le chemin!) JSON / sec : ").strip()
406
458
  config = lire_config_owa(chemin_fichier)
407
459
 
408
460
  if config == None:
@@ -411,7 +463,7 @@ def lecture_config_cli_owa():
411
463
 
412
464
 
413
465
  def lire_config_cli_imap4_ssl():
414
- chemin_fichier = input("📄 non fichier json (pas le chemin!) JSON : ").strip()
466
+ chemin_fichier = input("📄 nom fichier json ou sec (pas le chemin!) JSON / SEC: ").strip()
415
467
  config = lire_config_imap4_ssl(chemin_fichier)
416
468
 
417
469
  if config == None:
@@ -444,11 +496,62 @@ def enregistrer_config_api(service_name, api_key, description=""):
444
496
  print(f"❌ Erreur d’enregistrement : {e}")
445
497
  return 1
446
498
 
499
+ # Gestion clés API (HARD dossier aait_store/keys)
500
+ # Enregistre un fichier JSON {service, api_key_encrypted, description}
501
+ def enregistrer_config_api_secure(service_name, api_key, description=""):
502
+ try:
503
+ dossier = get_keys_dir("API")
504
+ # Crée le dossier s'il n'existe pas
505
+ if not os.path.exists(dossier):
506
+ os.makedirs(dossier)
507
+ service_name_windows=f"API__{service_name}"
508
+
509
+
510
+ contenu = {
511
+ "service": service_name,
512
+ "api_key": api_key,
513
+ "description": description
514
+ }
515
+ sm = secret_manager.SecretManager(service_name_windows)
516
+ sm.store(contenu)
517
+ chemin_fic = os.path.join(get_keys_dir("API"), f"{service_name}.sec")
518
+ with open(chemin_fic, "w", encoding="utf-8") as fp:
519
+ pass
520
+
521
+ #print(f"✅ Fichier enregistré : {chemin_fic}")
522
+ #print(get_user_key())
523
+ return 0
524
+ except Exception as e:
525
+ print(f"❌ Erreur d’enregistrement : {e}")
526
+ return 1
447
527
 
448
528
  # Lecture + déchiffrement → dict {"service", "api_key", "description"}
449
529
  def lire_config_api(service_name):
530
+ chemin_sec = os.path.join(get_keys_dir("API"), f"{service_name}")
531
+ if not service_name.endswith(".sec"):
532
+ chemin_sec += ".sec"
533
+ if os.path.exists(chemin_sec):
534
+ try:
535
+ if service_name.endswith(".sec"):
536
+ service_name=service_name[:-4]
537
+ service=f"API__{service_name}"
538
+ sm = secret_manager.SecretManager(service)
539
+ contenu=sm.load_all()
540
+ return {
541
+ "service": contenu["service"],
542
+ "api_key": contenu["api_key"],
543
+ "description": contenu.get("description", "")
544
+ }
545
+
546
+
547
+ except Exception as e:
548
+ print(f"❌ Erreur lors de la lecture : {e}")
549
+ return None
550
+
450
551
  try:
451
- chemin_fic = os.path.join(get_keys_dir("API"), f"{service_name}.json")
552
+ chemin_fic = os.path.join(get_keys_dir("API"), f"{service_name}")
553
+ if not service_name.endswith(".json"):
554
+ chemin_fic += ".json"
452
555
  with open(chemin_fic, "r", encoding="utf-8") as fp:
453
556
  contenu = json.load(fp)
454
557
 
@@ -475,13 +578,18 @@ def enregistrer_config_cli_api():
475
578
  service = input("🔖 Nom du service : ").strip()
476
579
  api_key = input("🔑 Clé API : ").strip()
477
580
  desc = input("✏️ Description : ").strip()
478
- if 0 != enregistrer_config_api(service, api_key, desc):
581
+ store = ask_secure()
582
+ if not store:
583
+ if 0 != enregistrer_config_api(service, api_key, desc):
584
+ print("erreur!")
585
+ return
586
+ if 0 != enregistrer_config_api_secure(service, api_key, desc):
479
587
  print("erreur!")
480
588
 
481
589
 
482
590
  def lire_config_cli_api(service=""):
483
591
  if service == "":
484
- service = input("🔖 Nom du service : ").strip()
592
+ service = input("🔖 Nom du service (ou nom du fichier .sec/.json): ").strip()
485
593
  try:
486
594
  cfg = lire_config_api(service)
487
595
  if cfg is None:
@@ -529,10 +637,67 @@ def enregistrer_config_nxp(
529
637
  print(f"❌ Erreur d’enregistrement : {e}")
530
638
  return 1
531
639
 
640
+ def enregistrer_config_nxp_secure(
641
+ dossier_node_id: str,
642
+ serveur: str,
643
+ username: str,
644
+ password: str,
645
+ description: str = ""
646
+ ) -> int:
647
+ try:
648
+ service_name = f"NXP__{serveur}"
649
+ dossier = get_keys_dir("NXP")
650
+ # Crée le dossier s'il n'existe pas
651
+ if not os.path.exists(dossier):
652
+ os.makedirs(dossier)
653
+ contenu = {
654
+ "dossier_node_id": dossier_node_id,
655
+ "serveur": serveur,
656
+ "username": username,
657
+ "password": password,
658
+ "description": description
659
+ }
660
+ sm = secret_manager.SecretManager(service_name)
661
+ sm.store(contenu)
662
+ # ⬅️ Ici : plus de "conn_", juste {serveur}.json
663
+ chemin = os.path.join(get_keys_dir("NXP"), f"{serveur}.sec")
664
+ with open(chemin, "w", encoding="utf-8") as f:
665
+ pass
666
+
667
+ print(f"✅ Fichier enregistré : {chemin}")
668
+ return 0
669
+ except Exception as e:
670
+ print(f"❌ Erreur d’enregistrement : {e}")
671
+ return 1
672
+
532
673
 
533
674
  def lire_config_nxp(serveur: str) -> dict | None:
675
+ chemin_sec = os.path.join(get_keys_dir("NXP"), f"{serveur}")
676
+ if not serveur.endswith(".sec"):
677
+ chemin_sec += ".sec"
678
+ if os.path.exists(chemin_sec):
679
+ try:
680
+ if serveur.endswith(".sec"):
681
+ serveur=serveur[:-4]
682
+ service=f"NXP__{serveur}"
683
+ sm = secret_manager.SecretManager(service)
684
+ contenu=sm.load_all()
685
+ return {
686
+ "dossier_node_id": contenu["dossier_node_id"],
687
+ "serveur": contenu["serveur"],
688
+ "username": contenu["username"],
689
+ "password": contenu["password"],
690
+ "description": contenu["description"]
691
+ }
692
+
693
+ except Exception as e:
694
+ print(f"❌ Erreur lors de la lecture : {e}")
695
+ return None
696
+
534
697
  try:
535
- chemin = os.path.join(get_keys_dir("NXP"), f"{serveur}.json") # ⬅️ même logique
698
+ chemin = os.path.join(get_keys_dir("NXP"), f"{serveur}") # ⬅️ même logique
699
+ if not serveur.endswith(".json"):
700
+ chemin += ".json"
536
701
  with open(chemin, "r", encoding="utf-8") as f:
537
702
  contenu = json.load(f)
538
703
 
@@ -561,7 +726,17 @@ def enregistrer_config_cli_nxp():
561
726
  username = input("👤 USERNAME : ").strip()
562
727
  password = getpass.getpass("🔑 PASSWORD : ").strip()
563
728
  description = input("✏️ Description : ").strip()
564
- enregistrer_config_nxp(
729
+ store = ask_secure()
730
+ if not store:
731
+ enregistrer_config_nxp(
732
+ dossier_node_id,
733
+ serveur,
734
+ username,
735
+ password,
736
+ description
737
+ )
738
+ return
739
+ enregistrer_config_nxp_secure(
565
740
  dossier_node_id,
566
741
  serveur,
567
742
  username,
@@ -569,7 +744,6 @@ def enregistrer_config_cli_nxp():
569
744
  description
570
745
  )
571
746
 
572
-
573
747
  def lire_config_cli_nxp():
574
748
  serveur = input("🌐 SERVEUR : ").strip() # ⬅️ on demande le serveur
575
749
  cfg = lire_config_nxp(serveur)
@@ -24,10 +24,10 @@ from oauthlib.oauth2 import OAuth2Token
24
24
 
25
25
  if "site-packages/Orange/widgets" in os.path.dirname(os.path.abspath(__file__)).replace("\\", "/"):
26
26
  from Orange.widgets.orangecontrib.AAIT.utils import MetManagement
27
- from Orange.widgets.orangecontrib.IO4IT.utils import offuscation_basique
27
+ from Orange.widgets.orangecontrib.IO4IT.utils import keys_manager
28
28
  else:
29
29
  from orangecontrib.AAIT.utils import MetManagement
30
- from orangecontrib.IO4IT.utils import offuscation_basique
30
+ from orangecontrib.IO4IT.utils import keys_manager
31
31
 
32
32
 
33
33
  def clean_addresses(field,myemail):
@@ -62,7 +62,7 @@ def mail_in_folder(agent_name, type="in"):
62
62
  def check_new_emails(offusc_conf_agent,type_co, list_agent_email=[]):
63
63
  if type_co=="IMAP4_SSL":
64
64
  try:
65
- agent,my_domain,password,interl_seconds,alias=offuscation_basique.lire_config_imap4_ssl(offusc_conf_agent)
65
+ agent,my_domain,password,interl_seconds,alias=keys_manager.lire_config_imap4_ssl(offusc_conf_agent)
66
66
  myemail=agent + my_domain
67
67
  imap = imaplib.IMAP4_SSL("imap.gmail.com")
68
68
  imap.login(myemail, password)
@@ -74,7 +74,7 @@ def check_new_emails(offusc_conf_agent,type_co, list_agent_email=[]):
74
74
  else:
75
75
  for mail_id in mail_ids:
76
76
  if list_agent_email != []:
77
- white_list, black_list = offuscation_basique.lire_list_email(list_agent_email)
77
+ white_list, black_list = keys_manager.lire_list_email(list_agent_email)
78
78
  else:
79
79
  white_list=[]
80
80
  black_list=[]
@@ -194,7 +194,7 @@ def check_new_emails(offusc_conf_agent,type_co, list_agent_email=[]):
194
194
  print(f"Erreur lors de la vérification des mails : {e}")
195
195
  elif type_co=="MICROSOFT_EXCHANGE_OWA":
196
196
  try:
197
- mail, alias, server, username, password, interval_second = offuscation_basique.lire_config_owa(
197
+ mail, alias, server, username, password, interval_second = keys_manager.lire_config_owa(
198
198
  offusc_conf_agent)
199
199
  credentials = Credentials(username=username, password=password)
200
200
  config = Configuration(
@@ -219,7 +219,7 @@ def check_new_emails(offusc_conf_agent,type_co, list_agent_email=[]):
219
219
  else:
220
220
  for item in inbox.order_by('datetime_received'):
221
221
  if list_agent_email != []:
222
- white_list, black_list = offuscation_basique.lire_list_email(list_agent_email)
222
+ white_list, black_list = keys_manager.lire_list_email(list_agent_email)
223
223
  else:
224
224
  white_list, black_list = [], []
225
225
  if not isinstance(item,Message):
@@ -310,7 +310,7 @@ def check_new_emails(offusc_conf_agent,type_co, list_agent_email=[]):
310
310
  print(f"Erreur lors du traitement du mail : {e}")
311
311
  elif type_co == "MICROSOFT_EXCHANGE_OAUTH2":
312
312
  try:
313
- client_id, client_secret, tenant_id, user_email= offuscation_basique.lire_config_oauth2(
313
+ client_id, client_secret, tenant_id, user_email= keys_manager.lire_config_oauth2(
314
314
  offusc_conf_agent)
315
315
  authority = f"https://login.microsoftonline.com/{tenant_id}"
316
316
 
@@ -359,7 +359,7 @@ def check_new_emails(offusc_conf_agent,type_co, list_agent_email=[]):
359
359
  else:
360
360
  for item in inbox.order_by('datetime_received'):
361
361
  if list_agent_email:
362
- white_list, black_list = offuscation_basique.lire_list_email(list_agent_email)
362
+ white_list, black_list = keys_manager.lire_list_email(list_agent_email)
363
363
  else:
364
364
  white_list, black_list = [], []
365
365
 
@@ -436,7 +436,7 @@ def check_new_emails(offusc_conf_agent,type_co, list_agent_email=[]):
436
436
  elif type_co == "MICROSOFT_EXCHANGE_OAUTH2_MICROSOFT_GRAPH":
437
437
  try:
438
438
  print("🔍 [DEBUG] Début de la vérification des emails avec Microsoft Graph OAuth2")
439
- client_id, client_secret, tenant_id, user_email = offuscation_basique.lire_config_oauth2(
439
+ client_id, client_secret, tenant_id, user_email = keys_manager.lire_config_oauth2(
440
440
  offusc_conf_agent)
441
441
  print(f"🔍 [DEBUG] Configuration lue - User: {user_email}, Tenant: {tenant_id}")
442
442
 
@@ -513,7 +513,7 @@ def check_new_emails(offusc_conf_agent,type_co, list_agent_email=[]):
513
513
  for i, email_item in enumerate(emails_data['value']):
514
514
  print(f"🔍 [DEBUG] Traitement de l'email {i + 1}/{len(emails_data['value'])}")
515
515
  if list_agent_email:
516
- white_list, black_list = offuscation_basique.lire_list_email(list_agent_email)
516
+ white_list, black_list = keys_manager.lire_list_email(list_agent_email)
517
517
  print(f"🔍 [DEBUG] Listes chargées - White: {len(white_list)}, Black: {len(black_list)}")
518
518
  else:
519
519
  white_list, black_list = [], []
@@ -688,7 +688,7 @@ def send_mail(expediteur, offusc_conf_agent, destinataire, sujet, contenu_html,
688
688
  except Exception as e:
689
689
  print(f"Erreur lors de l'ajout de la pièce jointe '{piece_path}': {e}")
690
690
  try:
691
- _, _, mot_de_passe, _, _ = offuscation_basique.lire_config_imap4_ssl(offusc_conf_agent)
691
+ _, _, mot_de_passe, _, _ = keys_manager.lire_config_imap4_ssl(offusc_conf_agent)
692
692
  with smtplib.SMTP(serveur, port) as smtp:
693
693
  smtp.starttls()
694
694
  smtp.login(expediteur, mot_de_passe)
@@ -700,7 +700,7 @@ def send_mail(expediteur, offusc_conf_agent, destinataire, sujet, contenu_html,
700
700
 
701
701
  def check_send_new_emails(offusc_conf_agent,type_co):
702
702
  if type_co=="IMAP4_SSL":
703
- agent, domain, _, _,alias = offuscation_basique.lire_config_imap4_ssl(offusc_conf_agent)
703
+ agent, domain, _, _,alias = keys_manager.lire_config_imap4_ssl(offusc_conf_agent)
704
704
  mail = agent+domain
705
705
  if alias != "":
706
706
  agent = alias
@@ -733,7 +733,7 @@ def check_send_new_emails(offusc_conf_agent,type_co):
733
733
  print("Le dossier n'existe pas ou le chemin n'est pas un dossier.")
734
734
  elif type_co=="MICROSOFT_EXCHANGE_OWA":
735
735
  try:
736
- mail, alias, server, username, password, interval_second = offuscation_basique.lire_config_owa(
736
+ mail, alias, server, username, password, interval_second = keys_manager.lire_config_owa(
737
737
  offusc_conf_agent)
738
738
  credentials = Credentials(username=username, password=password)
739
739
  config = Configuration(server=server,
@@ -776,7 +776,7 @@ def check_send_new_emails(offusc_conf_agent,type_co):
776
776
  print(f"Erreur lors du traitement du mail : {e}")
777
777
  elif type_co == "MICROSOFT_EXCHANGE_OAUTH2":
778
778
  try:
779
- client_id, client_secret, tenant_id, user_email = offuscation_basique.lire_config_oauth2(
779
+ client_id, client_secret, tenant_id, user_email = keys_manager.lire_config_oauth2(
780
780
  offusc_conf_agent)
781
781
  # Déduire l'alias pour le nom du dossier
782
782
  agent = user_email
@@ -859,7 +859,7 @@ def check_send_new_emails(offusc_conf_agent,type_co):
859
859
  elif type_co == "MICROSOFT_EXCHANGE_OAUTH2_MICROSOFT_GRAPH":
860
860
  try:
861
861
  print("📤 [DEBUG] Début de la vérification des emails à envoyer avec Microsoft Graph OAuth2")
862
- client_id, client_secret, tenant_id, user_email = offuscation_basique.lire_config_oauth2(
862
+ client_id, client_secret, tenant_id, user_email = keys_manager.lire_config_oauth2(
863
863
  offusc_conf_agent)
864
864
  print(f"📤 [DEBUG] Configuration lue - User: {user_email}, Tenant: {tenant_id}")
865
865
 
@@ -1,6 +1,7 @@
1
1
  import re, hashlib, secrets, urllib.parse, logging, numpy as np
2
2
  from pathlib import Path
3
3
  import fitz # PyMuPDF
4
+ import win32com.client
4
5
 
5
6
  try:
6
7
  import easyocr
@@ -88,7 +89,6 @@ def _make_powerpoint_invisible(ppt):
88
89
  pass
89
90
 
90
91
  def convert_doc_to_docx(src: Path, out_dir: Path) -> Path:
91
- import win32com.client
92
92
  out_dir.mkdir(parents=True, exist_ok=True)
93
93
  if src.suffix.lower() != ".doc":
94
94
  return src if src.suffix.lower() == ".docx" else src
@@ -108,7 +108,7 @@ def convert_doc_to_docx(src: Path, out_dir: Path) -> Path:
108
108
  word.Quit()
109
109
 
110
110
  def convert_ppt_to_pptx(src: Path, out_dir: Path) -> Path:
111
- import win32com.client
111
+
112
112
  out_dir.mkdir(parents=True, exist_ok=True)
113
113
  if src.suffix.lower() != ".ppt":
114
114
  return src if src.suffix.lower() == ".pptx" else src
@@ -128,7 +128,6 @@ def convert_ppt_to_pptx(src: Path, out_dir: Path) -> Path:
128
128
  ppt.Quit()
129
129
 
130
130
  def docx_to_pdf(src_docx: Path, out_dir: Path) -> Path:
131
- import win32com.client
132
131
  out_dir.mkdir(parents=True, exist_ok=True)
133
132
  pdf_path = out_dir / (src_docx.stem + ".pdf")
134
133
  if pdf_path.exists() and pdf_path.stat().st_size > 0:
@@ -149,7 +148,6 @@ def docx_to_pdf(src_docx: Path, out_dir: Path) -> Path:
149
148
  word.Quit()
150
149
 
151
150
  def pptx_to_pdf(src_pptx: Path, out_dir: Path) -> Path:
152
- import win32com.client
153
151
  out_dir.mkdir(parents=True, exist_ok=True)
154
152
  pdf_path = out_dir / (src_pptx.stem + ".pdf")
155
153
  if pdf_path.exists() and pdf_path.stat().st_size > 0:
@@ -165,3 +163,10 @@ def pptx_to_pdf(src_pptx: Path, out_dir: Path) -> Path:
165
163
  return pdf_path
166
164
  finally:
167
165
  ppt.Quit()
166
+
167
+ def is_word_installed():
168
+ try:
169
+ win32com.client.Dispatch("Word.Application")
170
+ return True
171
+ except Exception:
172
+ return False
@@ -12,11 +12,11 @@ from AnyQt.QtWidgets import QApplication, QLineEdit, QSpinBox, QDoubleSpinBox, Q
12
12
  if "site-packages/Orange/widgets" in os.path.dirname(os.path.abspath(__file__)).replace("\\", "/"):
13
13
  from Orange.widgets.orangecontrib.AAIT.utils import thread_management
14
14
  from Orange.widgets.orangecontrib.AAIT.utils.import_uic import uic
15
- from Orange.widgets.orangecontrib.IO4IT.utils import offuscation_basique
15
+ from Orange.widgets.orangecontrib.IO4IT.utils import keys_manager
16
16
  else:
17
17
  from orangecontrib.AAIT.utils.import_uic import uic
18
18
  from orangecontrib.AAIT.utils import thread_management
19
- from orangecontrib.IO4IT.utils import offuscation_basique
19
+ from orangecontrib.IO4IT.utils import keys_manager
20
20
 
21
21
  class ChatGpt(OWWidget):
22
22
  name = "CallChatGptApi"
@@ -46,8 +46,8 @@ class ChatGpt(OWWidget):
46
46
  if "image_paths" in in_data.domain:
47
47
  self.image_paths = in_data.get_column("image_paths")[0]
48
48
  if "api_keys" not in in_data.domain:
49
- self.api_keys = offuscation_basique.lire_config_cli_api("CHAT_GPT")
50
- if offuscation_basique.lire_config_cli_api("CHAT_GPT") is None:
49
+ self.api_keys = keys_manager.lire_config_cli_api("CHAT_GPT")
50
+ if keys_manager.lire_config_cli_api("CHAT_GPT") is None:
51
51
  self.error("input table need a api_keys column or a folder API with you CHAT_GPT keys in aait store")
52
52
  if self.api_keys is None:
53
53
  self.api_keys = in_data.get_column("api_keys")[0]
@@ -15,13 +15,13 @@ if "site-packages/Orange/widgets" in os.path.dirname(os.path.abspath(__file__)).
15
15
  from Orange.widgets.orangecontrib.AAIT.utils import thread_management
16
16
  from Orange.widgets.orangecontrib.AAIT.utils.import_uic import uic
17
17
  from Orange.widgets.orangecontrib.AAIT.utils.initialize_from_ini import apply_modification_from_python_file
18
- from Orange.widgets.orangecontrib.IO4IT.utils.offuscation_basique import lire_config_api
18
+ from Orange.widgets.orangecontrib.IO4IT.utils.keys_manager import lire_config_api
19
19
  else:
20
20
  # from orangecontrib.AAIT.llm import answers
21
21
  from orangecontrib.AAIT.utils import thread_management
22
22
  from orangecontrib.AAIT.utils.import_uic import uic
23
23
  from orangecontrib.AAIT.utils.initialize_from_ini import apply_modification_from_python_file
24
- from orangecontrib.IO4IT.utils.offuscation_basique import lire_config_api
24
+ from orangecontrib.IO4IT.utils.keys_manager import lire_config_api
25
25
 
26
26
  @apply_modification_from_python_file(filepath_original_widget=__file__)
27
27
  class OWDeep_Search(widget.OWWidget):
@@ -86,7 +86,7 @@ class OWDeep_Search(widget.OWWidget):
86
86
  cfg = lire_config_api(self.SERVICE_NAME)
87
87
  if cfg is None:
88
88
  self.error(f"⚠️ No API key stored for service '{self.SERVICE_NAME}'.\n"
89
- "Use offuscation_basique.enregistrer_config_cli_api() to add one.")
89
+ "Use keys_manager.enregistrer_config_cli_api() to add one.")
90
90
  self.api_key = None
91
91
  else:
92
92
  self.api_key = cfg["api_key"]
@@ -19,8 +19,10 @@ from docx2pdf import convert
19
19
  # Chargement UI
20
20
  if "site-packages/Orange/widgets" in os.path.dirname(os.path.abspath(__file__)).replace("\\", "/"):
21
21
  from Orange.widgets.orangecontrib.AAIT.utils.import_uic import uic
22
+ from Orange.widgets.orangecontrib.IO4IT.utils import utils_md
22
23
  else:
23
24
  from orangecontrib.AAIT.utils.import_uic import uic
25
+ from orangecontrib.IO4IT.utils import utils_md
24
26
 
25
27
 
26
28
  class OWExportMarkdown(widget.OWWidget):
@@ -164,32 +166,30 @@ class OWExportMarkdown(widget.OWWidget):
164
166
  tmp_md = tmp.name
165
167
 
166
168
  try:
167
- # DOCX
168
- pypandoc.convert_file(tmp_md, to="docx", format="gfm-yaml_metadata_block", outputfile=docx_out)
169
- self.ajouter_en_tete_pied_docx(
170
- docx_out,
171
- "Rapport - Orange AI",
172
- "Page générée automatiquement - Ne pas diffuser"
173
- )
174
-
175
- # PPTX
176
- pypandoc.convert_file(tmp_md, to="pptx", format="gfm-yaml_metadata_block", outputfile=pptx_out)
177
- self.ajouter_entete_pied_pptx(
178
- pptx_out,
179
- "Orange AI – Présentation",
180
- "Page générée automatiquement"
181
- )
182
-
183
- # PDF (docx -> pdf) avec chemin de sortie exact
169
+ if utils_md.is_word_installed():
170
+ pypandoc.convert_file(tmp_md, to="docx", format="gfm-yaml_metadata_block", outputfile=docx_out)
171
+ self.ajouter_en_tete_pied_docx(
172
+ docx_out,
173
+ "Rapport - Orange AI",
174
+ "Page générée automatiquement - Ne pas diffuser"
175
+ )
176
+
177
+ # PPTX
178
+ pypandoc.convert_file(tmp_md, to="pptx", format="gfm-yaml_metadata_block", outputfile=pptx_out)
179
+ self.ajouter_entete_pied_pptx(
180
+ pptx_out,
181
+ "Orange AI – Présentation",
182
+ "Page générée automatiquement"
183
+ )
184
+ else:
185
+ raise Exception("Word non détecté")
186
+
187
+ except Exception:
184
188
  try:
185
- convert(docx_out, pdf_out)
189
+ pypandoc.convert_file(tmp_md, to="pdf", outputfile=pdf_out)
186
190
  except Exception:
187
- # fallback pandoc->pdf (si LaTeX dispo)
188
- try:
189
- pypandoc.convert_file(tmp_md, to="pdf", outputfile=pdf_out)
190
- except Exception:
191
- self.error(f"Échec conversion PDF pour la ligne {i+1}.")
192
- pdf_out = ""
191
+ self.error(f"Échec conversion PDF pour la ligne {i + 1}.")
192
+ pdf_out = ""
193
193
  finally:
194
194
  try:
195
195
  os.remove(tmp_md)
@@ -349,4 +349,7 @@ if __name__ == "__main__":
349
349
  app = QApplication(sys.argv)
350
350
  my_widget = OWExtractTablesDocxToXlsx()
351
351
  my_widget.show()
352
- app.exec()
352
+ if hasattr(app, "exec"):
353
+ app.exec()
354
+ else:
355
+ app.exec_()