dominusnode-langchain 1.2.3__tar.gz → 1.2.4__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {dominusnode_langchain-1.2.3 → dominusnode_langchain-1.2.4}/PKG-INFO +1 -1
- {dominusnode_langchain-1.2.3 → dominusnode_langchain-1.2.4}/dominusnode_langchain/tools.py +55 -4
- {dominusnode_langchain-1.2.3 → dominusnode_langchain-1.2.4}/pyproject.toml +1 -1
- {dominusnode_langchain-1.2.3 → dominusnode_langchain-1.2.4}/.gitignore +0 -0
- {dominusnode_langchain-1.2.3 → dominusnode_langchain-1.2.4}/CHANGELOG.md +0 -0
- {dominusnode_langchain-1.2.3 → dominusnode_langchain-1.2.4}/LICENSE +0 -0
- {dominusnode_langchain-1.2.3 → dominusnode_langchain-1.2.4}/README.md +0 -0
- {dominusnode_langchain-1.2.3 → dominusnode_langchain-1.2.4}/conftest.py +0 -0
- {dominusnode_langchain-1.2.3 → dominusnode_langchain-1.2.4}/dominusnode_langchain/__init__.py +0 -0
- {dominusnode_langchain-1.2.3 → dominusnode_langchain-1.2.4}/dominusnode_langchain/toolkit.py +0 -0
- {dominusnode_langchain-1.2.3 → dominusnode_langchain-1.2.4}/tests/__init__.py +0 -0
- {dominusnode_langchain-1.2.3 → dominusnode_langchain-1.2.4}/tests/test_tools.py +0 -0
|
@@ -15,6 +15,7 @@ Security:
|
|
|
15
15
|
|
|
16
16
|
from __future__ import annotations
|
|
17
17
|
|
|
18
|
+
import hashlib
|
|
18
19
|
import ipaddress
|
|
19
20
|
import math
|
|
20
21
|
import os
|
|
@@ -63,6 +64,46 @@ def _sanitize_error(message: str) -> str:
|
|
|
63
64
|
return _CREDENTIAL_RE.sub("***", message)
|
|
64
65
|
|
|
65
66
|
|
|
67
|
+
def _count_leading_zero_bits(data: bytes) -> int:
|
|
68
|
+
"""Count leading zero bits in a byte array."""
|
|
69
|
+
count = 0
|
|
70
|
+
for byte in data:
|
|
71
|
+
if byte == 0:
|
|
72
|
+
count += 8
|
|
73
|
+
else:
|
|
74
|
+
mask = 0x80
|
|
75
|
+
while mask and not (byte & mask):
|
|
76
|
+
count += 1
|
|
77
|
+
mask >>= 1
|
|
78
|
+
break
|
|
79
|
+
return count
|
|
80
|
+
|
|
81
|
+
|
|
82
|
+
def _solve_pow(base_url: str) -> Optional[dict]:
|
|
83
|
+
"""Solve a Proof-of-Work challenge for CAPTCHA-free registration."""
|
|
84
|
+
try:
|
|
85
|
+
pow_url = f"{base_url.rstrip('/')}/api/auth/pow/challenge"
|
|
86
|
+
with httpx.Client(timeout=30.0, follow_redirects=False) as client:
|
|
87
|
+
resp = client.post(pow_url, headers={"Content-Type": "application/json"})
|
|
88
|
+
if resp.status_code >= 400:
|
|
89
|
+
return None
|
|
90
|
+
challenge = resp.json()
|
|
91
|
+
prefix = challenge.get("prefix", "")
|
|
92
|
+
difficulty = challenge.get("difficulty", 20)
|
|
93
|
+
challenge_id = challenge.get("challengeId", "")
|
|
94
|
+
if not prefix or not challenge_id:
|
|
95
|
+
return None
|
|
96
|
+
nonce = 0
|
|
97
|
+
while nonce < 100_000_000:
|
|
98
|
+
h = hashlib.sha256((prefix + str(nonce)).encode()).digest()
|
|
99
|
+
if _count_leading_zero_bits(h) >= difficulty:
|
|
100
|
+
return {"challengeId": challenge_id, "nonce": str(nonce)}
|
|
101
|
+
nonce += 1
|
|
102
|
+
return None
|
|
103
|
+
except Exception:
|
|
104
|
+
return None
|
|
105
|
+
|
|
106
|
+
|
|
66
107
|
# ──────────────────────────────────────────────────────────────────────
|
|
67
108
|
# Prototype pollution prevention
|
|
68
109
|
# ──────────────────────────────────────────────────────────────────────
|
|
@@ -2363,9 +2404,14 @@ class DominusNodeRegisterTool(BaseTool):
|
|
|
2363
2404
|
if not password or len(password) < 8 or len(password) > 128:
|
|
2364
2405
|
return "Error: Password must be between 8 and 128 characters."
|
|
2365
2406
|
try:
|
|
2366
|
-
|
|
2407
|
+
body: dict = {"email": email, "password": password}
|
|
2408
|
+
pow_result = _solve_pow(self.base_url)
|
|
2409
|
+
if pow_result:
|
|
2410
|
+
body["pow"] = pow_result
|
|
2411
|
+
data = _api_request_unauth_sync(self.base_url, "POST", "/api/auth/register", body, agent_secret=self.agent_secret)
|
|
2367
2412
|
user = data.get("user", {})
|
|
2368
|
-
|
|
2413
|
+
pow_msg = "Email auto-verified via Proof-of-Work." if pow_result else "Email auto-verified (MCP agent)"
|
|
2414
|
+
return f"Account Created\n Email: {user.get('email', email)}\n User ID: {user.get('id', '?')}\n {pow_msg}"
|
|
2369
2415
|
except Exception as exc:
|
|
2370
2416
|
return f"Error: {_sanitize_error(str(exc))}"
|
|
2371
2417
|
|
|
@@ -2377,9 +2423,14 @@ class DominusNodeRegisterTool(BaseTool):
|
|
|
2377
2423
|
if not password or len(password) < 8 or len(password) > 128:
|
|
2378
2424
|
return "Error: Password must be between 8 and 128 characters."
|
|
2379
2425
|
try:
|
|
2380
|
-
|
|
2426
|
+
body: dict = {"email": email, "password": password}
|
|
2427
|
+
pow_result = _solve_pow(self.base_url)
|
|
2428
|
+
if pow_result:
|
|
2429
|
+
body["pow"] = pow_result
|
|
2430
|
+
data = await _api_request_unauth_async(self.base_url, "POST", "/api/auth/register", body, agent_secret=self.agent_secret)
|
|
2381
2431
|
user = data.get("user", {})
|
|
2382
|
-
|
|
2432
|
+
pow_msg = "Email auto-verified via Proof-of-Work." if pow_result else "Email auto-verified (MCP agent)"
|
|
2433
|
+
return f"Account Created\n Email: {user.get('email', email)}\n User ID: {user.get('id', '?')}\n {pow_msg}"
|
|
2383
2434
|
except Exception as exc:
|
|
2384
2435
|
return f"Error: {_sanitize_error(str(exc))}"
|
|
2385
2436
|
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{dominusnode_langchain-1.2.3 → dominusnode_langchain-1.2.4}/dominusnode_langchain/__init__.py
RENAMED
|
File without changes
|
{dominusnode_langchain-1.2.3 → dominusnode_langchain-1.2.4}/dominusnode_langchain/toolkit.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|