diff --git a/README.md b/README.md index 621159d..35c31f5 100644 --- a/README.md +++ b/README.md @@ -5,8 +5,9 @@ and bitcoin-cli RPC usage, without requiring students to sync the node themselve ## Install -1. clone repo -2. `pip install -r requirements.txt` +1. Clone repo +2. Create and activate a Python Virtual Environment +3. `pip install -r requirements.txt` ## Run @@ -17,10 +18,11 @@ with bitcoin-cli. Networks supported: `main`, `testnet`, `signet`, `regtest` -- Start Bitcoin Core: `bitcoind -conf=/path/to/repo/rpc-auth-proxy/etc/bitcoin.conf` +- Start Bitcoin Core: `bitcoind -daemon -conf=/path/to/repo/rpc-auth-proxy/etc/bitcoin.conf` - Optionally add `-signet`, etc for different network - Start proxy server: `python src/server.py main` - Optionally replace `main` with `signet`, etc. + - Use `nohup` or `tmux` to ensure that the server process is not killed when exiting the terminal or session. ## Adding Users @@ -34,6 +36,15 @@ Password for newuser1: lYDk7mbTiN60 ~/rpc-auth-proxy$ python src/users.py newuser2 -p hunter2 Password for newuser2: hunter2 ``` +### Large amount of Users ### +To add large amount of users a utility is provided in `src/bulk_users.py`. Hashed passwords are saved by +default in a JSON file at `~/.rpc-auth-proxy-passwords.json`, but another file is saved too with the pair of username and clear password. + +```sh +~/rpc-auth-proxy$ python src/bulk_users.py 100 +100 users and passwords have been generated and saved to users_pass.csv. +100 users and passwords have been added to ~/.rpc-auth-proxy-passwords.json. +``` ## Remote Access diff --git a/src/bulk_users.py b/src/bulk_users.py new file mode 100644 index 0000000..338bafd --- /dev/null +++ b/src/bulk_users.py @@ -0,0 +1,64 @@ +import argparse +import csv +import json +import os +import random +import string + +from werkzeug.security import generate_password_hash + +from config import password_file_path + +# Parse command line arguments for username and optional password +parser = argparse.ArgumentParser(description="Add user and hashed password to JSON file.") +parser.add_argument("user_count", type=int, help="Number of users to generate") +parser.add_argument("-l", "--password_length", type=int, default=12, help="Length of the generated password") +args = parser.parse_args() + +# Generate and save user credentials to a CSV file +with open("users_pass.csv", "w", newline='') as user_pass_file: + csv_writer = csv.writer(user_pass_file) + csv_writer.writerow(['Username', 'Password']) + + users = {} + for i in range(args.user_count): + # Generate username + username = f"user_{i+1:03d}" + + # Generate password + characters = string.ascii_letters + string.digits + password = ''.join(random.choice(characters) for _ in range(args.password_length)) + + # Write user and password to the CSV file + csv_writer.writerow([username, password]) + + # Add user and hashed password to dictionary + hashed_password = generate_password_hash(password) + users[username] = hashed_password + +# Output message +print(f"{args.user_count} users and passwords have been generated and saved to users_pass.csv.") + +# File to store hashed passwords +PASSWORD_FILE_PATH = password_file_path() + +# Load existing data from file +if os.path.exists(PASSWORD_FILE_PATH): + with open(PASSWORD_FILE_PATH, 'r') as file: + try: + existing_users = json.load(file) + except json.JSONDecodeError: + existing_users = {} +else: + existing_users = {} + +# Add or update user passwords +existing_users.update(users) + +# Write back to the file +with open(PASSWORD_FILE_PATH, 'w') as file: + json.dump(existing_users, file, indent=4) + +# Output message +print(f"{args.user_count} users and passwords have been added to {PASSWORD_FILE_PATH}.") +