mirror of
https://github.com/yogeshojha/rengine.git
synced 2026-10-20 07:11:28 +02:00
Out-of-band testing is an instance setting — `off`, `self_hosted` or `public` — with the server, the token (the INTERACTSH API key row) and the wait resolved once in `shared/services/oast.py` and read on the stage thread. A mode that cannot be used is off and says why: self-hosted with no server, or public without the disclosure acknowledged. A fresh instance is off. `POST /oast/test` asks a public address for `/poll` over HTTPS and reports that the server answered, never that OAST works. The engine keeps one switch. `FieldNeeds` puts the resource key on the field and `GET /engines/catalog` fills `unavailable_reason`, so the builder renders the instance reason beside a switch that stays settable. Measured on nuclei v3.11.1: with `-no-interactsh` a check that needs a callback still loads and the request is refused — 0 requests, exit 0. So the batch reported COMPLETED and every origin in it read `scanned` for checks that never touched the target. The selection now drops them when nothing is listening, one coverage row reports the count and the reason, and `Tier.OAST` is left out of the planned tiers. Membership is what a check references, not what it is tagged: 615 of the 12,586 official rows reference an interactsh placeholder and 233 of those carry no `oast` tag. `vuln_templates.needs_oast` is parsed at index time; a library resync fills the column. The wait is paid on out-of-band batches alone, which sweep for 30 minutes so it is paid fewer times, and the tier names the server on its own rows. A finding's callback is rendered on the sheet from one label map; the list path is bared to the metadata. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
50 lines
1.2 KiB
Python
50 lines
1.2 KiB
Python
"""Out-of-band settings as the API reads and writes them."""
|
|
|
|
from __future__ import annotations
|
|
|
|
from datetime import datetime
|
|
|
|
from pydantic import BaseModel, ConfigDict
|
|
from pydantic import Field as PydanticField
|
|
|
|
from shared.definitions.oast import (
|
|
MAX_SERVER_LENGTH,
|
|
MAX_WAIT_SECONDS,
|
|
MIN_WAIT_SECONDS,
|
|
OastMode,
|
|
)
|
|
|
|
|
|
class OastRead(BaseModel):
|
|
mode: str = OastMode.OFF.value
|
|
server: str | None = None
|
|
wait_seconds: int = 0
|
|
public_acknowledged: bool = False
|
|
token_set: bool = False
|
|
public_servers: list[str] = PydanticField(default_factory=list)
|
|
checks: int = 0
|
|
reason: str | None = None
|
|
last_interaction_at: datetime | None = None
|
|
interactions: int = 0
|
|
|
|
|
|
class OastUpdate(BaseModel):
|
|
model_config = ConfigDict(extra="forbid")
|
|
|
|
mode: OastMode | None = None
|
|
server: str | None = PydanticField(default=None, max_length=MAX_SERVER_LENGTH)
|
|
wait_seconds: int | None = PydanticField(
|
|
default=None, ge=MIN_WAIT_SECONDS, le=MAX_WAIT_SECONDS
|
|
)
|
|
public_acknowledged: bool | None = None
|
|
|
|
|
|
class OastTest(BaseModel):
|
|
ok: bool = False
|
|
detail: str = ""
|
|
address: str | None = None
|
|
status_code: int | None = None
|
|
|
|
|
|
__all__ = ["OastRead", "OastTest", "OastUpdate"]
|