dominusnode-langchain 1.2.2__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.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: dominusnode-langchain
3
- Version: 1.2.2
3
+ Version: 1.2.4
4
4
  Summary: LangChain tools for Dominus Node rotating proxy service
5
5
  License-Expression: MIT
6
6
  License-File: LICENSE
@@ -95,7 +95,7 @@ tools = toolkit.get_tools()
95
95
 
96
96
  # Get tools by name
97
97
  fetch_tool = next(t for t in tools if t.name == "dominusnode_proxied_fetch")
98
- balance_tool = next(t for t in tools if t.name == "dominusnode_balance")
98
+ balance_tool = next(t for t in tools if t.name == "dominusnode_check_balance")
99
99
 
100
100
  # Check balance
101
101
  print(balance_tool.run({}))
@@ -134,19 +134,19 @@ Makes HTTP requests through the Dominus Node rotating proxy network.
134
134
  - `file://`, `ftp://`, and other non-HTTP schemes are rejected
135
135
  - URLs with embedded credentials are rejected
136
136
 
137
- ### `dominusnode_balance`
137
+ ### `dominusnode_check_balance`
138
138
 
139
139
  Check your Dominus Node wallet balance. No input required.
140
140
 
141
141
  Returns the balance in both USD and cents.
142
142
 
143
- ### `dominusnode_usage`
143
+ ### `dominusnode_check_usage`
144
144
 
145
145
  Check your Dominus Node proxy usage statistics. No input required.
146
146
 
147
147
  Returns total bandwidth used (GB), total cost, and request count.
148
148
 
149
- ### `dominusnode_proxy_config`
149
+ ### `dominusnode_get_proxy_config`
150
150
 
151
151
  Get the Dominus Node proxy configuration. No input required.
152
152
 
@@ -164,7 +164,7 @@ async def main():
164
164
  toolkit = DominusNodeToolkit(api_key="dn_live_your_key")
165
165
  tools = toolkit.get_tools()
166
166
 
167
- balance_tool = next(t for t in tools if t.name == "dominusnode_balance")
167
+ balance_tool = next(t for t in tools if t.name == "dominusnode_check_balance")
168
168
  fetch_tool = next(t for t in tools if t.name == "dominusnode_proxied_fetch")
169
169
 
170
170
  # Async balance check
@@ -80,7 +80,7 @@ tools = toolkit.get_tools()
80
80
 
81
81
  # Get tools by name
82
82
  fetch_tool = next(t for t in tools if t.name == "dominusnode_proxied_fetch")
83
- balance_tool = next(t for t in tools if t.name == "dominusnode_balance")
83
+ balance_tool = next(t for t in tools if t.name == "dominusnode_check_balance")
84
84
 
85
85
  # Check balance
86
86
  print(balance_tool.run({}))
@@ -119,19 +119,19 @@ Makes HTTP requests through the Dominus Node rotating proxy network.
119
119
  - `file://`, `ftp://`, and other non-HTTP schemes are rejected
120
120
  - URLs with embedded credentials are rejected
121
121
 
122
- ### `dominusnode_balance`
122
+ ### `dominusnode_check_balance`
123
123
 
124
124
  Check your Dominus Node wallet balance. No input required.
125
125
 
126
126
  Returns the balance in both USD and cents.
127
127
 
128
- ### `dominusnode_usage`
128
+ ### `dominusnode_check_usage`
129
129
 
130
130
  Check your Dominus Node proxy usage statistics. No input required.
131
131
 
132
132
  Returns total bandwidth used (GB), total cost, and request count.
133
133
 
134
- ### `dominusnode_proxy_config`
134
+ ### `dominusnode_get_proxy_config`
135
135
 
136
136
  Get the Dominus Node proxy configuration. No input required.
137
137
 
@@ -149,7 +149,7 @@ async def main():
149
149
  toolkit = DominusNodeToolkit(api_key="dn_live_your_key")
150
150
  tools = toolkit.get_tools()
151
151
 
152
- balance_tool = next(t for t in tools if t.name == "dominusnode_balance")
152
+ balance_tool = next(t for t in tools if t.name == "dominusnode_check_balance")
153
153
  fetch_tool = next(t for t in tools if t.name == "dominusnode_proxied_fetch")
154
154
 
155
155
  # Async balance check
@@ -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
  # ──────────────────────────────────────────────────────────────────────
@@ -439,7 +480,7 @@ class DominusNodeBalanceTool(BaseTool):
439
480
  spend before making proxied requests.
440
481
  """
441
482
 
442
- name: str = "dominusnode_balance"
483
+ name: str = "dominusnode_check_balance"
443
484
  description: str = (
444
485
  "Check your Dominus Node wallet balance. Returns the current balance "
445
486
  "in dollars and cents. No input required."
@@ -494,7 +535,7 @@ class DominusNodeUsageTool(BaseTool):
494
535
  cost, and request count.
495
536
  """
496
537
 
497
- name: str = "dominusnode_usage"
538
+ name: str = "dominusnode_check_usage"
498
539
  description: str = (
499
540
  "Check your Dominus Node proxy usage statistics. Returns total bandwidth "
500
541
  "used (in GB), total cost, and request count. No input required."
@@ -608,8 +649,6 @@ class TopupStripeInput(BaseModel):
608
649
  """Input schema for the Dominus Node Stripe top-up tool."""
609
650
 
610
651
  amount_cents: int = Field(
611
- ge=500,
612
- le=100000,
613
652
  description="Amount in cents to top up via Stripe (min 500 = $5, max 100000 = $1,000).",
614
653
  )
615
654
 
@@ -664,8 +703,6 @@ class TopupCryptoInput(BaseModel):
664
703
  """Input schema for the Dominus Node crypto top-up tool."""
665
704
 
666
705
  amount_usd: float = Field(
667
- ge=5,
668
- le=1000,
669
706
  description="Amount in USD to top up with cryptocurrency (min 5, max 1000).",
670
707
  )
671
708
  currency: str = Field(
@@ -750,7 +787,7 @@ class DominusNodeProxyConfigTool(BaseTool):
750
787
  and available geo-targeting features.
751
788
  """
752
789
 
753
- name: str = "dominusnode_proxy_config"
790
+ name: str = "dominusnode_get_proxy_config"
754
791
  description: str = (
755
792
  "Get the Dominus Node proxy configuration including supported countries, "
756
793
  "proxy endpoints, and geo-targeting capabilities. No input required."
@@ -2003,7 +2040,7 @@ def _validate_team_id(team_id: Any) -> Optional[str]:
2003
2040
  class DominusNodeProxyStatusTool(BaseTool):
2004
2041
  """Get live proxy network status."""
2005
2042
 
2006
- name: str = "dominusnode_proxy_status"
2043
+ name: str = "dominusnode_get_proxy_status"
2007
2044
  description: str = (
2008
2045
  "Get live proxy network status including latency, active session count, "
2009
2046
  "and uptime. No input required."
@@ -2227,7 +2264,7 @@ class DominusNodeCheckPaymentTool(BaseTool):
2227
2264
  class DominusNodeDailyUsageTool(BaseTool):
2228
2265
  """Get daily bandwidth breakdown."""
2229
2266
 
2230
- name: str = "dominusnode_daily_usage"
2267
+ name: str = "dominusnode_get_daily_usage"
2231
2268
  description: str = "Get daily bandwidth breakdown. Input: optional days (1-90, default 7)."
2232
2269
  args_schema: Type[BaseModel] = GetDailyUsageInput
2233
2270
  api_key: Optional[str] = None
@@ -2285,7 +2322,7 @@ class DominusNodeDailyUsageTool(BaseTool):
2285
2322
  class DominusNodeTopHostsTool(BaseTool):
2286
2323
  """Get top target hosts by bandwidth."""
2287
2324
 
2288
- name: str = "dominusnode_top_hosts"
2325
+ name: str = "dominusnode_get_top_hosts"
2289
2326
  description: str = "Get top target hosts by bandwidth usage. Input: optional limit (1-50), days (1-365)."
2290
2327
  args_schema: Type[BaseModel] = GetTopHostsInput
2291
2328
  api_key: Optional[str] = None
@@ -2367,9 +2404,14 @@ class DominusNodeRegisterTool(BaseTool):
2367
2404
  if not password or len(password) < 8 or len(password) > 128:
2368
2405
  return "Error: Password must be between 8 and 128 characters."
2369
2406
  try:
2370
- data = _api_request_unauth_sync(self.base_url, "POST", "/api/auth/register", {"email": email, "password": password}, agent_secret=self.agent_secret)
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)
2371
2412
  user = data.get("user", {})
2372
- return f"Account Created\n Email: {user.get('email', email)}\n User ID: {user.get('id', '?')}\n Email auto-verified (MCP agent)"
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}"
2373
2415
  except Exception as exc:
2374
2416
  return f"Error: {_sanitize_error(str(exc))}"
2375
2417
 
@@ -2381,9 +2423,14 @@ class DominusNodeRegisterTool(BaseTool):
2381
2423
  if not password or len(password) < 8 or len(password) > 128:
2382
2424
  return "Error: Password must be between 8 and 128 characters."
2383
2425
  try:
2384
- data = await _api_request_unauth_async(self.base_url, "POST", "/api/auth/register", {"email": email, "password": password}, agent_secret=self.agent_secret)
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)
2385
2431
  user = data.get("user", {})
2386
- return f"Account Created\n Email: {user.get('email', email)}\n User ID: {user.get('id', '?')}\n Email auto-verified (MCP agent)"
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}"
2387
2434
  except Exception as exc:
2388
2435
  return f"Error: {_sanitize_error(str(exc))}"
2389
2436
 
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "dominusnode-langchain"
7
- version = "1.2.2"
7
+ version = "1.2.4"
8
8
  description = "LangChain tools for Dominus Node rotating proxy service"
9
9
  readme = "README.md"
10
10
  license = "MIT"