dominusnode-dify 1.0.0__tar.gz → 1.1.0__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.
Potentially problematic release.
This version of dominusnode-dify might be problematic. Click here for more details.
- {dominusnode_dify-1.0.0 → dominusnode_dify-1.1.0}/PKG-INFO +5 -4
- {dominusnode_dify-1.0.0 → dominusnode_dify-1.1.0}/README.md +1 -1
- {dominusnode_dify-1.0.0 → dominusnode_dify-1.1.0}/dominusnode_dify/__init__.py +4 -4
- {dominusnode_dify-1.0.0 → dominusnode_dify-1.1.0}/dominusnode_dify/tools.py +129 -20
- {dominusnode_dify-1.0.0 → dominusnode_dify-1.1.0}/dominusnode_dify.egg-info/PKG-INFO +5 -4
- {dominusnode_dify-1.0.0 → dominusnode_dify-1.1.0}/pyproject.toml +2 -2
- {dominusnode_dify-1.0.0 → dominusnode_dify-1.1.0}/tests/test_tools.py +1 -1
- {dominusnode_dify-1.0.0 → dominusnode_dify-1.1.0}/LICENSE +0 -0
- {dominusnode_dify-1.0.0 → dominusnode_dify-1.1.0}/dominusnode_dify.egg-info/SOURCES.txt +0 -0
- {dominusnode_dify-1.0.0 → dominusnode_dify-1.1.0}/dominusnode_dify.egg-info/dependency_links.txt +0 -0
- {dominusnode_dify-1.0.0 → dominusnode_dify-1.1.0}/dominusnode_dify.egg-info/requires.txt +0 -0
- {dominusnode_dify-1.0.0 → dominusnode_dify-1.1.0}/dominusnode_dify.egg-info/top_level.txt +0 -0
- {dominusnode_dify-1.0.0 → dominusnode_dify-1.1.0}/setup.cfg +0 -0
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
Metadata-Version: 2.
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
2
|
Name: dominusnode-dify
|
|
3
|
-
Version: 1.
|
|
4
|
-
Summary:
|
|
3
|
+
Version: 1.1.0
|
|
4
|
+
Summary: Dominus Node tool provider for Dify -- 22 proxy, wallet, and team management tools
|
|
5
5
|
License: MIT
|
|
6
6
|
Requires-Python: >=3.10
|
|
7
7
|
Description-Content-Type: text/markdown
|
|
@@ -9,10 +9,11 @@ License-File: LICENSE
|
|
|
9
9
|
Requires-Dist: httpx>=0.25.0
|
|
10
10
|
Provides-Extra: dev
|
|
11
11
|
Requires-Dist: pytest>=7.0; extra == "dev"
|
|
12
|
+
Dynamic: license-file
|
|
12
13
|
|
|
13
14
|
# dominusnode-dify
|
|
14
15
|
|
|
15
|
-
Dify tool provider for the [
|
|
16
|
+
Dify tool provider for the [Dominus Node](https://dominusnode.com) rotating proxy-as-a-service platform. Provides 22 tools for proxy management, wallet operations, team administration, and payment processing.
|
|
16
17
|
|
|
17
18
|
## Installation
|
|
18
19
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# dominusnode-dify
|
|
2
2
|
|
|
3
|
-
Dify tool provider for the [
|
|
3
|
+
Dify tool provider for the [Dominus Node](https://dominusnode.com) rotating proxy-as-a-service platform. Provides 22 tools for proxy management, wallet operations, team administration, and payment processing.
|
|
4
4
|
|
|
5
5
|
## Installation
|
|
6
6
|
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
"""
|
|
1
|
+
"""Dominus Node Dify integration -- 26 tools for the Dify AI platform.
|
|
2
2
|
|
|
3
|
-
Provides a Dify-compatible tool provider that exposes
|
|
4
|
-
interacting with the
|
|
3
|
+
Provides a Dify-compatible tool provider that exposes 26 tools for
|
|
4
|
+
interacting with the Dominus Node rotating proxy-as-a-service platform.
|
|
5
5
|
|
|
6
6
|
Tools cover:
|
|
7
7
|
- Proxied HTTP fetching through rotating proxies
|
|
@@ -10,7 +10,7 @@ Tools cover:
|
|
|
10
10
|
- Agentic wallet management (create, fund, freeze, unfreeze, delete)
|
|
11
11
|
- Team management (create, list, fund, keys, usage, update, role changes)
|
|
12
12
|
- x402 micropayment info
|
|
13
|
-
- PayPal top-up
|
|
13
|
+
- PayPal, Stripe, and crypto top-up
|
|
14
14
|
|
|
15
15
|
Security:
|
|
16
16
|
- Full SSRF prevention (private IP blocking, DNS rebinding, Teredo/6to4,
|
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
"""
|
|
1
|
+
"""Dominus Node Dify tool provider -- 26 tools with full security hardening.
|
|
2
2
|
|
|
3
3
|
This module implements the DominusNodeProvider class that Dify invokes.
|
|
4
4
|
Each tool is a method that receives credentials (from the provider YAML)
|
|
5
5
|
and parameters (from the tool YAML), performs the operation against the
|
|
6
|
-
|
|
6
|
+
Dominus Node REST API, and returns a dict result.
|
|
7
7
|
|
|
8
8
|
Security code is copied verbatim from the AutoGPT integration to ensure
|
|
9
9
|
identical SSRF, OFAC, credential scrubbing, and prototype pollution
|
|
@@ -14,6 +14,7 @@ from __future__ import annotations
|
|
|
14
14
|
|
|
15
15
|
import ipaddress
|
|
16
16
|
import json
|
|
17
|
+
import math
|
|
17
18
|
import os
|
|
18
19
|
import re
|
|
19
20
|
import socket
|
|
@@ -346,7 +347,7 @@ _CREDENTIAL_RE = re.compile(r"dn_(live|test)_[a-zA-Z0-9]+")
|
|
|
346
347
|
|
|
347
348
|
|
|
348
349
|
def _sanitize_error(message: str) -> str:
|
|
349
|
-
"""Remove
|
|
350
|
+
"""Remove Dominus Node API key patterns from error messages."""
|
|
350
351
|
return _CREDENTIAL_RE.sub("***", message)
|
|
351
352
|
|
|
352
353
|
|
|
@@ -474,9 +475,9 @@ def _validate_allowed_domains(domains: Any) -> Optional[str]:
|
|
|
474
475
|
|
|
475
476
|
|
|
476
477
|
class DominusNodeProvider:
|
|
477
|
-
"""Dify tool provider for
|
|
478
|
+
"""Dify tool provider for Dominus Node rotating proxy service.
|
|
478
479
|
|
|
479
|
-
Authenticates using a
|
|
480
|
+
Authenticates using a Dominus Node API key and exposes 26 tool methods that
|
|
480
481
|
Dify can invoke. Each tool method receives ``credentials`` and ``params``
|
|
481
482
|
dicts from the Dify runtime and returns a dict result.
|
|
482
483
|
|
|
@@ -502,6 +503,7 @@ class DominusNodeProvider:
|
|
|
502
503
|
self.proxy_host: str = creds.get("proxy_host", "") or os.environ.get("DOMINUSNODE_PROXY_HOST", "proxy.dominusnode.com")
|
|
503
504
|
self.proxy_port: int = int(os.environ.get("DOMINUSNODE_PROXY_PORT", "8080"))
|
|
504
505
|
self.timeout: float = 30.0
|
|
506
|
+
self.agent_secret: str | None = creds.get("agent_secret") or os.environ.get("DOMINUSNODE_AGENT_SECRET")
|
|
505
507
|
self._token: str | None = None
|
|
506
508
|
|
|
507
509
|
# ------------------------------------------------------------------
|
|
@@ -509,7 +511,7 @@ class DominusNodeProvider:
|
|
|
509
511
|
# ------------------------------------------------------------------
|
|
510
512
|
|
|
511
513
|
def _authenticate(self) -> str:
|
|
512
|
-
"""Authenticate with the
|
|
514
|
+
"""Authenticate with the Dominus Node API using the API key.
|
|
513
515
|
|
|
514
516
|
Returns:
|
|
515
517
|
The JWT bearer token.
|
|
@@ -519,10 +521,18 @@ class DominusNodeProvider:
|
|
|
519
521
|
"""
|
|
520
522
|
if not self.api_key:
|
|
521
523
|
raise RuntimeError(
|
|
522
|
-
"
|
|
524
|
+
"Dominus Node API key is required. Set api_key in provider credentials "
|
|
523
525
|
"or DOMINUSNODE_API_KEY environment variable."
|
|
524
526
|
)
|
|
525
527
|
|
|
528
|
+
auth_headers = {
|
|
529
|
+
"User-Agent": "dominusnode-dify/1.0.0",
|
|
530
|
+
"Content-Type": "application/json",
|
|
531
|
+
}
|
|
532
|
+
if self.agent_secret:
|
|
533
|
+
auth_headers["X-DominusNode-Agent"] = "mcp"
|
|
534
|
+
auth_headers["X-DominusNode-Agent-Secret"] = self.agent_secret
|
|
535
|
+
|
|
526
536
|
with httpx.Client(
|
|
527
537
|
timeout=self.timeout,
|
|
528
538
|
follow_redirects=False,
|
|
@@ -530,10 +540,7 @@ class DominusNodeProvider:
|
|
|
530
540
|
resp = client.post(
|
|
531
541
|
f"{self.base_url}/api/auth/verify-key",
|
|
532
542
|
json={"apiKey": self.api_key},
|
|
533
|
-
headers=
|
|
534
|
-
"User-Agent": "dominusnode-dify/1.0.0",
|
|
535
|
-
"Content-Type": "application/json",
|
|
536
|
-
},
|
|
543
|
+
headers=auth_headers,
|
|
537
544
|
)
|
|
538
545
|
|
|
539
546
|
if resp.status_code != 200:
|
|
@@ -564,7 +571,7 @@ class DominusNodeProvider:
|
|
|
564
571
|
path: str,
|
|
565
572
|
body: Optional[Dict[str, Any]] = None,
|
|
566
573
|
) -> Any:
|
|
567
|
-
"""Make an authenticated API request to the
|
|
574
|
+
"""Make an authenticated API request to the Dominus Node REST API.
|
|
568
575
|
|
|
569
576
|
Args:
|
|
570
577
|
method: HTTP method (GET, POST, PATCH, DELETE).
|
|
@@ -584,12 +591,17 @@ class DominusNodeProvider:
|
|
|
584
591
|
timeout=self.timeout,
|
|
585
592
|
follow_redirects=False,
|
|
586
593
|
) as client:
|
|
594
|
+
req_headers = {
|
|
595
|
+
"User-Agent": "dominusnode-dify/1.0.0",
|
|
596
|
+
"Content-Type": "application/json",
|
|
597
|
+
"Authorization": f"Bearer {self._token}",
|
|
598
|
+
}
|
|
599
|
+
if self.agent_secret:
|
|
600
|
+
req_headers["X-DominusNode-Agent"] = "mcp"
|
|
601
|
+
req_headers["X-DominusNode-Agent-Secret"] = self.agent_secret
|
|
602
|
+
|
|
587
603
|
kwargs: Dict[str, Any] = {
|
|
588
|
-
"headers":
|
|
589
|
-
"User-Agent": "dominusnode-dify/1.0.0",
|
|
590
|
-
"Content-Type": "application/json",
|
|
591
|
-
"Authorization": f"Bearer {self._token}",
|
|
592
|
-
},
|
|
604
|
+
"headers": req_headers,
|
|
593
605
|
}
|
|
594
606
|
|
|
595
607
|
if body is not None and method.upper() not in ("GET", "HEAD", "OPTIONS"):
|
|
@@ -639,7 +651,7 @@ class DominusNodeProvider:
|
|
|
639
651
|
# ==================================================================
|
|
640
652
|
|
|
641
653
|
def proxied_fetch(self, params: Dict[str, Any]) -> Dict[str, Any]:
|
|
642
|
-
"""Fetch a URL through the
|
|
654
|
+
"""Fetch a URL through the Dominus Node rotating proxy network.
|
|
643
655
|
|
|
644
656
|
Args:
|
|
645
657
|
params: Dict with keys: url (required), method, country, proxy_type.
|
|
@@ -724,7 +736,7 @@ class DominusNodeProvider:
|
|
|
724
736
|
except Exception as e:
|
|
725
737
|
return {
|
|
726
738
|
"error": f"Proxy fetch failed: {_sanitize_error(str(e))}",
|
|
727
|
-
"hint": "Ensure the
|
|
739
|
+
"hint": "Ensure the Dominus Node proxy gateway is running and accessible.",
|
|
728
740
|
}
|
|
729
741
|
|
|
730
742
|
# ==================================================================
|
|
@@ -1480,6 +1492,99 @@ class DominusNodeProvider:
|
|
|
1480
1492
|
except Exception as e:
|
|
1481
1493
|
return {"error": _sanitize_error(str(e))}
|
|
1482
1494
|
|
|
1495
|
+
# ==================================================================
|
|
1496
|
+
# Tool 24: topup_stripe
|
|
1497
|
+
# ==================================================================
|
|
1498
|
+
|
|
1499
|
+
def topup_stripe(self, params: Dict[str, Any]) -> Dict[str, Any]:
|
|
1500
|
+
"""Create a Stripe checkout session for wallet top-up.
|
|
1501
|
+
|
|
1502
|
+
Args:
|
|
1503
|
+
params: Dict with key: amount_cents (required, 500-100000).
|
|
1504
|
+
|
|
1505
|
+
Returns:
|
|
1506
|
+
Dict with checkout session details.
|
|
1507
|
+
"""
|
|
1508
|
+
amount_cents = params.get("amount_cents")
|
|
1509
|
+
if amount_cents is None:
|
|
1510
|
+
return {"error": "amount_cents is required"}
|
|
1511
|
+
|
|
1512
|
+
# Dify sends numbers as float; coerce to int
|
|
1513
|
+
if isinstance(amount_cents, float):
|
|
1514
|
+
if not math.isfinite(amount_cents):
|
|
1515
|
+
return {"error": "amount_cents must be an integer between 500 and 100000"}
|
|
1516
|
+
if amount_cents == int(amount_cents):
|
|
1517
|
+
amount_cents = int(amount_cents)
|
|
1518
|
+
|
|
1519
|
+
err = _validate_positive_int(
|
|
1520
|
+
amount_cents, "amount_cents", min_value=500, max_value=100_000
|
|
1521
|
+
)
|
|
1522
|
+
if err:
|
|
1523
|
+
return {"error": err}
|
|
1524
|
+
|
|
1525
|
+
try:
|
|
1526
|
+
result = self._request_with_retry(
|
|
1527
|
+
"POST",
|
|
1528
|
+
"/api/wallet/topup/stripe",
|
|
1529
|
+
{"amountCents": amount_cents},
|
|
1530
|
+
)
|
|
1531
|
+
return result if isinstance(result, dict) else {"data": result}
|
|
1532
|
+
except Exception as e:
|
|
1533
|
+
return {"error": _sanitize_error(str(e))}
|
|
1534
|
+
|
|
1535
|
+
# ==================================================================
|
|
1536
|
+
# Tool 25: topup_crypto
|
|
1537
|
+
# ==================================================================
|
|
1538
|
+
|
|
1539
|
+
_VALID_CRYPTO_CURRENCIES = {
|
|
1540
|
+
"BTC", "ETH", "LTC", "XMR", "ZEC",
|
|
1541
|
+
"USDC", "SOL", "USDT", "DAI", "BNB", "LINK",
|
|
1542
|
+
}
|
|
1543
|
+
|
|
1544
|
+
def topup_crypto(self, params: Dict[str, Any]) -> Dict[str, Any]:
|
|
1545
|
+
"""Create a crypto payment invoice for wallet top-up.
|
|
1546
|
+
|
|
1547
|
+
Args:
|
|
1548
|
+
params: Dict with keys: amount_usd (required, 5-1000),
|
|
1549
|
+
currency (required, one of BTC/ETH/LTC/XMR/ZEC/USDC/SOL/
|
|
1550
|
+
USDT/DAI/BNB/LINK).
|
|
1551
|
+
|
|
1552
|
+
Returns:
|
|
1553
|
+
Dict with invoice details for completing the crypto payment.
|
|
1554
|
+
"""
|
|
1555
|
+
amount_usd = params.get("amount_usd")
|
|
1556
|
+
currency = params.get("currency")
|
|
1557
|
+
|
|
1558
|
+
if amount_usd is None:
|
|
1559
|
+
return {"error": "amount_usd is required"}
|
|
1560
|
+
|
|
1561
|
+
# Dify sends numbers as float; keep as-is but validate
|
|
1562
|
+
if isinstance(amount_usd, bool) or not isinstance(amount_usd, (int, float)):
|
|
1563
|
+
return {"error": "amount_usd must be a number between 5 and 1,000"}
|
|
1564
|
+
if not math.isfinite(amount_usd):
|
|
1565
|
+
return {"error": "amount_usd must be a number between 5 and 1,000"}
|
|
1566
|
+
if amount_usd < 5 or amount_usd > 1000:
|
|
1567
|
+
return {"error": "amount_usd must be a number between 5 and 1,000"}
|
|
1568
|
+
|
|
1569
|
+
if not currency or not isinstance(currency, str):
|
|
1570
|
+
return {
|
|
1571
|
+
"error": "currency must be one of: BTC, ETH, LTC, XMR, ZEC, USDC, SOL, USDT, DAI, BNB, LINK",
|
|
1572
|
+
}
|
|
1573
|
+
if currency.upper() not in self._VALID_CRYPTO_CURRENCIES:
|
|
1574
|
+
return {
|
|
1575
|
+
"error": "currency must be one of: BTC, ETH, LTC, XMR, ZEC, USDC, SOL, USDT, DAI, BNB, LINK",
|
|
1576
|
+
}
|
|
1577
|
+
|
|
1578
|
+
try:
|
|
1579
|
+
result = self._request_with_retry(
|
|
1580
|
+
"POST",
|
|
1581
|
+
"/api/wallet/topup/crypto",
|
|
1582
|
+
{"amountUsd": amount_usd, "currency": currency.lower()},
|
|
1583
|
+
)
|
|
1584
|
+
return result if isinstance(result, dict) else {"data": result}
|
|
1585
|
+
except Exception as e:
|
|
1586
|
+
return {"error": _sanitize_error(str(e))}
|
|
1587
|
+
|
|
1483
1588
|
# ==================================================================
|
|
1484
1589
|
# Tool dispatcher (Dify invokes tools by name)
|
|
1485
1590
|
# ==================================================================
|
|
@@ -1521,6 +1626,8 @@ class DominusNodeProvider:
|
|
|
1521
1626
|
"update_team_member_role": self.update_team_member_role,
|
|
1522
1627
|
"x402_info": self.x402_info,
|
|
1523
1628
|
"topup_paypal": self.topup_paypal,
|
|
1629
|
+
"topup_stripe": self.topup_stripe,
|
|
1630
|
+
"topup_crypto": self.topup_crypto,
|
|
1524
1631
|
}
|
|
1525
1632
|
|
|
1526
1633
|
handler = dispatch.get(tool_name)
|
|
@@ -1537,7 +1644,7 @@ class DominusNodeProvider:
|
|
|
1537
1644
|
|
|
1538
1645
|
@staticmethod
|
|
1539
1646
|
def get_tools() -> list[str]:
|
|
1540
|
-
"""Return the list of all
|
|
1647
|
+
"""Return the list of all 26 tool names.
|
|
1541
1648
|
|
|
1542
1649
|
Returns:
|
|
1543
1650
|
Sorted list of tool name strings.
|
|
@@ -1567,4 +1674,6 @@ class DominusNodeProvider:
|
|
|
1567
1674
|
"update_team_member_role",
|
|
1568
1675
|
"x402_info",
|
|
1569
1676
|
"topup_paypal",
|
|
1677
|
+
"topup_stripe",
|
|
1678
|
+
"topup_crypto",
|
|
1570
1679
|
])
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
Metadata-Version: 2.
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
2
|
Name: dominusnode-dify
|
|
3
|
-
Version: 1.
|
|
4
|
-
Summary:
|
|
3
|
+
Version: 1.1.0
|
|
4
|
+
Summary: Dominus Node tool provider for Dify -- 22 proxy, wallet, and team management tools
|
|
5
5
|
License: MIT
|
|
6
6
|
Requires-Python: >=3.10
|
|
7
7
|
Description-Content-Type: text/markdown
|
|
@@ -9,10 +9,11 @@ License-File: LICENSE
|
|
|
9
9
|
Requires-Dist: httpx>=0.25.0
|
|
10
10
|
Provides-Extra: dev
|
|
11
11
|
Requires-Dist: pytest>=7.0; extra == "dev"
|
|
12
|
+
Dynamic: license-file
|
|
12
13
|
|
|
13
14
|
# dominusnode-dify
|
|
14
15
|
|
|
15
|
-
Dify tool provider for the [
|
|
16
|
+
Dify tool provider for the [Dominus Node](https://dominusnode.com) rotating proxy-as-a-service platform. Provides 22 tools for proxy management, wallet operations, team administration, and payment processing.
|
|
16
17
|
|
|
17
18
|
## Installation
|
|
18
19
|
|
|
@@ -4,8 +4,8 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "dominusnode-dify"
|
|
7
|
-
version = "1.
|
|
8
|
-
description = "
|
|
7
|
+
version = "1.1.0"
|
|
8
|
+
description = "Dominus Node tool provider for Dify -- 22 proxy, wallet, and team management tools"
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
license = {text = "MIT"}
|
|
11
11
|
requires-python = ">=3.10"
|
|
@@ -453,7 +453,7 @@ class TestProviderInit:
|
|
|
453
453
|
|
|
454
454
|
def test_get_tools_returns_24(self):
|
|
455
455
|
tools = DominusNodeProvider.get_tools()
|
|
456
|
-
assert len(tools) ==
|
|
456
|
+
assert len(tools) == 26
|
|
457
457
|
assert "proxied_fetch" in tools
|
|
458
458
|
assert "check_balance" in tools
|
|
459
459
|
assert "topup_paypal" in tools
|
|
File without changes
|
|
File without changes
|
{dominusnode_dify-1.0.0 → dominusnode_dify-1.1.0}/dominusnode_dify.egg-info/dependency_links.txt
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|