aianyu commited on
Commit
78f3214
·
verified ·
1 Parent(s): 6ae375b

Upload 5 files

Browse files
Files changed (4) hide show
  1. Dockerfile +0 -0
  2. README.md +16 -42
  3. app.py +148 -128
  4. requirements.txt +2 -1
Dockerfile ADDED
File without changes
README.md CHANGED
@@ -1,55 +1,29 @@
1
  ---
2
- title: Bitcoin Wallet Recovery
3
  emoji: 🔑
4
  colorFrom: blue
5
  colorTo: green
6
- sdk: streamlit
7
- sdk_version: 1.26.0 # Or your streamlit version
8
- app_file: app.py
9
  pinned: false
10
- license: mit # Or apache-2.0 if you prefer, consistent with btcrecover
11
  ---
12
 
13
- # Bitcoin Wallet Password Recovery (via `btcrecover`)
14
 
15
- This Streamlit application provides a web interface to use `btcrecover` for attempting to recover passwords for Bitcoin `wallet.dat` files.
16
 
17
- **[Link to the running Space (You'll add this after deploying)]**
18
 
19
- ## ⚠️ Important Disclaimers
 
 
 
 
20
 
21
- * **SECURITY RISK**: Uploading your `wallet.dat` file to any online service, including this one, carries inherent security risks. This tool is intended for **educational and personal recovery purposes only**. Do NOT use it with wallets containing significant value unless you fully understand and accept the risks. The application processes files in temporary storage on the server.
22
- * **RESOURCE LIMITS**: This application runs on Hugging Face Spaces, which has resource (CPU, memory, time) limitations. Password recovery, especially with large password lists, can be very time-consuming and CPU-intensive. Long-running tasks may be terminated. For extensive recovery attempts, it's highly recommended to run `btcrecover` locally on your own machine.
23
- * **NO GUARANTEES**: The success of password recovery depends entirely on the quality and completeness of your password list and the complexity of the original password. This tool does not guarantee that your password will be found.
24
- * **FOR YOUR OWN WALLETS ONLY**: Only use this tool on `wallet.dat` files that you legally own and have forgotten the password to.
25
 
26
- ## How to Use
 
 
27
 
28
- 1. **Upload `wallet.dat`**: Use the sidebar to upload your encrypted `wallet.dat` file.
29
- 2. **Provide Passwords**:
30
- * **Upload a list**: Upload a `.txt` file containing potential passwords, one password per line.
31
- * **Enter manually**: Type or paste potential passwords directly into the text area, one per line.
32
- 3. **Options (Optional)**:
33
- * Check `Use '--no-strict-wallet-verify'` if you are dealing with a very old wallet or if `btcrecover` reports issues with wallet integrity.
34
- 4. **Start Recovery**: Click the "Start Recovery Process" button.
35
- 5. **Monitor Output**: The application will display the live log from `btcrecover`. This process can take a significant amount of time.
36
- 6. **Result**: If a password is found, it will be displayed. Otherwise, a "not found" message or error will be shown.
37
-
38
- ## Technical Details
39
-
40
- This application uses:
41
- * [Streamlit](https://streamlit.io/) for the web interface.
42
- * [btcrecover](https://github.com/gurnec/btcrecover) as the backend engine for password recovery.
43
-
44
- The uploaded files are stored temporarily on the server for processing by `btcrecover` and are deleted after the attempt.
45
-
46
- ## Local Development
47
-
48
- 1. Clone this repository.
49
- 2. Create a virtual environment: `python -m venv venv && source venv/bin/activate` (or `venv\Scripts\activate` on Windows).
50
- 3. Install dependencies: `pip install -r requirements.txt`.
51
- 4. Run the Streamlit app: `streamlit run app.py`.
52
-
53
- ## Acknowledgment
54
-
55
- This tool is a wrapper around the powerful `btcrecover` utility. Please consider supporting its original author.
 
1
  ---
2
+ title: BTCRecover Streamlit
3
  emoji: 🔑
4
  colorFrom: blue
5
  colorTo: green
6
+ sdk: docker
 
 
7
  pinned: false
8
+ app_port: 8501 # Should match EXPOSE and CMD in Dockerfile
9
  ---
10
 
11
+ # Bitcoin Wallet (`wallet.dat`) Password Recovery Tool
12
 
13
+ This Space provides a web interface for `btcrecover` to help recover lost passwords for Bitcoin `wallet.dat` files.
14
 
15
+ **How to Use:**
16
 
17
+ 1. Upload your `wallet.dat` file.
18
+ 2. Upload a text file containing potential passwords (one per line) OR paste them directly into the text area.
19
+ 3. Select any relevant options (e.g., `--no-strict-wallet-verify`).
20
+ 4. Click "🚀 Start Recovery Attempt".
21
+ 5. The output from `btcrecover` will be displayed in real-time.
22
 
23
+ **⚠️ Important Limitations on Hugging Face Spaces:**
 
 
 
24
 
25
+ * **Resource Intensive:** Password recovery is CPU-heavy. Free tier Spaces have limited resources.
26
+ * **Execution Timeouts:** Operations may be terminated if they run for too long (e.g., >30 minutes on free tier). This tool is **not suitable for large password lists or complex passwords** on this platform.
27
+ * **Security:** Your `wallet.dat` is uploaded to the server for processing. While this app doesn't store it permanently, be mindful of uploading sensitive data.
28
 
29
+ This tool is primarily for educational purposes or for attempting recovery with very small, targeted password lists on Hugging Face Spaces. For serious recovery attempts, running `btcrecover` locally on a more powerful machine is recommended.
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
app.py CHANGED
@@ -1,148 +1,168 @@
1
  import streamlit as st
2
  import subprocess
3
- import os
4
  import tempfile
5
- from wallet_utils import find_btcrecover_executable # Or paste the function directly here
 
6
 
7
  # --- Configuration ---
8
- DEFAULT_WALLET_FILENAME = "wallet.dat"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
9
 
10
- # --- Helper Functions ---
11
- # If not using wallet_utils.py, paste find_btcrecover_executable here.
 
 
 
 
 
 
 
12
 
13
- # --- Streamlit UI ---
14
- st.set_page_config(page_title="Bitcoin Wallet Recovery", layout="wide")
15
-
16
- st.title("🔑 Bitcoin Wallet Password Recovery Tool (via btcrecover)")
17
- st.markdown("""
18
- **Disclaimer:**
19
- - **Security Risk:** Uploading your `wallet.dat` file to any online service carries inherent security risks. Use with caution and only with wallets you are comfortable exposing in this manner. This tool is intended for educational and personal recovery purposes.
20
- - **Resource Limits:** This tool runs on a shared environment (Hugging Face Spaces). Long recovery processes with large password lists may be slow or terminated due to resource limits. For extensive searches, running `btcrecover` locally is recommended.
21
- - **No Guarantees:** Password recovery success depends entirely on the quality of your password list and the original password's complexity.
22
- """)
23
- st.markdown("---")
 
24
 
25
- # --- Inputs ---
26
- st.sidebar.header("Configuration")
27
- uploaded_wallet_file = st.sidebar.file_uploader("1. Upload your `wallet.dat` file", type=["dat"])
 
 
28
 
29
- password_source = st.sidebar.radio(
30
- "2. Provide Passwords:",
31
- ("Upload a password list (.txt)", "Enter passwords manually")
32
- )
33
 
34
- passwords = []
35
- uploaded_password_file = None
36
- manual_passwords_text = ""
 
 
37
 
38
- if password_source == "Upload a password list (.txt)":
39
- uploaded_password_file = st.sidebar.file_uploader("Upload your password list (one password per line)", type=["txt"])
 
 
 
 
 
 
 
 
40
  else:
41
- manual_passwords_text = st.sidebar.text_area("Enter passwords (one per line)", height=150)
42
-
43
- use_no_strict_verify = st.sidebar.checkbox(
44
- "Use '--no-strict-wallet-verify' (for old/potentially corrupt wallets)",
45
- value=False,
46
- help="Useful if btcrecover complains about wallet integrity or if it's a very old wallet."
47
- )
48
-
49
- # --- Execution ---
50
- output_placeholder = st.empty()
51
- result_placeholder = st.empty()
52
-
53
- if st.sidebar.button("🚀 Start Recovery Process", type="primary"):
54
- if not uploaded_wallet_file:
55
- st.error("🚨 Please upload a `wallet.dat` file.")
56
- st.stop()
57
-
58
- if uploaded_password_file:
59
- passwords = [line.decode('utf-8', errors='ignore').strip() for line in uploaded_password_file.readlines() if line.strip()]
60
- elif manual_passwords_text:
61
- passwords = [line.strip() for line in manual_passwords_text.split('\n') if line.strip()]
62
- else:
63
- st.error("🚨 Please provide passwords either by uploading a list or entering them manually.")
64
- st.stop()
65
 
66
- if not passwords:
67
- st.error("🚨 The password list is empty.")
68
- st.stop()
69
 
70
- btcrecover_exe = find_btcrecover_executable()
71
- if not btcrecover_exe:
72
- st.error("CRITICAL: `btcrecover` executable not found. Ensure it's installed in the environment.")
73
- st.stop()
74
 
75
- # Create temporary files for wallet and password list
76
- # These will be automatically deleted when closed or when the 'with' block exits.
77
- # btcrecover needs file paths, so we can't just pass bytes.
78
- # delete=False is important here because Popen needs to access the file after it's written.
79
- # We'll manually delete them in a finally block.
80
 
81
- tmp_wallet_file = None
82
- tmp_password_list_file = None
 
 
 
83
 
84
- try:
85
- with tempfile.NamedTemporaryFile(delete=False, suffix=".dat") as twf:
86
- twf.write(uploaded_wallet_file.getvalue())
87
- tmp_wallet_file_path = twf.name
88
-
89
- with tempfile.NamedTemporaryFile(delete=False, mode="w", encoding="utf-8", suffix=".txt") as tpf:
90
- for p in passwords:
91
- tpf.write(p + "\n")
92
- tmp_password_list_file_path = tpf.name
93
-
94
- command = [
95
- btcrecover_exe,
96
- "--walletfile", tmp_wallet_file_path,
97
- "--passwordlist", tmp_password_list_file_path
98
- ]
99
- if use_no_strict_verify:
100
- command.append("--no-strict-wallet-verify")
101
- # command.append("--no-eta") # Optional: for cleaner output if ETA is not desired
102
-
103
- st.info(f"ℹ️ Starting `btcrecover` with {len(passwords)} passwords...")
104
- st.markdown(f"**Command:** `{' '.join(command)}` (paths are temporary)")
105
- st.markdown("---")
106
- output_placeholder.markdown("### Recovery Log:")
107
- log_output_area = st.empty() # For streaming output
108
-
109
- full_log = ""
110
- found_password_str = None
111
-
112
- process = subprocess.Popen(command, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, text=True, universal_newlines=True)
113
 
114
- if process.stdout:
115
- with st.spinner("⏳ `btcrecover` is running... This may take a while."):
116
- for line in iter(process.stdout.readline, ''):
117
- full_log += line
118
- log_output_area.code(full_log, language=None) # Display live log
119
- if "Password found:" in line:
120
- found_password_str = line.split("Password found:", 1)[1].strip()
121
- # Don't break, let btcrecover finish its output if any
122
- if process.poll() is not None: # Process finished
123
- break
124
- process.stdout.close()
125
- return_code = process.wait()
126
- log_output_area.code(full_log, language=None) # Display final log
127
-
128
- st.markdown("---")
129
- if found_password_str:
130
- result_placeholder.success(f"🎉 **PASSWORD FOUND:** `{found_password_str}`")
131
- elif return_code == 0: # btcrecover might exit 0 even if not found
132
- result_placeholder.warning("⚠️ Password not found in the provided list (btcrecover completed).")
133
- else:
134
- result_placeholder.error(f"🚫 `btcrecover` exited with an error (code: {return_code}). Password likely not found or an issue occurred.")
135
- st.info("Check the log above for details. Common issues: wallet format, corrupted wallet (try --no-strict-wallet-verify).")
136
-
137
- except Exception as e:
138
- st.error(f"An unexpected error occurred: {e}")
139
- finally:
140
- # Clean up temporary files
141
- if tmp_wallet_file_path and os.path.exists(tmp_wallet_file_path):
142
- os.remove(tmp_wallet_file_path)
143
- if tmp_password_list_file_path and os.path.exists(tmp_password_list_file_path):
144
- os.remove(tmp_password_list_file_path)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
145
 
146
  st.markdown("---")
147
- st.markdown("Crafted for educational and recovery purposes. Use responsibly.")
148
- st.markdown("Consider supporting the original `btcrecover` tool: [btcrecover on GitHub](https://github.com/gurnec/btcrecover)")
 
1
  import streamlit as st
2
  import subprocess
 
3
  import tempfile
4
+ import os
5
+ import shutil
6
 
7
  # --- Configuration ---
8
+ APP_TITLE = "Bitcoin Wallet.dat Password Recovery (btcrecover)"
9
+ APP_INTRO = """
10
+ Upload your `wallet.dat` file and a password list to attempt recovery.
11
+ This tool uses `btcrecover` in the backend.
12
+ """
13
+ WARNING_TEXT = """
14
+ **⚠️ Important Considerations for Hugging Face Spaces:**
15
+ - **Resource Limits:** Hugging Face Spaces (especially free tier) have CPU, memory, and execution time limits.
16
+ - **Execution Time:** Password recovery can be very time-consuming. Long-running jobs might be terminated. This tool is best for very small password lists or educational purposes on this platform.
17
+ - **Security:** Your `wallet.dat` file is uploaded to the server for processing. While not stored permanently by this app, please be aware of this.
18
+ - **Patience:** The process can be slow. Output will stream below.
19
+ """
20
+
21
+ def find_btcrecover_executable():
22
+ """Tries to find the btcrecover executable."""
23
+ executable = shutil.which("btcrecover")
24
+ if executable:
25
+ return executable
26
+ # Fallback for some environments, though `shutil.which` should work in Docker with PATH set
27
+ possible_paths = [
28
+ "/usr/local/bin/btcrecover",
29
+ os.path.expanduser("~/.local/bin/btcrecover")
30
+ ]
31
+ for path in possible_paths:
32
+ if os.path.exists(path) and os.access(path, os.X_OK):
33
+ return path
34
+ return None
35
+
36
+ def run_btcrecover(wallet_path, password_list_path, btcrecover_exe, extra_args=None):
37
+ """Runs btcrecover and streams its output."""
38
+ command = [
39
+ btcrecover_exe,
40
+ "--walletfile", wallet_path,
41
+ "--passwordlist", password_list_path,
42
+ ]
43
+ if extra_args:
44
+ command.extend(extra_args)
45
+
46
+ st.info(f"Executing: {' '.join(command)}")
47
+
48
+ # Placeholder for real-time output
49
+ output_placeholder = st.empty()
50
+ log_output = ""
51
 
52
+ try:
53
+ process = subprocess.Popen(
54
+ command,
55
+ stdout=subprocess.PIPE,
56
+ stderr=subprocess.STDOUT, # Combine stdout and stderr
57
+ text=True,
58
+ bufsize=1, # Line buffered
59
+ universal_newlines=True
60
+ )
61
 
62
+ if process.stdout:
63
+ for line in iter(process.stdout.readline, ''):
64
+ log_output += line
65
+ output_placeholder.code(log_output, language="text") # Update placeholder with cumulative log
66
+ if "Password found:" in line:
67
+ st.balloons()
68
+ st.success(f"🎉 Password potentially found! Check logs above. Line: {line.strip()}")
69
+ elif "Password not found" in line and "exhaustive" in line:
70
+ st.warning("Password not found in the list after exhaustive search by btcrecover.")
71
+ process.stdout.close()
72
+
73
+ return_code = process.wait()
74
 
75
+ if return_code != 0 and "Password found:" not in log_output:
76
+ st.error(f"btcrecover exited with error code {return_code}. Check the logs.")
77
+ elif "Password found:" not in log_output and ("Password not found" not in log_output or "exhaustive" not in log_output) :
78
+ # If no "Password found" and no clear "not found" message from btcrecover, it might be an unknown state or early exit
79
+ st.info("btcrecover finished. Please review the logs above to determine the outcome.")
80
 
 
 
 
 
81
 
82
+ except FileNotFoundError:
83
+ st.error(f"Error: btcrecover executable not found at '{btcrecover_exe}'. Ensure it's installed and in PATH.")
84
+ except Exception as e:
85
+ st.error(f"An unexpected error occurred: {str(e)}")
86
+ st.code(log_output, language="text") # Show any logs gathered so far
87
 
88
+ # --- Streamlit UI ---
89
+ st.set_page_config(page_title=APP_TITLE, layout="wide")
90
+ st.title(APP_TITLE)
91
+ st.markdown(APP_INTRO)
92
+ st.warning(WARNING_TEXT)
93
+
94
+ btcrecover_exe = find_btcrecover_executable()
95
+ if not btcrecover_exe:
96
+ st.error("`btcrecover` executable not found in the environment. The application cannot proceed.")
97
+ st.stop()
98
  else:
99
+ st.sidebar.success(f"btcrecover found: {btcrecover_exe}")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
100
 
 
 
 
101
 
102
+ # File Uploaders
103
+ st.sidebar.header("1. Upload Files")
104
+ uploaded_wallet_file = st.sidebar.file_uploader("Upload wallet.dat", type=['dat', 'wallet'])
105
+ uploaded_password_list = st.sidebar.file_uploader("Upload password list (text file, one password per line)", type=['txt', 'list'])
106
 
107
+ # Or provide passwords directly in a textarea
108
+ st.sidebar.markdown("--- OR ---")
109
+ passwords_text_area = st.sidebar.text_area("Paste passwords (one per line)", height=150,
110
+ help="If you provide passwords here, the uploaded password list will be ignored.")
 
111
 
112
+ st.sidebar.header("2. Options")
113
+ no_strict_verify = st.sidebar.checkbox("Disable strict wallet verification (`--no-strict-wallet-verify`)",
114
+ help="Useful for very old or slightly non-standard wallet.dat files.")
115
+ # processes_auto = st.sidebar.checkbox("Use multiple processes if available (`--processes auto`)",
116
+ # help="Might be limited by Hugging Face Spaces resources.")
117
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
118
 
119
+ if st.sidebar.button("🚀 Start Recovery Attempt"):
120
+ if not uploaded_wallet_file:
121
+ st.error("Please upload a wallet.dat file.")
122
+ elif not uploaded_password_list and not passwords_text_area.strip():
123
+ st.error("Please upload a password list file OR paste passwords into the text area.")
124
+ else:
125
+ with tempfile.NamedTemporaryFile(delete=False, suffix=".dat") as tmp_wallet, \
126
+ tempfile.NamedTemporaryFile(mode="w+", delete=False, suffix=".txt") as tmp_passlist:
127
+
128
+ # Save uploaded wallet to a temporary file
129
+ tmp_wallet.write(uploaded_wallet_file.getvalue())
130
+ tmp_wallet_path = tmp_wallet.name
131
+
132
+ # Prepare password list
133
+ if passwords_text_area.strip():
134
+ tmp_passlist.write(passwords_text_area.strip())
135
+ else:
136
+ tmp_passlist.write(uploaded_password_list.getvalue().decode())
137
+ tmp_passlist_path = tmp_passlist.name
138
+
139
+ # Ensure files are closed before btcrecover tries to access them
140
+ tmp_wallet.close()
141
+ tmp_passlist.close()
142
+
143
+ st.info(f"Wallet file saved to: {tmp_wallet_path}")
144
+ st.info(f"Password list saved to: {tmp_passlist_path}")
145
+
146
+ extra_args = []
147
+ if no_strict_verify:
148
+ extra_args.append("--no-strict-wallet-verify")
149
+ # if processes_auto: # Be cautious with this on shared resources
150
+ # extra_args.append("--processes")
151
+ # extra_args.append("auto")
152
+
153
+ with st.spinner("Attempting password recovery... Please wait. This can take a very long time."):
154
+ run_btcrecover(tmp_wallet_path, tmp_passlist_path, btcrecover_exe, extra_args)
155
+
156
+ # Clean up temporary files
157
+ try:
158
+ os.unlink(tmp_wallet_path)
159
+ os.unlink(tmp_passlist_path)
160
+ st.caption(f"Cleaned up temporary files: {os.path.basename(tmp_wallet_path)}, {os.path.basename(tmp_passlist_path)}")
161
+ except Exception as e:
162
+ st.warning(f"Could not clean up temporary files: {e}")
163
+ else:
164
+ st.info("Upload your files and click 'Start Recovery Attempt' in the sidebar.")
165
 
166
  st.markdown("---")
167
+ st.markdown("Powered by [btcrecover](https://github.com/gurnec/btcrecover) and [Streamlit](https://streamlit.io/).")
168
+ st.markdown("Remember the limitations when running on free cloud platforms.")
requirements.txt CHANGED
@@ -1,2 +1,3 @@
1
  streamlit
2
- btcrecover
 
 
1
  streamlit
2
+ btcrecover
3
+ # requests # btcrecover might pull this or similar, good to list explicitly if known