- Exclude already-swept payments from watcher queue to prevent endless processing - Mark swept payments as "swept" status to remove from future cycles - Fix cart deactivation by ensuring shop/user objects are attached to session - Add debug logging for cart deactivation to track behavior - Resolves issue where confirmed payments were processed every 20 seconds indefinitely 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
76 lines
2.6 KiB
Python
76 lines
2.6 KiB
Python
#!/usr/bin/env python3
|
|
"""
|
|
Debug script to examine the exact WWW-Authenticate header
|
|
that Monero wallet RPC sends and how urllib handles it.
|
|
"""
|
|
import urllib.request
|
|
import urllib.error
|
|
import json
|
|
|
|
|
|
def examine_auth_challenge():
|
|
"""Look at the WWW-Authenticate header from the server"""
|
|
print("=== Examining Authentication Challenge ===")
|
|
|
|
rpc_url = "http://127.0.0.1:18083/json_rpc"
|
|
payload = {"jsonrpc": "2.0", "id": 1, "method": "get_height"}
|
|
data = json.dumps(payload).encode()
|
|
|
|
# Make request without auth to get the challenge
|
|
req = urllib.request.Request(
|
|
rpc_url, data=data, headers={"Content-Type": "application/json"}
|
|
)
|
|
|
|
try:
|
|
with urllib.request.urlopen(req) as resp:
|
|
print("Unexpected: No auth required")
|
|
return None
|
|
except urllib.error.HTTPError as e:
|
|
if e.code == 401:
|
|
www_auth = e.headers.get("WWW-Authenticate", "")
|
|
print(f"WWW-Authenticate header: {www_auth!r}")
|
|
|
|
# Parse it
|
|
if www_auth.startswith("Digest "):
|
|
challenge = www_auth[7:].strip()
|
|
print(f"Challenge details: {challenge}")
|
|
|
|
# Parse individual components
|
|
import re
|
|
|
|
pattern = r'(\w+)=(?:"([^"]*)"|([^,\s]+))'
|
|
matches = re.findall(pattern, challenge)
|
|
|
|
print("Parsed components:")
|
|
for key, quoted_val, unquoted_val in matches:
|
|
val = quoted_val if quoted_val else unquoted_val
|
|
print(f" {key} = {val!r}")
|
|
|
|
return dict(
|
|
(key, quoted_val if quoted_val else unquoted_val)
|
|
for key, quoted_val, unquoted_val in matches
|
|
)
|
|
else:
|
|
print(f"Not Digest auth: {www_auth}")
|
|
return None
|
|
else:
|
|
print(f"Unexpected error: {e.code} {e.reason}")
|
|
return None
|
|
|
|
|
|
if __name__ == "__main__":
|
|
challenge = examine_auth_challenge()
|
|
|
|
if challenge:
|
|
print()
|
|
print("=== Analysis ===")
|
|
print(f"Realm: {challenge.get('realm', 'NOT SET')}")
|
|
print(f"Nonce: {challenge.get('nonce', 'NOT SET')}")
|
|
print(f"QOP: {challenge.get('qop', 'NOT SET')}")
|
|
print(f"Algorithm: {challenge.get('algorithm', 'NOT SET (defaults to MD5)')}")
|
|
|
|
# Check for any unusual parameters
|
|
standard_params = {"realm", "nonce", "qop", "algorithm", "opaque"}
|
|
extra_params = set(challenge.keys()) - standard_params
|
|
if extra_params:
|
|
print(f"Extra parameters: {extra_params}")
|