bcpkgfox 0.17.14__py3-none-any.whl → 0.18.1__py3-none-any.whl

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.

Potentially problematic release.


This version of bcpkgfox might be problematic. Click here for more details.

bcpkgfox/login_2factor.py CHANGED
@@ -1,10 +1,22 @@
1
1
  import requests, time
2
+ from selenium.common import TimeoutException, WebDriverException, NoSuchElementException, NoAlertPresentException
3
+ from selenium.webdriver.common.by import By
4
+ from selenium.webdriver.common.keys import Keys
5
+ from selenium.webdriver.support.wait import WebDriverWait
6
+ from selenium.webdriver.support import expected_conditions as ec
7
+
8
+ from bcpkgfox import login_2fac
9
+
2
10
 
3
11
  class Login2facmycena:
4
- def __init__(self, uf, sistema, advogado, token, maximo = 5):
12
+ def __init__(self, uf, sistema, advogado, token, maximo = 10):
5
13
  self.codes = None
6
- self.api = ApiControll(uf, sistema, advogado, token)
14
+ self._api = _ApiControll(uf, sistema, advogado, token)
7
15
  self.code_timeout = maximo
16
+ self.uf = uf
17
+ self.sistema = sistema
18
+ self.advogado = advogado
19
+ self.token = token
8
20
 
9
21
  def processar_codes(self):
10
22
  max_attempts = self.code_timeout
@@ -13,24 +25,34 @@ class Login2facmycena:
13
25
 
14
26
  while five_attempts <= max_attempts:
15
27
  five_attempts += 1
16
- self.codes = self.api.listar_codigos_otp()
28
+ self.codes = self._api.listar_codigos_otp()
17
29
  if self.codes:
18
30
  print("Códigos obtidos com sucesso:")
19
31
  return self.codes
20
32
  else:
21
33
  print("Solicitando novo codigo.")
22
- self.api.solicitar_codigos_otp()
23
- time.sleep(10)
34
+ self._api.solicitar_codigos_otp()
35
+ time.sleep(5)
24
36
  while ten_attempts <=10:
25
37
  ten_attempts += 1
26
- self.codes = self.api.listar_codigos_otp()
38
+ self.codes = self._api.listar_codigos_otp()
27
39
  if self.codes:
28
40
  return self.codes
29
- time.sleep(10)
41
+ time.sleep(5)
30
42
  return None
31
43
 
44
+ def login_eproc(self, driver, url, tipo_login="mysena"):
45
+ login = _LoginEproc(driver, self._api, url, self.uf, self.sistema, self.advogado, self.token, tipo_login, self.processar_codes)
46
+ login.login()
47
+ return True
32
48
 
33
- class ApiControll:
49
+ def login_pje(self, driver, url, tipo_login="mysena"):
50
+ login = _LoginPje(driver, self._api, url, self.uf, self.sistema, self.advogado, self.token, tipo_login,
51
+ self.processar_codes)
52
+ login.login()
53
+ return True
54
+
55
+ class _ApiControll:
34
56
  def __init__(self, uf, sistema, advogado, tk):
35
57
  super().__init__()
36
58
  self.uf = uf
@@ -96,3 +118,902 @@ class ApiControll:
96
118
  return None
97
119
 
98
120
 
121
+ class _LoginEproc:
122
+ def __init__(self, driver, api, url_procurada, uf, sistema, advogado, token, tipo_login="mysena", processar_codes=None):
123
+ self.driver = driver
124
+ self.api = api
125
+ self.uf = uf
126
+ self.sistema = sistema
127
+ self.advogado = advogado
128
+ self.url_procurada = url_procurada
129
+ self.tipo_login = tipo_login.lower if tipo_login else "mysena"
130
+ self._util = _Utils(driver, api, url_procurada, uf, sistema, advogado, token,tipo_login)
131
+ self.processar_codes = processar_codes
132
+
133
+ def login(self):
134
+ """
135
+ Realiza o login no sistema EPROC.
136
+
137
+ Prioridade:
138
+ 1. Verifica se já está logado
139
+ 2. Login via WHOM (para estados específicos: RJ, TO)
140
+ 3. Login via Certificado Digital + 2FA (método principal)
141
+ """
142
+ print(f"\n{'='*60}")
143
+ print(f"[LOGIN] Acessando: {self.url_procurada}")
144
+ print(f"{'='*60}")
145
+
146
+ self.driver.get(f"{self.url_procurada}")
147
+ time.sleep(2)
148
+
149
+ # ══════════════════════════════════════════════════════════════
150
+ # PRIORIDADE 1: Verifica se já está logado
151
+ # ══════════════════════════════════════════════════════════════
152
+ if self._verificar_ja_logado():
153
+ return
154
+
155
+ # ══════════════════════════════════════════════════════════════
156
+ # PRIORIDADE 2: Login via WHOM (estados específicos)
157
+ # ══════════════════════════════════════════════════════════════
158
+ if self._util.deve_usar_whom():
159
+ # Verifica se o login foi bem-sucedido
160
+ self._util.login_via_whom()
161
+ if self._confere_login_sucesso():
162
+ print(" ✓ Login via WHOM realizado com sucesso!")
163
+ self._finalizar_login()
164
+ return True
165
+ else:
166
+ print("⚠ Login via WHOM falhou. Não há fallback disponível para este estado.")
167
+ raise Exception("Falha no login via WHOM")
168
+
169
+
170
+
171
+ # ══════════════════════════════════════════════════════════════
172
+ # PRIORIDADE 3: Login via Certificado Digital + 2FA
173
+ # ══════════════════════════════════════════════════════════════
174
+ self._login_via_certificado_digital()
175
+
176
+ def _verificar_ja_logado(self):
177
+ """
178
+ Verifica se o usuário já está logado no sistema.
179
+ Retorna True se já está logado, False caso contrário.
180
+ """
181
+ print("\n[1/3] Verificando se já está logado...")
182
+
183
+ response_login_sucesso = self._confere_login_sucesso()
184
+ if response_login_sucesso:
185
+ print(" ✓ Já estava logado no sistema.")
186
+ self._finalizar_login()
187
+ return True
188
+
189
+ print(" → Usuário não está logado. Prosseguindo com autenticação...")
190
+ return False
191
+
192
+ def _confere_login_sucesso(self):
193
+ """
194
+ Verifica se o login foi bem-sucedido.
195
+ Retorna False se encontrar elementos de login (usuário não está logado).
196
+ Retorna True se não encontrar elementos de login (usuário está logado).
197
+ """
198
+ self._confere_e_aceita_popup_advogado_logado()
199
+
200
+ try:
201
+ # Tenta encontrar qualquer elemento que indique tela de login
202
+ # Usando XPath com OR para cobrir múltiplas variações
203
+ self._util.find_clickable_element_with_wait(By.XPATH, "//button[@id='kc-login-certificate'] | //input[@value='Certificado Digital'] | //input[contains(@onclick, 'SubmitCert')]", timeout=10)
204
+ # Se encontrou algum elemento de login, significa que NÃO está logado
205
+ return False
206
+ except Exception:
207
+ # Se não encontrou elementos de login, está logado
208
+ return True
209
+
210
+ def _login_via_certificado_digital(self, tentativa=1):
211
+ """
212
+ Realiza login via Certificado Digital + código 2FA.
213
+
214
+ Fluxo:
215
+ 1. Clica no botão de Certificado Digital (se estiver na tela de login)
216
+ 2. Fica na tela de 2FA até conseguir logar
217
+ 3. Se der erro, recarrega a página e tenta novo código
218
+
219
+ Args:
220
+ tentativa: Número da tentativa atual (máximo 5)
221
+ """
222
+ max_tentativas = 5
223
+
224
+ print(f"\n[LOGIN CERTIFICADO] Tentativa {tentativa}/{max_tentativas}")
225
+ print(" → Método: Certificado Digital + 2FA")
226
+
227
+ try:
228
+ # ─────────────────────────────────────────────────────────
229
+ # PASSO 1: Verificar estado atual da página
230
+ # ─────────────────────────────────────────────────────────
231
+ print("\n [Passo 1/4] Verificando estado da página...")
232
+
233
+ # Verifica se voltou para tela de login (usuário/senha)
234
+ if self._esta_na_tela_login():
235
+ print(" → Está na tela de login. Clicando em Certificado Digital...")
236
+ btn_certificado = self._util.find_clickable_element_with_wait(
237
+ By.XPATH,
238
+ "//button[@id='kc-login-certificate'] | //input[@value='Certificado Digital'] | //input[contains(@onclick, 'SubmitCert')]",
239
+ timeout=20,
240
+ )
241
+ btn_certificado.click()
242
+ print(" ✓ Botão Certificado Digital clicado")
243
+ time.sleep(3)
244
+
245
+ # Verifica se apareceu algum alert (erro de certificado)
246
+ if self._tratar_alert_login(tentativa, max_tentativas):
247
+ return
248
+
249
+ # Verifica erro de conexão
250
+ if self._verificar_erro_conexao():
251
+ if tentativa < max_tentativas:
252
+ return self._login_via_certificado_digital(tentativa + 1)
253
+ else:
254
+ raise Exception("Erro de conexão persistente após múltiplas tentativas")
255
+
256
+ # ─────────────────────────────────────────────────────────
257
+ # PASSO 2: Verificar se já logou direto (sem 2FA)
258
+ # ─────────────────────────────────────────────────────────
259
+ print("\n [Passo 2/4] Verificando se já está logado...")
260
+
261
+ if self._verificar_login_sucesso_direto():
262
+ print(" ✓ Login realizado sem necessidade de 2FA!")
263
+ self._finalizar_login()
264
+ return
265
+
266
+ # ─────────────────────────────────────────────────────────
267
+ # PASSO 3: Loop de tentativas de código 2FA
268
+ # ─────────────────────────────────────────────────────────
269
+ print("\n [Passo 3/4] Entrando no loop de validação 2FA...")
270
+
271
+ tentativas_2fa = 0
272
+ max_tentativas_2fa = 5
273
+
274
+ while tentativas_2fa < max_tentativas_2fa:
275
+ tentativas_2fa += 1
276
+ print(f"\n [2FA] Tentativa {tentativas_2fa}/{max_tentativas_2fa}")
277
+
278
+ # Verifica se voltou para tela de login (sessão expirou)
279
+ if self._esta_na_tela_login():
280
+ print(" ⚠ Voltou para tela de login. Reiniciando processo...")
281
+ return self._login_via_certificado_digital(tentativa + 1)
282
+
283
+ # Verifica se já está logado
284
+ if self._verificar_login_sucesso_direto():
285
+ print(" ✓ Login bem-sucedido!")
286
+ self._finalizar_login()
287
+ return
288
+
289
+ # Verifica se está na tela de 2FA
290
+ if not self._esta_na_tela_2fa():
291
+ print(" ⚠ Não está na tela de 2FA. Recarregando página...")
292
+ self.driver.refresh()
293
+ time.sleep(3)
294
+ continue
295
+
296
+ # Obtém novo código 2FA
297
+ code = self._obter_codigo_2fa()
298
+ if not code:
299
+ print(" ✗ Falha ao obter código. Recarregando página...")
300
+ self.driver.refresh()
301
+ time.sleep(3)
302
+ continue
303
+
304
+ print(f" ✓ Código 2FA obtido: {code[:2]}****")
305
+
306
+ # Localiza e preenche o campo 2FA
307
+ try:
308
+ campo_2fa = self._util.find_element_with_wait(
309
+ By.XPATH,
310
+ "//*[self::input[@id='txtAcessoCodigo'] or self::input[@id='otp']]",
311
+ timeout=10,
312
+ )
313
+ campo_2fa.clear()
314
+ campo_2fa.send_keys(code)
315
+ print(" ✓ Código inserido no campo")
316
+ except TimeoutException:
317
+ print(" ✗ Campo 2FA não encontrado. Recarregando página...")
318
+ self.driver.refresh()
319
+ time.sleep(3)
320
+ continue
321
+
322
+ # ─────────────────────────────────────────────────────────
323
+ # PASSO 4: Confirmar login
324
+ # ─────────────────────────────────────────────────────────
325
+ print("\n [Passo 4/4] Confirmando login...")
326
+
327
+ # Pressiona ENTER para confirmar
328
+ campo_2fa.send_keys(Keys.ENTER)
329
+ print(" ✓ ENTER pressionado para confirmar")
330
+
331
+ time.sleep(3)
332
+
333
+ # Verifica se apareceu alert após confirmar
334
+ self._tratar_alert_login(tentativa, max_tentativas)
335
+
336
+ # Verifica erro de 2FA (div de erro) - NÃO clica em cancelar, apenas recarrega
337
+ if self._verificar_erro_2fa():
338
+ print(" → Recarregando página para tentar novo código...")
339
+ self.driver.refresh()
340
+ time.sleep(3)
341
+ continue
342
+
343
+ # Verifica se login foi bem-sucedido
344
+ time.sleep(2)
345
+ if self._verificar_login_sucesso_direto():
346
+ print("\n ✓ Login via Certificado Digital realizado com sucesso!")
347
+ self._finalizar_login()
348
+ return
349
+
350
+ # Verifica se voltou para tela de login
351
+ if self._esta_na_tela_login():
352
+ print(" ⚠ Voltou para tela de login. Reiniciando processo...")
353
+ return self._login_via_certificado_digital(tentativa + 1)
354
+
355
+ print(" ⚠ Login não confirmado. Tentando novo código...")
356
+
357
+ # Esgotou tentativas de 2FA
358
+ raise Exception(f"Falha no login após {max_tentativas_2fa} tentativas de 2FA")
359
+
360
+ except TimeoutException as e:
361
+ print(f"\n ✗ Timeout durante login: {e}")
362
+ if tentativa < max_tentativas:
363
+ print(f" → Tentando novamente ({tentativa + 1}/{max_tentativas})...")
364
+ time.sleep(2)
365
+ return self._login_via_certificado_digital(tentativa + 1)
366
+ else:
367
+ raise Exception("Falha no login: timeout aguardando elementos da página")
368
+
369
+ except Exception as e:
370
+ print(f"\n ✗ Erro durante login: {e}")
371
+ if tentativa < max_tentativas and "Alert" not in str(e):
372
+ print(f" → Tentando novamente ({tentativa + 1}/{max_tentativas})...")
373
+ time.sleep(2)
374
+ return self._login_via_certificado_digital(tentativa + 1)
375
+ else:
376
+ raise Exception(f"Falha no login via certificado: {e}")
377
+
378
+ def _esta_na_tela_login(self):
379
+ """
380
+ Verifica se está na tela de login (usuário/senha).
381
+ """
382
+ try:
383
+ self.driver.find_element(
384
+ By.XPATH,
385
+ "//button[@id='kc-login-certificate'] | //input[@value='Certificado Digital'] | //input[contains(@onclick, 'SubmitCert')]",
386
+ )
387
+ return True
388
+ except NoSuchElementException:
389
+ return False
390
+
391
+ def _esta_na_tela_2fa(self):
392
+ """
393
+ Verifica se está na tela de inserção do código 2FA.
394
+ """
395
+ try:
396
+ self.driver.find_element(By.XPATH, "//*[self::input[@id='txtAcessoCodigo'] or self::input[@id='otp']]")
397
+ return True
398
+ except NoSuchElementException:
399
+ return False
400
+
401
+ def _obter_codigo_2fa(self):
402
+ """
403
+ Obtém o código 2FA via API (login_2factor).
404
+ Retorna o código ou None se falhar.
405
+ """
406
+ try:
407
+
408
+ code = self.processar_codes()
409
+ return code
410
+ except Exception as e:
411
+ print(f" ✗ Erro ao obter código 2FA: {e}")
412
+ return None
413
+
414
+ def _tratar_alert_login(self, tentativa, max_tentativas):
415
+ """
416
+ Verifica e trata alerts que podem aparecer durante o login.
417
+
418
+ Retorna:
419
+ True se um alert foi tratado (e retry foi feito se necessário)
420
+ False se não havia alert
421
+ """
422
+ try:
423
+ alert = self.driver.switch_to.alert
424
+ alert_text = alert.text
425
+ print(f"\n ⚠ Alert detectado: {alert_text}")
426
+ alert.accept()
427
+
428
+ # Se for alert de login inválido, tenta novamente
429
+ if "inválido" in alert_text.lower() or "Login []" in alert_text:
430
+ if tentativa < max_tentativas:
431
+ print(f" → Tentando login novamente ({tentativa + 1}/{max_tentativas})...")
432
+ time.sleep(2)
433
+ self._login_via_certificado_digital(tentativa + 1)
434
+ return True
435
+ else:
436
+ raise Exception(f"Login falhou após {max_tentativas} tentativas: {alert_text}")
437
+
438
+ return True
439
+
440
+ except NoSuchElementException:
441
+ return False
442
+ except Exception as e:
443
+ if "no such alert" in str(e).lower() or "no alert" in str(e).lower():
444
+ return False
445
+ raise
446
+
447
+ def _verificar_erro_conexao(self):
448
+ """
449
+ Verifica se houve erro de conexão na página.
450
+ Se detectar, faz refresh e retorna True.
451
+ """
452
+ page_source_lower = self.driver.page_source.lower()
453
+ if "conexão interrompida" in page_source_lower or "connection interrupted" in page_source_lower:
454
+ print(" ⚠ Conexão interrompida detectada, fazendo refresh...")
455
+ self.driver.refresh()
456
+ time.sleep(3)
457
+ return True
458
+ return False
459
+
460
+ def _verificar_erro_2fa(self):
461
+ """
462
+ Verifica se apareceu erro de validação do código 2FA.
463
+ Retorna True se erro detectado, False caso contrário.
464
+ """
465
+ try:
466
+ div_erro = self.driver.find_element(By.ID, "divErro")
467
+ if div_erro.is_displayed():
468
+ texto_erro = div_erro.text
469
+ print(f" ⚠ Erro de 2FA detectado: {texto_erro}")
470
+ return True
471
+ except NoSuchElementException:
472
+ pass
473
+ return False
474
+
475
+ def _verificar_login_sucesso_direto(self):
476
+ """
477
+ Verifica se o login foi feito diretamente (sem necessidade de 2FA).
478
+ """
479
+ page_source = self.driver.page_source
480
+ indicadores_sucesso = ["Painel do Advogado", "Citações/Intimações", "Painel do usuário", "selInfraUnidades", "Seleção de perfil"]
481
+ return any(indicador in page_source for indicador in indicadores_sucesso)
482
+
483
+ def _finalizar_login(self):
484
+ """
485
+ Finaliza o processo de login verificando popups e seleção de perfil.
486
+ """
487
+ print("\n[FINALIZANDO LOGIN]")
488
+
489
+ # Aceita popups se houver
490
+ self._confere_e_aceita_popup_advogado_logado()
491
+
492
+ # Verifica e seleciona perfil de advogado se necessário
493
+ response_perfil = self._confere_tela_de_selecao_de_perfil()
494
+ if response_perfil:
495
+ print(" → Selecionando perfil de advogado...")
496
+ self._selecionar_perfil_advogado()
497
+
498
+ print(" ✓ Login finalizado com sucesso!\n")
499
+
500
+ def _confere_tela_de_selecao_de_perfil(self):
501
+ """
502
+ Verifica se a tela de seleção de perfil está presente.
503
+ """
504
+ try:
505
+ elemento_perfil = self._util.find_element_with_wait(By.XPATH, "//*[contains(text(), 'Seleção de perfil')]", 5)
506
+ if elemento_perfil:
507
+ return True
508
+ except TimeoutException:
509
+ if "Seleção de perfil" in self.driver.page_source:
510
+ return True
511
+ else:
512
+ return False
513
+
514
+ def _confere_e_aceita_popup_advogado_logado(self, refresh=False):
515
+ """
516
+ Função que busca um alerta na página e aceita o mesmo.
517
+ """
518
+ try:
519
+ alert = WebDriverWait(self.driver, 5).until(ec.alert_is_present())
520
+ alert.accept()
521
+ time.sleep(1)
522
+ if refresh:
523
+ self.driver.refresh()
524
+ return True
525
+ except TimeoutException:
526
+ return False
527
+ except NoAlertPresentException:
528
+ return False
529
+
530
+ def _selecionar_perfil_advogado(self):
531
+ """
532
+ Seleciona o perfil de advogado na tela de seleção de perfil.
533
+ """
534
+
535
+ try:
536
+ botao_advogado = self._util.find_element_with_wait(By.XPATH, "//button[@id='tr0']", 10)
537
+ botao_advogado.click()
538
+ except TimeoutException:
539
+ forms_de_perfis = self._util.find_element_with_wait(By.XPATH, "//form[@id='frmEscolherUsuario']", 10)
540
+ primeira_opcao = self._util.find_element_with_wait(By.XPATH, ".//button[contains(@id, 'tr0')]", 10,
541
+ parent=forms_de_perfis)
542
+ primeira_opcao.click()
543
+
544
+ return
545
+
546
+ class _LoginPje:
547
+ def __init__(self, driver, api, url_procurada, uf, sistema, advogado, token, tipo_login="mysena", processar_codes=None):
548
+ self.driver = driver
549
+ self.api = api
550
+ self.uf = uf
551
+ self.sistema = sistema
552
+ self.advogado = advogado
553
+ self.url_procurada = url_procurada
554
+ self.tipo_login = tipo_login.lower if tipo_login else "mysena"
555
+ self._util = _Utils(driver, api, url_procurada, uf, sistema, advogado, token,tipo_login)
556
+ self.processar_codes = processar_codes
557
+
558
+ def login(self):
559
+ """
560
+ Realiza o login no sistema EPROC.
561
+
562
+ Prioridade:
563
+ 1. Verifica se já está logado
564
+ 2. Login via WHOM (para estados específicos: RJ, TO)
565
+ 3. Login via Certificado Digital + 2FA (método principal)
566
+ """
567
+ print(f"\n{'='*60}")
568
+ print(f"[LOGIN] Acessando: {self.url_procurada}")
569
+ print(f"{'='*60}")
570
+
571
+ self.driver.get(f"{self.url_procurada}")
572
+ time.sleep(2)
573
+
574
+ # ══════════════════════════════════════════════════════════════
575
+ # PRIORIDADE 1: Verifica se já está logado
576
+ # ══════════════════════════════════════════════════════════════
577
+ if self._verificar_ja_logado():
578
+ return True
579
+
580
+ print(f"{self.url_procurada}")
581
+ self.driver.get(f"{self.url_procurada}")
582
+ self.driver.execute_script("document.body.style.zoom='90%'")
583
+
584
+
585
+ el_peticionar = '//td[contains(@id,"tabExpedientes_lbl") or contains(text(),"Expedientes")]'
586
+ time.sleep(1)
587
+ if "EXPEDIENTES" in self.driver.page_source or "ciência" in self.driver.page_source or "Ciencia" in self.driver.page_source or "Selecione uma jurisdição ou caixa" in self.driver.page_source:
588
+ print("Já logado, continuando o código.")
589
+ if "Número do processo" in self.driver.page_source and "Quadro de avisos" not in self.driver.page_source:
590
+ self._util.find_element_with_wait(
591
+ By.XPATH,
592
+ '//td[contains(@id,"tabExpedientes_lbl")] or //td[contains(text(),"Expedientes")]',
593
+ ).click()
594
+
595
+ self._fechar_popup_certificado()
596
+ return True
597
+
598
+ if "Avisos" in self.driver.page_source or "Mensagens" in self.driver.page_source or "Painel do usuário" in self.driver.page_source:
599
+ try:
600
+ btn_painel = self._util.find_element_with_wait(By.XPATH, "//input[contains(@value, 'Painel do usuário')]")
601
+ self.driver.execute_script("arguments[0].click();", btn_painel)
602
+ except BaseException:
603
+ if self._util.verificar_home_seam_atual():
604
+ link_redirect = self._util.find_element_with_wait(By.XPATH, "//a[contains(@href,'painel')]")
605
+ link_redirect = link_redirect.get_attribute("href")
606
+ self.driver.get(link_redirect)
607
+ time.sleep(2)
608
+ self._util.loading()
609
+ else:
610
+ btn_painel = self._util.find_element_with_wait(By.XPATH, "//a[@id='home']")
611
+ self.driver.execute_script("arguments[0].click();", btn_painel)
612
+
613
+ self._util.find_clickable_element_with_wait(By.XPATH, "//body", 30)
614
+ print("Já logado, continuando o código.")
615
+ if "Número do processo" in self.driver.page_source and "Quadro de avisos" not in self.driver.page_source:
616
+ self._util.find_element_with_wait(
617
+ By.XPATH,
618
+ '//td[contains(@id,"tabExpedientes_lbl")] or //td[contains(text(),"Expedientes")]',
619
+ ).click()
620
+ self._fechar_popup_certificado()
621
+
622
+ return True
623
+
624
+ elif "403 Forbidden" in self.driver.page_source:
625
+ raise WebDriverException("Erro 403 Forbidden ao acessar o PJe.")
626
+
627
+ xpath_framers = ["ssoFrame", "ifrmLogin", "framePeticionar"]
628
+ text_quebra = "Número do processo"
629
+ self._util.loading()
630
+ time.sleep(2)
631
+ self._util.framer_atached(
632
+ xpath_framers=xpath_framers,
633
+ text_quebra=text_quebra,
634
+ el=el_peticionar,
635
+ quebra=True,
636
+ )
637
+
638
+ xpath_cert = (
639
+ "//input["
640
+ "contains(@id, 'kc-pje-office') or "
641
+ "contains(@name, 'login-pje-office') or "
642
+ "contains(@value, 'CERTIFICADO DIGITAL') or "
643
+ "contains(@id, 'loginAplicacaoButton') or "
644
+ "contains(@name, 'loginAplicacaoButton') or "
645
+ "contains(@value, 'Certificado Digital')"
646
+ "]"
647
+ )
648
+
649
+ self._verificar_bad_request()
650
+
651
+ try:
652
+ click_certification = self._util.find_element_with_wait(By.XPATH, xpath_cert, timeout=30)
653
+ if click_certification:
654
+ if self._util.deve_usar_whom():
655
+ # Verifica se o login foi bem-sucedido
656
+ self._util.login_via_whom()
657
+ if self._verificar_ja_logado():
658
+ print(" ✓ Login via WHOM realizado com sucesso!")
659
+ return True
660
+ else:
661
+ print("⚠ Login via WHOM falhou. Não há fallback disponível para este estado.")
662
+ raise Exception("Falha no login via WHOM")
663
+ else:
664
+ click_certification.click()
665
+ print("CLICOU NO CERTIFICADO DIGITAL")
666
+
667
+ time.sleep(2)
668
+ self._util.loading()
669
+
670
+ self._verificar_bad_request()
671
+ if self._verificar_ja_logado():
672
+ return True
673
+
674
+ code = self._obter_codigo_2fa()
675
+ if code:
676
+ self._insert_codigo_2fa(code)
677
+ else:
678
+ self.login()
679
+
680
+ self._fechar_popup_certificado()
681
+ if "Redirecionamento em excesso por" in self.driver.page_source:
682
+ self.driver.refresh()
683
+ time.sleep(2)
684
+ pass
685
+
686
+ try:
687
+ input_certificado = self.driver.find_elements(By.XPATH, xpath_cert)
688
+ if input_certificado:
689
+ self.driver.refresh()
690
+ time.sleep(1)
691
+ click_certification = self._util.find_element_with_wait(By.XPATH, xpath_cert, timeout=30)
692
+ try:
693
+ self.driver.execute_script("arguments[0].click();", click_certification)
694
+ except Exception:
695
+ click_certification.click()
696
+ self._util.loading()
697
+ time.sleep(2)
698
+ except NoSuchElementException:
699
+ pass
700
+
701
+ except Exception as e:
702
+ print(f"Erro ao clicar no certificado digital ou já logado: {e}")
703
+ self._fechar_popup_certificado()
704
+ if "Número do processo" in self.driver.page_source and "Quadro de avisos" not in self.driver.page_source:
705
+ try:
706
+ self._util.find_element_with_wait(By.XPATH, f"{el_peticionar}").click()
707
+ self.driver.switch_to.default_content()
708
+ except BaseException:
709
+ self.driver.switch_to.default_content()
710
+ self._util.find_element_with_wait(By.XPATH, f"{el_peticionar}").click()
711
+ self._util.loading()
712
+ time.sleep(0.5)
713
+ else:
714
+ self._util.framer_atached(xpath_framers, text_quebra, el_peticionar)
715
+ self.driver.switch_to.default_content()
716
+
717
+ self.driver.switch_to.default_content()
718
+ time.sleep(2)
719
+
720
+ if "Redirecionamento em excesso por" in self.driver.page_source:
721
+ self.driver.refresh()
722
+ time.sleep(2)
723
+ pass
724
+
725
+ self._util.framer_atached(xpath_framers, text_quebra, el_peticionar)
726
+
727
+ if "Número do processo" in self.driver.page_source and "Quadro de avisos" not in self.driver.page_source:
728
+ try:
729
+ self._util.find_element_with_wait(By.XPATH, f"{el_peticionar}", 5).click()
730
+ self.driver.switch_to.default_content()
731
+ except BaseException:
732
+ self.driver.switch_to.default_content()
733
+ self._util.find_element_with_wait(By.XPATH, f"{el_peticionar}").click()
734
+ self._util.loading()
735
+ time.sleep(0.5)
736
+
737
+ self._fechar_popup_certificado()
738
+
739
+ if "Sua página expirou, por favor tente novamente." in self.driver.page_source:
740
+ self.driver.refresh()
741
+ time.sleep(1)
742
+ self.login()
743
+ self._util.loading()
744
+ return
745
+
746
+ if "Avisos" in self.driver.page_source or "Mensagens" in self.driver.page_source or "Painel do usuário" in self.driver.page_source:
747
+ try:
748
+ btn_painel = self._util.find_element_with_wait(By.XPATH, "//input[contains(@value, 'Painel do usuário')]")
749
+ self.driver.execute_script("arguments[0].click();", btn_painel)
750
+ except BaseException:
751
+ if self._util.verificar_home_seam_atual():
752
+ link_redirect = self._util.find_element_with_wait(By.XPATH, "//a[contains(@href,'painel')]")
753
+ link_redirect = link_redirect.get_attribute("href")
754
+ self.driver.get(link_redirect)
755
+ time.sleep(2)
756
+ self._util.loading()
757
+ else:
758
+ btn_painel = self._util.find_element_with_wait(By.XPATH, "//a[@id='home']")
759
+ self.driver.execute_script("arguments[0].click();", btn_painel)
760
+ self._util.find_clickable_element_with_wait(By.XPATH, "//body", 30)
761
+ print("Já logado, continuando o código.")
762
+
763
+ if "Sua página expirou, por favor tente novamente." in self.driver.page_source:
764
+ self.driver.refresh()
765
+ time.sleep(1)
766
+ self.login()
767
+ self._util.loading()
768
+ return
769
+
770
+ if "Número do processo" in self.driver.page_source and "Quadro de avisos" not in self.driver.page_source:
771
+ self._util.find_element_with_wait(
772
+ By.XPATH,
773
+ '//td[contains(@id,"tabExpedientes_lbl")] or //td[contains(text(),"Expedientes")]',
774
+ ).click()
775
+ self._fechar_popup_certificado()
776
+
777
+ if self._util.verificar_home_seam_atual():
778
+ link_redirect = self._util.find_element_with_wait(By.XPATH, "//a[contains(@href,'painel')]")
779
+ link_redirect = link_redirect.get_attribute("href")
780
+ self.driver.get(link_redirect)
781
+ time.sleep(2)
782
+ self._util.loading()
783
+ return
784
+ else:
785
+ return
786
+
787
+ def _verificar_ja_logado(self):
788
+ if "Avisos" in self.driver.page_source or "Mensagens" in self.driver.page_source or "Painel do usuário" in self.driver.page_source:
789
+ try:
790
+ btn_painel = self._util.find_element_with_wait(By.XPATH,
791
+ "//input[contains(@value, 'Painel do usuário')]")
792
+ self.driver.execute_script("arguments[0].click();", btn_painel)
793
+ except BaseException:
794
+ if self._util.verificar_home_seam_atual():
795
+ link_redirect = self._util.find_element_with_wait(By.XPATH, "//a[contains(@href,'painel')]")
796
+ link_redirect = link_redirect.get_attribute("href")
797
+ self.driver.get(link_redirect)
798
+ time.sleep(2)
799
+ self._util.loading()
800
+ else:
801
+ btn_painel = self._util.find_element_with_wait(By.XPATH, "//a[@id='home']")
802
+ self.driver.execute_script("arguments[0].click();", btn_painel)
803
+
804
+ self._util.find_clickable_element_with_wait(By.XPATH, "//body", 30)
805
+
806
+ if "Sua página expirou, por favor tente novamente." in self.driver.page_source:
807
+ self.driver.refresh()
808
+ time.sleep(1)
809
+ self.login()
810
+ self._util.loading()
811
+ return True
812
+
813
+ if "Número do processo" in self.driver.page_source and "Quadro de avisos" not in self.driver.page_source:
814
+ self._util.find_element_with_wait(
815
+ By.XPATH,
816
+ '//td[contains(@id,"tabExpedientes_lbl")] or //td[contains(text(),"Expedientes")]',
817
+ ).click()
818
+ self._fechar_popup_certificado()
819
+
820
+ if self._util.verificar_home_seam_atual():
821
+ link_redirect = self._util.find_element_with_wait(By.XPATH, "//a[contains(@href,'painel')]")
822
+ link_redirect = link_redirect.get_attribute("href")
823
+ self.driver.get(link_redirect)
824
+ time.sleep(2)
825
+ self._util.loading()
826
+ return True
827
+ else:
828
+ return True
829
+ else:
830
+ return False
831
+
832
+ def _fechar_popup_certificado(self):
833
+ if "Certificado próximo de expirar" in self.driver.page_source:
834
+ try:
835
+ bt_fechar = self._util.find_element_with_wait(
836
+ By.XPATH,
837
+ "//span[contains(@class,'btn-fechar') or contains(@onclick,'fechar')]",
838
+ )
839
+ bt_fechar.click()
840
+ self._util.loading()
841
+
842
+ except BaseException:
843
+ pass
844
+
845
+ def _verificar_bad_request(self):
846
+ if "Bad Request" in self.driver.page_source:
847
+ raise WebDriverException("Erro de Bad Request ao acessar o PJe.")
848
+
849
+ def _esta_na_tela_2fa(self):
850
+ """
851
+ Verifica se está na tela de inserção do código 2FA.
852
+ """
853
+ try:
854
+ self.driver.find_element(By.XPATH, "//*[self::input[@id='txtAcessoCodigo'] or self::input[@id='otp']]")
855
+ return True
856
+ except NoSuchElementException:
857
+ return False
858
+
859
+ def _obter_codigo_2fa(self):
860
+ """
861
+ Obtém o código 2FA via API (login_2factor).
862
+ Retorna o código ou None se falhar.
863
+ """
864
+ try:
865
+
866
+ code = self.processar_codes()
867
+ return code
868
+ except Exception as e:
869
+ print(f" ✗ Erro ao obter código 2FA: {e}")
870
+ return None
871
+
872
+ def _insert_codigo_2fa(self,code):
873
+ # Verifica se apareceu o formulário de autenticação 2FA
874
+ try:
875
+ if code:
876
+ input_otp = self._util.find_element_with_wait(By.XPATH,
877
+ "//form[@id='kc-otp-login-form'] | //input[@id='otp' and @name='otp']",
878
+ timeout=5)
879
+ if input_otp:
880
+ input_otp = self._util.find_element_with_wait(By.XPATH, "//input[contains(@type,'text')]")
881
+ time.sleep(2)
882
+
883
+ input_otp.clear()
884
+ input_otp.send_keys(str(code))
885
+
886
+ click_validar = self._util.find_element_with_wait(By.XPATH,
887
+ "//input[contains(@type,'submit')] | //button[contains(@type,'submit')]",
888
+ timeout=5)
889
+ click_validar.click()
890
+ self._util.loading()
891
+ if 'Código inválido'.lower() in self.driver.page_source.lower():
892
+ code = self._obter_codigo_2fa()
893
+ self._insert_codigo_2fa(code)
894
+ return
895
+ else:
896
+ self.login()
897
+ except (TimeoutException, NoSuchElementException):
898
+ # Formulário OTP não apareceu, continua normalmente
899
+ pass
900
+
901
+ class _Utils:
902
+ def __init__(self, driver, api, url_procurada, uf, sistema, advogado, token, tipo='mysena'):
903
+ self.driver = driver
904
+ self.tipo_login = tipo
905
+ self.sistema = sistema
906
+ self.advogado = advogado
907
+ self.token = token
908
+ self.url_procurada = url_procurada
909
+ self.uf = uf
910
+ self.api = api
911
+
912
+ def find_element_with_wait(self, by, value, timeout=10, parent=None):
913
+ if parent is None:
914
+ parent = self.driver # Usa o driver principal se nenhum elemento pai for passado
915
+ return WebDriverWait(parent, timeout).until(ec.presence_of_element_located((by, value)))
916
+
917
+ def find_elements_with_wait(self, by, value, timeout=10, parent=None):
918
+ if parent is None:
919
+ parent = self.driver # Usa o driver principal se nenhum elemento pai for passado
920
+ return WebDriverWait(parent, timeout).until(ec.presence_of_all_elements_located((by, value)))
921
+
922
+ def find_clickable_element_with_wait(self, by, value, timeout=10, parent=None):
923
+ if parent is None:
924
+ parent = self.driver # Usa o driver principal se nenhum elemento pai for passado
925
+ return WebDriverWait(parent, timeout).until(ec.element_to_be_clickable((by, value)))
926
+
927
+ def deve_usar_whom(self):
928
+ """
929
+ Determina se deve usar o login via WHOM baseado no estado (UF).
930
+ Estados que usam WHOM: RJ, TO
931
+ """
932
+ if self.tipo_login.lower() == "mysena" or "my" in self.tipo_login.lower():
933
+ return False
934
+ elif 'whoom' in self.tipo_login.lower() or self.tipo_login.lower() == 'whoom' or self.tipo_login.lower() == 'whom' or self.tipo_login.lower() == 'wh' or 'wh' in self.tipo_login.lower() :
935
+ return True
936
+ else:
937
+ return False
938
+
939
+ def login_via_whom(self):
940
+ """
941
+ Realiza login via WHOM (login_2fac do bcpkgfox).
942
+ Todo o processo de autenticação é feito pela função login_2fac.
943
+
944
+ Retorna True se login bem-sucedido, False caso contrário.
945
+ """
946
+ print(f"\n[LOGIN WHOM] Iniciando login via WHOM para {self.uf}...")
947
+ print(f" → Sistema: {self.sistema}")
948
+ print(f" → Certificado: {self.advogado}")
949
+
950
+ try:
951
+ login_2fac(
952
+ driver=self.driver,
953
+ certificate=f"{self.advogado}",
954
+ system=f"{self.sistema}",
955
+ token=f"{self.token}",
956
+ code_timeout=120,
957
+ )
958
+ time.sleep(3)
959
+ except Exception as e:
960
+ print(f" ✗ Erro durante login via WHOM: {e}")
961
+ return False
962
+
963
+ def framer_atached(self, xpath_framers, quebra=False, text_quebra="", el=""):
964
+ for framer in xpath_framers:
965
+ try:
966
+ self.driver.switch_to.frame(framer)
967
+ if quebra:
968
+ if framer == "framePeticionar":
969
+ if f"{text_quebra}" in self.driver.page_source:
970
+ try:
971
+ self.find_element_with_wait(By.XPATH, f"{el}").click()
972
+ except BaseException:
973
+ self.driver.switch_to.default_content()
974
+ self.find_element_with_wait(By.XPATH, f"{el}").click()
975
+ return
976
+ break
977
+ except NoSuchElementException:
978
+ continue
979
+ except BaseException:
980
+ continue
981
+
982
+ def loading(self):
983
+ timeout = 60 # Tempo máximo de espera em segundos
984
+ start_time = time.time()
985
+ while True:
986
+ if time.time() - start_time > timeout:
987
+ print("Aviso: A verificação de 'loading' excedeu o tempo limite.")
988
+ break
989
+ try:
990
+ styled = self.driver.find_element("xpath", '//*[@id="_viewRoot:status.start"]')
991
+ style_content = styled.get_attribute("style")
992
+ if "display: none;" in style_content:
993
+ break # Sai do loop se o carregamento terminou
994
+ else:
995
+ time.sleep(0.5) # Espera um pouco antes de verificar novamente
996
+ except NoSuchElementException:
997
+ break # Sai do loop se o elemento de loading não for encontrado
998
+
999
+ def verificar_home_seam_atual(self):
1000
+ """
1001
+ Verifica se 'home.seam' está presente na URL atual do navegador.
1002
+ """
1003
+ url_atual = self.driver.current_url
1004
+ if "home.seam" in url_atual:
1005
+ print(f"'home.seam' encontrado na URL atual: {url_atual}")
1006
+ return True
1007
+ else:
1008
+ print(f"'home.seam' NÃO encontrado na URL atual: {url_atual}")
1009
+ return False
1010
+
1011
+ def msg_aviso(self, mensagem, titulo="Aviso"):
1012
+ import tkinter as tk
1013
+ from tkinter import messagebox
1014
+
1015
+ root = tk.Tk()
1016
+ root.withdraw()
1017
+ root.attributes("-topmost", True)
1018
+ messagebox.showinfo(titulo, mensagem, parent=root)
1019
+ root.destroy()
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: bcpkgfox
3
- Version: 0.17.14
3
+ Version: 0.18.1
4
4
  Summary: Biblioteca BCFOX
5
5
  Home-page: https://github.com/robotsbcfox/PacotePythonBCFOX
6
6
  Author: BCFOX
@@ -4,10 +4,10 @@ bcpkgfox/cli.py,sha256=E1Yahd8jIjUwxM6EMHveDDne5-fh8QeAvAhyATNatEo,33541
4
4
  bcpkgfox/find_elements.py,sha256=oeB-73LqMLoKchozPXuxRkThBju9IgUKqbgU-2AAq0s,23027
5
5
  bcpkgfox/get_driver.py,sha256=ohimk9E2hL6T35IXv0XX0uvWDGCUZvZDlPMnuRjV1R0,30490
6
6
  bcpkgfox/invoke_api.py,sha256=MEwbdBW6PtnKRGTv6Mezw3Fx7NsHdDHsnKT-1CZIOQA,21832
7
- bcpkgfox/login_2factor.py,sha256=atRepywCo6jWn3gYUPIFjNgZY4E0GzRpiNFJkrkIN_c,3563
7
+ bcpkgfox/login_2factor.py,sha256=i01tZNmcl-YmNKODnXcjXTEioC9qPsxBtqeJ2KXvu60,45594
8
8
  bcpkgfox/system.py,sha256=3lyOWx893T6KiAI-jDv7zAo3oKPf0Q5CLgZ8TeFd0Do,7901
9
- bcpkgfox-0.17.14.dist-info/METADATA,sha256=ohpcy02w1OMu_STpA4SZi3hvGSEXjMtB-ChrETYh9i8,1894
10
- bcpkgfox-0.17.14.dist-info/WHEEL,sha256=qELbo2s1Yzl39ZmrAibXA2jjPLUYfnVhUNTlyF1rq0Y,92
11
- bcpkgfox-0.17.14.dist-info/entry_points.txt,sha256=qmaEg6K7Y0HOeaFo-G6lf44InGkeVI4I6hqobcY_nns,653
12
- bcpkgfox-0.17.14.dist-info/top_level.txt,sha256=h01SqyYBEfS72vkRFOlEDZBUSu9pzU0bdX4m9hWNNmw,9
13
- bcpkgfox-0.17.14.dist-info/RECORD,,
9
+ bcpkgfox-0.18.1.dist-info/METADATA,sha256=EE9AD1DKaTcIM3-h80p8T1zenSdeeRc1QfjCSSCd79k,1893
10
+ bcpkgfox-0.18.1.dist-info/WHEEL,sha256=qELbo2s1Yzl39ZmrAibXA2jjPLUYfnVhUNTlyF1rq0Y,92
11
+ bcpkgfox-0.18.1.dist-info/entry_points.txt,sha256=qmaEg6K7Y0HOeaFo-G6lf44InGkeVI4I6hqobcY_nns,653
12
+ bcpkgfox-0.18.1.dist-info/top_level.txt,sha256=h01SqyYBEfS72vkRFOlEDZBUSu9pzU0bdX4m9hWNNmw,9
13
+ bcpkgfox-0.18.1.dist-info/RECORD,,