#!/usr/bin/python3

# inspired by https://github.com/cyberblackhole/7zip-crack

import subprocess
import sys

chars="abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890 ~`!@#$%^&*()-_=+[{]}\\|;:'\"/?.>,<"

target_zip = sys.argv[1]

def popen_check_password(zip_file: str, password: str) -> bool:
  return subprocess.Popen(["7z", "t", "-p%s" % password, zip_file], stdout=subprocess.DEVNULL, stderr=subprocess.STDOUT)

interval_print_password = 100
count_to_print_password = 0

number_multi_process = 10

def search_brute_force(prefix: str, min_len=1: int, max_len=None: int):
  len_pass = len(prefix) + 1
  index_char = 0
  process_and_passwords = []
  found_password = None
  for c in chars:
    if len(process_and_passwords) >= number_multi_process:
      process_and_pass = process_and_passwords.pop(0)
      if process_and_pass["process"].wait() == 0:
        found_password = process_and_pass["password"]
        break
    password = prefix + c
    global count_to_print_password
    count_to_print_password = count_to_print_password + 1
    if len_pass >= min_len:
      if count_to_print_password % interval_print_password == 0:
        print("\r%s" % password, end="")
      process_and_passwords.append({"process": popen_check_password(target_zip, password), "password": password})
      # if check_password(target_zip, password):
      #   return password
  for process_and_pass in process_and_passwords:
    if found_password is not None:
      process_and_pass['process'].wait()
    elif process_and_pass["process"].wait() == 0:
      found_password = process_and_pass["password"]
  if found_password is not None:
    return found_password
  if max_len is None or len_pass < max_len:
    for c in chars:
      found_password = search_brute_force(prefix + c, min_len, max_len)
      if found_password is not None:
        return found_password

result_password=search_brute_force("")
print("")
print("password: %s" % result_password)