Source code for octopoes.models.ooi.web
from enum import Enum
from typing import Literal
from pydantic import AnyUrl
from octopoes.models import OOI, PrimaryKeyToken, Reference
from octopoes.models.ooi.certificate import X509Certificate
from octopoes.models.ooi.dns.zone import Hostname
from octopoes.models.ooi.network import IPAddress, Network
from octopoes.models.ooi.service import IPService
from octopoes.models.persistence import ReferenceField
def format_web_url_token(token: PrimaryKeyToken) -> str:
port = f":{token.port}" if token.port else ""
try:
netloc = token.netloc.address
except KeyError:
netloc = token.netloc.name
return f"{token.scheme}://{netloc}{port}{token.path}"
[docs]
class Website(OOI):
object_type: Literal["Website"] = "Website"
ip_service: Reference = ReferenceField(IPService, max_issue_scan_level=0, max_inherit_scan_level=4)
hostname: Reference = ReferenceField(Hostname, max_inherit_scan_level=4)
certificate: Reference | None = ReferenceField(X509Certificate, default=None, max_issue_scan_level=1)
_natural_key_attrs = ["ip_service", "hostname"]
_reverse_relation_names = {"ip_service": "websites", "hostname": "websites"}
[docs]
@classmethod
def format_reference_human_readable(cls, reference: Reference) -> str:
t = reference.tokenized
service = t.ip_service.service.name
address = t.ip_service.ip_port.address.address
port = t.ip_service.ip_port.port
return f"{service}://{t.hostname.name}:{port} @ {address}"
[docs]
class WebURL(OOI):
network: Reference = ReferenceField(Network)
scheme: WebScheme
port: int
path: str
[docs]
class HostnameHTTPURL(WebURL):
object_type: Literal["HostnameHTTPURL"] = "HostnameHTTPURL"
netloc: Reference = ReferenceField(Hostname, max_issue_scan_level=2, max_inherit_scan_level=4)
_natural_key_attrs = ["scheme", "netloc", "port", "path"]
_reverse_relation_names = {"netloc": "urls"}
[docs]
@classmethod
def format_reference_human_readable(cls, reference: Reference) -> str:
tokenized = reference.tokenized
port = f":{tokenized.port}" if tokenized.port else ""
return f"{tokenized.scheme}://{tokenized.netloc.name}{port}{tokenized.path}"
[docs]
class IPAddressHTTPURL(WebURL):
object_type: Literal["IPAddressHTTPURL"] = "IPAddressHTTPURL"
netloc: Reference = ReferenceField(IPAddress, max_issue_scan_level=1, max_inherit_scan_level=4)
_natural_key_attrs = ["scheme", "netloc", "port", "path"]
_reverse_relation_names = {"netloc": "urls"}
[docs]
@classmethod
def format_reference_human_readable(cls, reference: Reference) -> str:
tokenized = reference.tokenized
port = f":{tokenized.port}" if tokenized.port else ""
return f"{tokenized.scheme}://{tokenized.netloc.address}{port}{tokenized.path}"
[docs]
class HTTPResource(OOI):
object_type: Literal["HTTPResource"] = "HTTPResource"
website: Reference = ReferenceField(Website, max_issue_scan_level=0, max_inherit_scan_level=4)
web_url: Reference = ReferenceField(WebURL, max_issue_scan_level=1, max_inherit_scan_level=4)
redirects_to: Reference | None = ReferenceField(WebURL, default=None)
_natural_key_attrs = ["website", "web_url"]
_reverse_relation_names = {"website": "resources", "web_url": "resources"}
[docs]
@classmethod
def format_reference_human_readable(cls, reference: Reference) -> str:
t = reference.tokenized
port = f":{t.web_url.port}"
try:
netloc = t.web_url.netloc.address
except KeyError:
netloc = t.web_url.netloc.name
web_url = f"{t.web_url.scheme}://{netloc}{port}{t.web_url.path}"
address = t.website.ip_service.ip_port.address.address
return f"{web_url} @ {address}"
[docs]
class HTTPHeader(OOI):
object_type: Literal["HTTPHeader"] = "HTTPHeader"
resource: Reference = ReferenceField(HTTPResource, max_issue_scan_level=0, max_inherit_scan_level=4)
key: str
value: str
_natural_key_attrs = ["resource", "key"]
_information_value = ["key"]
_reverse_relation_names = {"url": "http_headers"}
[docs]
@classmethod
def format_reference_human_readable(cls, reference: Reference) -> str:
t = reference.tokenized
port = f":{t.resource.web_url.port}" if t.resource.web_url.port else ""
try:
netloc = t.resource.web_url.netloc.address
except KeyError:
netloc = t.resource.web_url.netloc.name
web_url = f"{t.resource.web_url.scheme}://{netloc}{port}{t.resource.web_url.path}"
address = t.resource.website.ip_service.ip_port.address.address
return f"{reference.tokenized.key} @ {web_url} @ {address}"
[docs]
class URL(OOI):
object_type: Literal["URL"] = "URL"
network: Reference = ReferenceField(Network)
raw: AnyUrl
web_url: Reference | None = ReferenceField(WebURL, max_issue_scan_level=2, default=None)
_natural_key_attrs = ["network", "raw"]
_reverse_relation_names = {"network": "urls"}
[docs]
@classmethod
def format_reference_human_readable(cls, reference: Reference) -> str:
return f"{reference.tokenized.raw} @{reference.tokenized.network.name}"
[docs]
class HTTPHeaderURL(OOI):
object_type: Literal["HTTPHeaderURL"] = "HTTPHeaderURL"
header: Reference = ReferenceField(HTTPHeader, max_issue_scan_level=0, max_inherit_scan_level=1)
url: Reference = ReferenceField(URL, max_issue_scan_level=1, max_inherit_scan_level=0)
_natural_key_attrs = ["header", "url"]
_reverse_relation_names = {"header": "urls", "url": "headers_containing_url"}
[docs]
@classmethod
def format_reference_human_readable(cls, reference: Reference) -> str:
t = reference.tokenized.header
port = f":{t.resource.web_url.port}" if t.resource.web_url.port else ""
try:
netloc = t.resource.web_url.netloc.address
except KeyError:
netloc = t.resource.web_url.netloc.name
web_url = f"{t.resource.web_url.scheme}://{netloc}{port}{t.resource.web_url.path}"
address = t.resource.website.ip_service.ip_port.address.address
return f"{t.key} @ {web_url} @ {address} contains {str(reference.tokenized.url.raw)}"
[docs]
class HTTPHeaderHostname(OOI):
object_type: Literal["HTTPHeaderHostname"] = "HTTPHeaderHostname"
header: Reference = ReferenceField(HTTPHeader, max_issue_scan_level=0, max_inherit_scan_level=1)
hostname: Reference = ReferenceField(Hostname, max_issue_scan_level=1, max_inherit_scan_level=0)
_natural_key_attrs = ["header", "hostname"]
_reverse_relation_names = {"header": "hostnames", "hostname": "headers_containing_hostname"}
[docs]
@classmethod
def format_reference_human_readable(cls, reference: Reference) -> str:
t = reference.tokenized.header
port = f":{t.resource.web_url.port}" if t.resource.web_url.port else ""
try:
netloc = t.resource.web_url.netloc.address
except KeyError:
netloc = t.resource.web_url.netloc.name
web_url = f"{t.resource.web_url.scheme}://{netloc}{port}{t.resource.web_url.path}"
address = t.resource.website.ip_service.ip_port.address.address
return f"{t.key} @ {web_url} @ {address} contains {str(reference.tokenized.hostname.name)}"
[docs]
class ImageMetadata(OOI):
object_type: Literal["ImageMetadata"] = "ImageMetadata"
resource: Reference = ReferenceField(HTTPResource, max_issue_scan_level=0, max_inherit_scan_level=4)
image_info: dict
_natural_key_attrs = ["resource"]
_reverse_relation_names = {"resource": "ImageMetaData"}
[docs]
@classmethod
def format_reference_human_readable(cls, reference: Reference) -> str:
try:
t = reference.tokenized
port = f":{t.resource.web_url.port}" if t.resource.web_url.port else ""
try:
netloc = t.resource.web_url.netloc.address
except KeyError:
netloc = t.resource.web_url.netloc.name
web_url = f"{t.resource.web_url.scheme}://{netloc}{port}{t.resource.web_url.path}"
address = t.resource.website.ip_service.ip_port.address.address
return f"{web_url} @ {address}"
except IndexError:
# try parsing reference as a HostnameHTTPURL instead
tokenized = HostnameHTTPURL.get_tokenized_primary_key(reference.natural_key)
port = f":{tokenized.port}" if tokenized.port else ""
return f"{tokenized.scheme}://{tokenized.netloc.name}{port}{tokenized.path}"
[docs]
class RESTAPI(OOI):
object_type: Literal["RESTAPI"] = "RESTAPI"
api_url: Reference = ReferenceField(WebURL)
_natural_key_attrs = ["api_url"]
_reverse_relation_names = {"api_url": "api_url_of"}
[docs]
@classmethod
def format_reference_human_readable(cls, reference: Reference) -> str:
return format_web_url_token(reference.tokenized.api_url)
[docs]
class APIDesignRule(OOI):
object_type: Literal["APIDesignRule"] = "APIDesignRule"
name: str
_natural_key_attrs = ["name"]
_reverse_relation_names = {}
_traversable = False
[docs]
@classmethod
def format_reference_human_readable(cls, reference: Reference) -> str:
return reference.tokenized.name
[docs]
class APIDesignRuleResult(OOI):
object_type: Literal["APIDesignRuleResult"] = "APIDesignRuleResult"
rest_api: Reference = ReferenceField(RESTAPI)
rule: Reference = ReferenceField(APIDesignRule)
passed: bool
message: str
_natural_key_attrs = ["rest_api", "rule"]
_reverse_relation_names = {"rest_api": "api_design_rule_results", "rule": "results"}
[docs]
@classmethod
def format_reference_human_readable(cls, reference: Reference) -> str:
t = reference.tokenized
rule = t.rule.name
api_url = format_web_url_token(t.rest_api.api_url)
return f"{rule} @ {api_url}"
[docs]
class SecurityTXT(OOI):
object_type: Literal["SecurityTXT"] = "SecurityTXT"
website: Reference = ReferenceField("Website", max_issue_scan_level=0, max_inherit_scan_level=4)
url: Reference = ReferenceField("URL", max_issue_scan_level=0, max_inherit_scan_level=4)
redirects_to: Reference | None = ReferenceField(
"SecurityTXT", max_issue_scan_level=2, max_inherit_scan_level=0, default=None
)
security_txt: str | None = None
_natural_key_attrs = ["website", "url"]
_reverse_relation_names = {
"website": "security_txt_of",
"url": "security_txt",
"redirects_to": "is_being_redirected_to_by",
}