mirror of
https://github.com/yogeshojha/rengine.git
synced 2026-10-20 07:11:28 +02:00
A third transport over the MCP tool layer, beside HTTP and stdio. The `channels` compose service long-polls the Bot API, so an instance needs no public URL, certificate or open port; the listener runs on the api image because MCP tools lazy-import app.services. Commands are curated at the tool: a tool joins chat by declaring one short `command` (/scan, /add, /vulns, /progress); no command means MCP-only. Twenty-three commands in five groups, pinned by a test, with replies rendered through ToolResult.blocks instead of the data dump. An unknown chat gets a device code approved under Toolkit, Remote control; anything above read is confirmed with the account's own authenticator and capped at read when none is enrolled. The bot token is the Telegram API key, shared with notifications. Replies are text plus entities with UTF-16 offsets, never parse_mode, so target-written text is literal by construction. Also fixes Dimension.search passing scan_id= to a service that takes scope, and gives query_assets an optional target for project-wide search. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01VckaDx6mBB4TsG76u61gvv
135 lines
4.3 KiB
Python
135 lines
4.3 KiB
Python
import uuid
|
|
from datetime import datetime
|
|
|
|
from pydantic import BaseModel
|
|
from sqlalchemy import Column
|
|
from sqlalchemy.types import JSON
|
|
from sqlmodel import Field, SQLModel, UniqueConstraint
|
|
|
|
from shared.enums.api_key import APIProvider
|
|
from shared.utils.datetime import utc_now
|
|
|
|
API_PROVIDER_META: dict[str, dict] = {
|
|
APIProvider.VIEWDNS: {
|
|
"name": "ViewDNS.info",
|
|
"description": "DNS intelligence, reverse lookups and DNS history",
|
|
"docs_url": "https://viewdns.info/api/?src=reNgine",
|
|
"requires_username": False,
|
|
"icon": "scan-search",
|
|
},
|
|
APIProvider.GITHUB: {
|
|
"name": "GitHub",
|
|
"description": "Subdomains found in public code, and subfinder's GitHub source",
|
|
"docs_url": "https://github.com/settings/tokens",
|
|
"requires_username": False,
|
|
"icon": "github",
|
|
},
|
|
APIProvider.CHAOS: {
|
|
"name": "Chaos",
|
|
"description": "ProjectDiscovery Chaos subdomain dataset",
|
|
"docs_url": "https://cloud.projectdiscovery.io",
|
|
"requires_username": False,
|
|
"icon": "radar",
|
|
},
|
|
APIProvider.NETLAS: {
|
|
"name": "Netlas",
|
|
"description": "Internet-wide asset and attack-surface intelligence",
|
|
"docs_url": "https://netlas.io",
|
|
"requires_username": False,
|
|
"icon": "globe",
|
|
},
|
|
APIProvider.SECURITYTRAILS: {
|
|
"name": "SecurityTrails",
|
|
"description": "DNS, domain and subdomain history intelligence",
|
|
"docs_url": "https://securitytrails.com",
|
|
"requires_username": False,
|
|
"icon": "route",
|
|
},
|
|
APIProvider.HACKERONE: {
|
|
"name": "HackerOne",
|
|
"description": "Program scope and reports from HackerOne",
|
|
"docs_url": "https://api.hackerone.com",
|
|
"requires_username": True,
|
|
"icon": "shield",
|
|
},
|
|
APIProvider.INTIGRITI: {
|
|
"name": "Intigriti",
|
|
"description": "Program scope from Intigriti, including invite-only programs",
|
|
"docs_url": "https://app.intigriti.com/researcher/personal-access-tokens",
|
|
"requires_username": False,
|
|
"icon": "shield",
|
|
},
|
|
APIProvider.VULNX: {
|
|
"name": "vulnx",
|
|
"description": "ProjectDiscovery vulnerability intelligence: exploits, coverage and exposure",
|
|
"docs_url": "https://cloud.projectdiscovery.io",
|
|
"requires_username": False,
|
|
"icon": "biohazard",
|
|
},
|
|
APIProvider.INTERACTSH: {
|
|
"name": "Interactsh",
|
|
"description": "Auth token for a self-hosted out-of-band callback server",
|
|
"docs_url": "https://github.com/projectdiscovery/interactsh",
|
|
"requires_username": False,
|
|
"icon": "satellite-dish",
|
|
},
|
|
APIProvider.TELEGRAM: {
|
|
"name": "Telegram",
|
|
"description": "Bot token for remote control and notifications",
|
|
"docs_url": "https://core.telegram.org/bots#how-do-i-create-a-bot",
|
|
"requires_username": False,
|
|
"icon": "send",
|
|
},
|
|
}
|
|
|
|
|
|
class APIKey(SQLModel, table=True):
|
|
__tablename__ = "api_keys"
|
|
__table_args__ = (UniqueConstraint("provider", name="uq_api_key_provider"),)
|
|
|
|
id: uuid.UUID = Field(default_factory=uuid.uuid4, primary_key=True)
|
|
provider: APIProvider = Field(index=True)
|
|
key_value: str = Field(max_length=1000)
|
|
key_meta: dict | None = Field(default=None, sa_column=Column(JSON, nullable=True))
|
|
is_enabled: bool = Field(default=True)
|
|
usage_counter: int = Field(default=0)
|
|
last_used_at: datetime | None = Field(default=None)
|
|
created_at: datetime = Field(default_factory=utc_now)
|
|
updated_at: datetime = Field(default_factory=utc_now)
|
|
|
|
|
|
class APIKeyCreate(BaseModel):
|
|
provider: APIProvider
|
|
key_value: str
|
|
key_meta: dict | None = None
|
|
|
|
|
|
class APIKeyUpdate(BaseModel):
|
|
key_value: str | None = None
|
|
is_enabled: bool | None = None
|
|
key_meta: dict | None = None
|
|
|
|
|
|
class APIKeyRead(BaseModel):
|
|
id: uuid.UUID
|
|
provider: APIProvider
|
|
key_value_masked: str
|
|
key_meta: dict | None = None
|
|
is_enabled: bool
|
|
usage_counter: int
|
|
last_used_at: datetime | None
|
|
created_at: datetime
|
|
updated_at: datetime
|
|
meta: dict
|
|
|
|
|
|
class ProviderInfo(BaseModel):
|
|
provider: APIProvider
|
|
name: str
|
|
description: str
|
|
docs_url: str
|
|
icon: str = "package"
|
|
requires_username: bool = False
|
|
configured: bool = False
|
|
is_enabled: bool = False
|