NOJSCAP/server/python-flask/server.py
2025-08-06 16:58:36 +00:00

136 lines
3.8 KiB
Python

from flask import Flask, request
import hashlib, os, time
app = Flask(__name__)
DIFFICULTY = 20
challenge_store = {}
def generate_challenge():
return os.urandom(12).hex()
def check_difficulty(hash_bytes, bits):
i = 0
while bits > 0:
byte = hash_bytes[i]
if bits >= 8:
if byte != 0: return False
bits -= 8
else:
if byte & (0xFF << (8 - bits)) != 0: return False
bits = 0
i += 1
return True
@app.route('/', methods=['GET'])
def index():
challenge = generate_challenge()
challenge_store[challenge] = time.time()
return f'''
<!doctype html>
<html lang="en">
<head>
<title>NOJSCAP demo</title>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<style>
body {{
padding: 20px;
margin-bottom: 300px;
background: #cacaca;
color: black;
}}
code {{
white-space: break-spaces;
background: black;
color: white;
padding: 10px;
display: block;
max-width: 500px;
}}
.h {{
font-size: 21px;
font-weight: bolder;
width: 100%;
float: left;
}}
button {{
background: #006ed0;
color: white;
border: 1px solid #006ed0;
padding: 10px 20px;
margin-top: 10px;
}}
input {{
background: black;
color: white;
padding: 10px;
display: block;
max-width: 500px;
width: 100%;
border: 0px solid transparent;
font-family: monospace;
font-size: 12px;
}}
</style>
</head>
<body>
<h1>NOJSCAP demo</h1>
<p><a href="https://git.libroot.org/libroot/NOJSCAP/" target="_blank">https://git.libroot.org/libroot/NOJSCAP/</a></p><p><br></p>
<p>If you don't already have the <b><em>NOJSCAP</em></b> client:</p>
<code>$ git clone https://git.libroot.org/libroot/NOJSCAP/
$ cd NOJSCAP/client/</code>
<p><br></p>
<p>
<code>$ python3 pow_client.py {challenge} {DIFFICULTY}</code>
</p>
<p>
<strong>Go:</strong>
</p>
<p>
<code>$ go run pow_client.go {challenge} {DIFFICULTY}</code>
</p>
<p>
<strong>Node.js:</strong>
</p>
<p>
<code>$ node pow_client.js {challenge} {DIFFICULTY}</code>
</p>
<p>
<strong>Rust:</strong>
</p>
<p>
<code>$ rustc pow_client.rs -o pow_client_rs
$ pow_client_rs {challenge} {DIFFICULTY}
</code>
<small>Requires Rust and sha2 crate if using the Cargo version.</small>
</p>
<p>
<strong>C:</strong>
</p>
<p>
<code>$ gcc -O2 -o pow_client pow_client.c -lssl -lcrypto
$ ./pow_client {challenge} {DIFFICULTY}
</code>
<small>Required: GCC or any C compiler. OpenSSL development libraries (libssl-dev on Debian-based systems)</small>
</p>
<form method="POST">
<input type="hidden" name="challenge" value="{challenge}">
<label class="h">Nonce: <input name="nonce"></label>
<button type="submit">Submit</button>
</form>
</body>
</html>
'''
@app.route('/', methods=['POST'])
def submit():
challenge = request.form.get("challenge")
nonce = request.form.get("nonce")
if challenge not in challenge_store: return "Invalid challenge"
challenge_store.pop(challenge)
combined = (challenge + nonce).encode()
h = hashlib.sha256(combined).digest()
return "<p>Success! Valid nonce.</p><a href='/'>Try again</a>" if check_difficulty(h, DIFFICULTY) else "<p>Invalid nonce.</p><a href='/'>Try again</a>"
app.run(port=3000)