Monitoring for handshake TLS in chrome/selenium headless mode.

I have a script that access a URL that ask for certificate, when i'm using kaspersky anti virus it prompt me for a certificate selection, but when i turn off kaspersky, then no prompt appear.


I'm trying to do what kaspersky is doing, i want to choose the certificate and use chrome on headless mode.

This is my script

def acessar_portal_nfce_auto(pasta_download, log_callback, progress_callback, status_callback, status_chave_callback):
    global processed_count, chrome_initial_chrome_pids, chrome_initial_chromedriver_pids

    initial_chrome_pids, initial_chromedriver_pids = get_chrome_processes()
    chrome_initial_chrome_pids = set(initial_chrome_pids)
    chrome_initial_chromedriver_pids = set(initial_chromedriver_pids)

    chrome_options = Options()
    prefs = {
        "download.prompt_for_download": False,
        "download.directory_upgrade": True,
        "safebrowsing.enabled": True,
        "download.default_directory": pasta_download,
        "plugins.always_open_pdf_externally": True
    }
    chrome_options.add_experimental_option("prefs", prefs)
    chrome_options.add_argument("--no-sandbox")
    chrome_options.add_argument("--disable-dev-shm-usage")

    if modo_oculto.get():
        chrome_options.add_argument("--headless")
        log_callback("🔍 Modo oculto ativado - Chrome será executado em segundo plano")
    else:
        log_callback("🖥️ Modo visível - Chrome será exibido durante a execução")

    service = Service(ChromeDriverManager().install())
    driver = webdriver.Chrome(service=service, options=chrome_options)

    # Ativa o botão Cancelar APENAS após o driver ser criado
    root.after(0, lambda: btn_cancelar.config(state="normal"))

    try:
        log_callback("\n🔗 Acessando portal NFCE...")
        status_callback("Acessando portal...")
        driver.get("https://dfe-portal.svrs.rs.gov.br/NfceSSL/DownloadXmlDfe")

        processed_count = 0
        total_chaves = chave_queue.qsize()

        while not chave_queue.empty():
            if cancel_event.is_set():
                status_callback("Cancelando Processo")
                log_callback("❌ Processo cancelado pelo usuário")
                log_em_arquivo(pasta_download, "Cancelado pelo usuário")
                break

            try:
                chave_acesso = chave_queue.get(timeout=1)
            except queue.Empty:
                time.sleep(1)
                continue

            # VERIFICA SE ESTA CHAVE JÁ FOI CONCLUÍDA (DOUBLE-CHECK)
            if chave_acesso in chaves_processadas:
                processed_count += 1
                progress_callback(processed_count, chave_queue.qsize())
                log_callback(f"⏭️ Chave já concluída anteriormente, pulando: {chave_acesso}")
                continue

            processed_count += 1
            sucesso = False
            tentativa = 1

            while not sucesso and tentativa <= max_tentativas:
                if cancel_event.is_set():
                    break

                try:
                    tempo_apos_consulta = int(entry_apos_consulta.get())
                except:
                    tempo_apos_consulta = 5
                try:
                    tempo_download = int(entry_download.get())
                except:
                    tempo_download = 8
                try:
                    tempo_espera = int(entry_espera.get())
                except:
                    tempo_espera = 30
                try:
                    timeout_download = int(entry_timeout_download.get())
                except:
                    timeout_download = 12

                if cancel_event.is_set():
                    break

                try:
                    status_callback(f"Chave {processed_count}: Tentativa {tentativa} - Aguardando comando...")
                    while pause_event.is_set():
                        status_callback("⏸️ Pausado")
                        time.sleep(1)
                        if cancel_event.is_set():
                            break

                    status_chave_callback(chave_acesso, "Consultando...", "#ffff66")
                    status_callback(f"Chave {processed_count}: Tentativa {tentativa} - Consultando...")
                    log_callback(f"\n➡️ ({processed_count}) Tentativa {tentativa} - Consultando chave: {chave_acesso}")
                    progress_callback(processed_count, chave_queue.qsize())

                    if cancel_event.is_set():
                        break

                    wait = WebDriverWait(driver, tempo_apos_consulta + 15)
                    campo_chave = wait.until(EC.presence_of_element_located((By.ID, "ChaveAcessoDfe")))
                    botao_consultar = wait.until(
                        EC.element_to_be_clickable(
                            (By.XPATH, "//button[@type='submit' and contains(@class, 'btn-primary')]")
                        )
                    )

                    campo_chave.clear()
                    campo_chave.send_keys(chave_acesso)
                    botao_consultar.click()
                    status_callback("Consultando...")
                    time.sleep(tempo_apos_consulta)

                    if cancel_event.is_set():
                        break

                    botao_download = WebDriverWait(driver, timeout_download).until(
                        EC.element_to_be_clickable((By.ID, "btnExportar"))
                    )
                    botao_download.click()
                    status_callback("Download iniciado")
                    log_callback("⏳ Download do XML iniciado...")
                    log_em_arquivo(pasta_download, f"Download iniciado para chave {chave_acesso}")
                    status_chave_callback(chave_acesso, "Baixando...", "#ffa500")

                    for _ in range(tempo_download):
                        time.sleep(1)
                        while pause_event.is_set():
                            status_callback("⏸️ Pausado durante download")
                            time.sleep(1)
                        if cancel_event.is_set():
                            break

                    log_callback(f"✅ Download da chave {chave_acesso} concluído!")
                    status_callback("Download concluído")
                    log_em_arquivo(pasta_download, f"Download concluído para chave {chave_acesso}")

                    log_callback("🔄 Renomeando arquivo baixado...")
                    renomear_arquivos_xml(pasta_download, log_callback)

                    sucesso = True
                    chaves_processadas.add(chave_acesso)  # MARCA COMO PROCESSADA
                    status_chave_callback(chave_acesso, "Concluído", "#32cd32")

                except Exception as e:
                    if cancel_event.is_set() and (
                            "Failed to establish a new connection" in str(e)
                            or "chrome not reachable" in str(e).lower()
                            or "Max retries exceeded" in str(e)
                            or "disconnected" in str(e).lower()
                    ):
                        log_callback("⚠️ Cancelamento detectado durante operação Selenium.")
                        break

                    log_callback(f"⚠️ Falha na tentativa {tentativa} para a chave {chave_acesso}: {e}")
                    status_callback("Repetindo tentativa")
                    log_em_arquivo(pasta_download, f"Falha tentativa {tentativa} para chave {chave_acesso}: {e}")
                    tentativa += 1

                    if tentativa > max_tentativas:
                        log_callback("❌ Tentativas excedidas! Pulando para próxima chave.")
                        status_callback("Falha - pulando chave")
                        log_em_arquivo(pasta_download, f"Chave {chave_acesso} pulada após {max_tentativas} tentativas")
                        status_chave_callback(chave_acesso, "Falhou", "#ff4d4d")
                        break

                    for t in range(tempo_espera, 0, -1):
                        if cancel_event.is_set(): break
                        while pause_event.is_set():
                            status_callback("⏸️ Pausado durante espera")
                            time.sleep(1)
                        progress_callback(processed_count, chave_queue.qsize())
                        time.sleep(1)

                    if cancel_event.is_set():
                        break

                    try:
                        driver.get("https://dfe-portal.svrs.rs.gov.br/NfceSSL/DownloadXmlDfe")
                    except Exception:
                        break

        progress_callback(processed_count, chave_queue.qsize())
        if not cancel_event.is_set():
            status_callback("Todos os downloads concluídos!")
            log_callback("\n🎉 Todas as consultas foram processadas com sucesso!")
            log_em_arquivo(pasta_download, "Todas as consultas concluídas com sucesso")

    except Exception as e:
        if cancel_event.is_set() and (
                "Failed to establish a new connection" in str(e)
                or "chrome not reachable" in str(e).lower()
                or "Max retries exceeded" in str(e)
                or "disconnected" in str(e).lower()
        ):
            log_callback("⚠️ Chrome foi encerrado antes do término (cancelamento detectado).")
        else:
            log_callback(f"💥 Erro fatal: {e}")
            status_callback("Erro fatal")
            log_em_arquivo(pasta_download, f"Erro fatal: {e}")
    finally:
        try:
            driver.quit()
        except Exception:
            pass

        if cancel_event.is_set():
            killed = kill_chrome_processes(initial_chrome_pids, initial_chromedriver_pids)
            if killed > 0:
                log_callback(f"🔴 {killed} processos do Chrome encerrados forçadamente")

0

Please sign in to leave a comment.