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.

@@ -1,7 +1,7 @@
1
- Metadata-Version: 2.1
1
+ Metadata-Version: 2.4
2
2
  Name: dominusnode-dify
3
- Version: 1.0.0
4
- Summary: DomiNode tool provider for Dify -- 22 proxy, wallet, and team management tools
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 [DomiNode](https://dominusnode.com) rotating proxy-as-a-service platform. Provides 22 tools for proxy management, wallet operations, team administration, and payment processing.
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 [DomiNode](https://dominusnode.com) rotating proxy-as-a-service platform. Provides 22 tools for proxy management, wallet operations, team administration, and payment processing.
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
- """DomiNode Dify integration -- 24 tools for the Dify AI platform.
1
+ """Dominus Node Dify integration -- 26 tools for the Dify AI platform.
2
2
 
3
- Provides a Dify-compatible tool provider that exposes 24 tools for
4
- interacting with the DomiNode rotating proxy-as-a-service platform.
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
- """DomiNode Dify tool provider -- 24 tools with full security hardening.
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
- DomiNode REST API, and returns a dict result.
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 DomiNode API key patterns from error messages."""
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 DomiNode rotating proxy service.
478
+ """Dify tool provider for Dominus Node rotating proxy service.
478
479
 
479
- Authenticates using a DomiNode API key and exposes 24 tool methods that
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 DomiNode API using the API key.
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
- "DomiNode API key is required. Set api_key in provider credentials "
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 DomiNode REST API.
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 DomiNode rotating proxy network.
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 DomiNode proxy gateway is running and accessible.",
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 22 tool names (plus topup_paypal = 23 entries).
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
1
+ Metadata-Version: 2.4
2
2
  Name: dominusnode-dify
3
- Version: 1.0.0
4
- Summary: DomiNode tool provider for Dify -- 22 proxy, wallet, and team management tools
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 [DomiNode](https://dominusnode.com) rotating proxy-as-a-service platform. Provides 22 tools for proxy management, wallet operations, team administration, and payment processing.
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.0.0"
8
- description = "DomiNode tool provider for Dify -- 22 proxy, wallet, and team management tools"
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) == 24
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