142 lines
4.8 KiB
Python
142 lines
4.8 KiB
Python
#!/usr/bin/env python3
|
|
"""
|
|
http_test.py — test the HTTP listener mode with curl-like requests.
|
|
|
|
Starts nsigner in HTTP mode, sends requests via urllib, and verifies
|
|
the responses.
|
|
"""
|
|
import json
|
|
import os
|
|
import subprocess
|
|
import sys
|
|
import time
|
|
import urllib.request
|
|
|
|
NSIGNER = "./build/nsigner"
|
|
PAD_DIR = "/media/user/Music/pads"
|
|
PAD_SPEC = "333e9902db839d9d"
|
|
MNEMONIC_FILE = ".test_mnemonic"
|
|
MNEMONIC_TMP = ".test_mnemonic_http.tmp"
|
|
PORT = 11111
|
|
|
|
|
|
def main():
|
|
# Reset pad offset
|
|
state_path = f"{PAD_DIR}/333e9902db839d9d7f1f6aaa30f392a77c9abd011dd6274d9d3cf167361a789e.state"
|
|
with open(state_path, "w") as f:
|
|
f.write("offset=32\n")
|
|
|
|
# Prepare mnemonic temp file
|
|
with open(MNEMONIC_FILE) as f:
|
|
mnemonic = f.read().strip()
|
|
with open(MNEMONIC_TMP, "w") as f:
|
|
f.write(mnemonic + "\n")
|
|
|
|
# Start nsigner in HTTP mode
|
|
shell_cmd = (
|
|
f"exec 3<{MNEMONIC_TMP} 2>/dev/null; "
|
|
f"exec {NSIGNER} --listen http:127.0.0.1:{PORT} --mnemonic-fd 3 "
|
|
f"--otp-pad-dir {PAD_DIR} --otp-pad {PAD_SPEC} "
|
|
f"--otp-allow-blkback --allow-all"
|
|
)
|
|
proc = subprocess.Popen(
|
|
["bash", "-c", shell_cmd],
|
|
stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE,
|
|
)
|
|
time.sleep(2.0) # let the signer start
|
|
|
|
if proc.poll() is not None:
|
|
err = proc.stderr.read().decode()
|
|
print(f"ERROR: nsigner exited early (code {proc.returncode})")
|
|
print(f"stderr: {err}")
|
|
try:
|
|
os.unlink(MNEMONIC_TMP)
|
|
except OSError:
|
|
pass
|
|
return 1
|
|
|
|
try:
|
|
url = f"http://127.0.0.1:{PORT}/"
|
|
|
|
# Test 1: get_public_key
|
|
print("=== Test 1: get_public_key via HTTP ===")
|
|
req_data = json.dumps({
|
|
"id": "1",
|
|
"method": "get_public_key",
|
|
"params": [{"role": "main"}],
|
|
}).encode()
|
|
req = urllib.request.Request(url, data=req_data,
|
|
headers={"Content-Type": "application/json"})
|
|
with urllib.request.urlopen(req, timeout=5) as resp:
|
|
result = json.loads(resp.read().decode())
|
|
print(f"Response: {json.dumps(result)[:120]}...")
|
|
if "result" not in result:
|
|
print("ERROR: no result in get_public_key response")
|
|
return 1
|
|
pubkey = result["result"].strip('"')
|
|
print(f"Public key: {pubkey}")
|
|
|
|
# Test 2: otp_encrypt
|
|
print("\n=== Test 2: otp_encrypt via HTTP ===")
|
|
import base64
|
|
pt_b64 = base64.b64encode(b"Hello, OTP via HTTP!").decode()
|
|
req_data = json.dumps({
|
|
"id": "2",
|
|
"method": "otp_encrypt",
|
|
"params": [pt_b64, {"encoding": "ascii"}],
|
|
}).encode()
|
|
req = urllib.request.Request(url, data=req_data,
|
|
headers={"Content-Type": "application/json"})
|
|
with urllib.request.urlopen(req, timeout=5) as resp:
|
|
result = json.loads(resp.read().decode())
|
|
print(f"Response: {json.dumps(result)[:200]}...")
|
|
if "result" not in result:
|
|
print("ERROR: no result in otp_encrypt response")
|
|
return 1
|
|
enc_result = json.loads(result["result"])
|
|
ciphertext = enc_result["ciphertext"]
|
|
print(f"Pad offset: {enc_result['pad_offset_before']} -> {enc_result['pad_offset_after']}")
|
|
print(f"Ciphertext (first 60 chars): {ciphertext[:60]}...")
|
|
|
|
# Test 3: otp_decrypt
|
|
print("\n=== Test 3: otp_decrypt via HTTP ===")
|
|
req_data = json.dumps({
|
|
"id": "3",
|
|
"method": "otp_decrypt",
|
|
"params": [ciphertext, {"encoding": "ascii"}],
|
|
}).encode()
|
|
req = urllib.request.Request(url, data=req_data,
|
|
headers={"Content-Type": "application/json"})
|
|
with urllib.request.urlopen(req, timeout=5) as resp:
|
|
result = json.loads(resp.read().decode())
|
|
print(f"Response: {json.dumps(result)[:200]}...")
|
|
if "result" not in result:
|
|
print("ERROR: no result in otp_decrypt response")
|
|
return 1
|
|
dec_result = json.loads(result["result"])
|
|
recovered = base64.b64decode(dec_result["plaintext"]).decode()
|
|
print(f"Recovered plaintext: {recovered}")
|
|
|
|
if recovered == "Hello, OTP via HTTP!":
|
|
print("\n=== HTTP ROUND-TRIP SUCCESS ===")
|
|
return 0
|
|
else:
|
|
print("\n=== HTTP ROUND-TRIP FAILED ===")
|
|
print(f"Expected: Hello, OTP via HTTP!")
|
|
print(f"Got: {recovered}")
|
|
return 1
|
|
finally:
|
|
proc.terminate()
|
|
try:
|
|
proc.wait(timeout=3)
|
|
except subprocess.TimeoutExpired:
|
|
proc.kill()
|
|
try:
|
|
os.unlink(MNEMONIC_TMP)
|
|
except OSError:
|
|
pass
|
|
|
|
|
|
if __name__ == "__main__":
|
|
sys.exit(main())
|