feat: adds onions list to api
This commit is contained in:
parent
2ca4ddffb0
commit
04f5a0345b
2 changed files with 65 additions and 6 deletions
|
@ -2,7 +2,7 @@ import base64
|
||||||
import binascii
|
import binascii
|
||||||
import logging
|
import logging
|
||||||
import re
|
import re
|
||||||
from typing import Optional, List, Callable, Any, Type, Dict, Union
|
from typing import Optional, List, Callable, Any, Type, Dict, Union, Literal
|
||||||
|
|
||||||
from flask import Blueprint, request, jsonify, abort
|
from flask import Blueprint, request, jsonify, abort
|
||||||
from flask.typing import ResponseReturnValue
|
from flask.typing import ResponseReturnValue
|
||||||
|
@ -12,6 +12,7 @@ from werkzeug.exceptions import HTTPException
|
||||||
from app.extensions import db
|
from app.extensions import db
|
||||||
from app.models.base import Group
|
from app.models.base import Group
|
||||||
from app.models.mirrors import Origin, Proxy
|
from app.models.mirrors import Origin, Proxy
|
||||||
|
from app.models.onions import Onion
|
||||||
|
|
||||||
api = Blueprint('api', __name__)
|
api = Blueprint('api', __name__)
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
@ -70,6 +71,16 @@ def validate_marker(marker_str: str) -> int:
|
||||||
abort(400, description="Marker must be a valid token.")
|
abort(400, description="Marker must be a valid token.")
|
||||||
|
|
||||||
|
|
||||||
|
TLPMarkings = Union[
|
||||||
|
Literal["default"],
|
||||||
|
Literal["clear"],
|
||||||
|
Literal["green"],
|
||||||
|
Literal["amber"],
|
||||||
|
Literal["amber+strict"],
|
||||||
|
Literal["red"],
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
def list_resources(
|
def list_resources(
|
||||||
model: Type[Any],
|
model: Type[Any],
|
||||||
serialize_func: Callable[[Any], Dict[str, Any]],
|
serialize_func: Callable[[Any], Dict[str, Any]],
|
||||||
|
@ -78,7 +89,8 @@ def list_resources(
|
||||||
resource_name: str = 'ResourceList',
|
resource_name: str = 'ResourceList',
|
||||||
max_items_param: str = 'MaxItems',
|
max_items_param: str = 'MaxItems',
|
||||||
marker_param: str = 'Marker',
|
marker_param: str = 'Marker',
|
||||||
max_allowed_items: int = 100
|
max_allowed_items: int = 100,
|
||||||
|
protective_marking: TLPMarkings = 'default',
|
||||||
) -> ResponseReturnValue:
|
) -> ResponseReturnValue:
|
||||||
try:
|
try:
|
||||||
marker = request.args.get(marker_param)
|
marker = request.args.get(marker_param)
|
||||||
|
@ -108,6 +120,7 @@ def list_resources(
|
||||||
"Quantity": len(items_list),
|
"Quantity": len(items_list),
|
||||||
"Items": items_list,
|
"Items": items_list,
|
||||||
"IsTruncated": is_truncated,
|
"IsTruncated": is_truncated,
|
||||||
|
"ProtectiveMarking": protective_marking,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -128,7 +141,8 @@ def list_groups() -> ResponseReturnValue:
|
||||||
model=Group,
|
model=Group,
|
||||||
serialize_func=lambda group: group.to_dict(),
|
serialize_func=lambda group: group.to_dict(),
|
||||||
resource_name='OriginGroupList',
|
resource_name='OriginGroupList',
|
||||||
max_allowed_items=MAX_ALLOWED_ITEMS
|
max_allowed_items=MAX_ALLOWED_ITEMS,
|
||||||
|
protective_marking='amber',
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@ -157,7 +171,8 @@ def list_origins() -> ResponseReturnValue:
|
||||||
serialize_func=lambda origin: origin.to_dict(),
|
serialize_func=lambda origin: origin.to_dict(),
|
||||||
filters=filters,
|
filters=filters,
|
||||||
resource_name='OriginsList',
|
resource_name='OriginsList',
|
||||||
max_allowed_items=MAX_ALLOWED_ITEMS
|
max_allowed_items=MAX_ALLOWED_ITEMS,
|
||||||
|
protective_marking='amber',
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@ -187,5 +202,36 @@ def list_mirrors() -> ResponseReturnValue:
|
||||||
serialize_func=lambda proxy: proxy.to_dict(),
|
serialize_func=lambda proxy: proxy.to_dict(),
|
||||||
filters=filters,
|
filters=filters,
|
||||||
resource_name='MirrorsList',
|
resource_name='MirrorsList',
|
||||||
max_allowed_items=MAX_ALLOWED_ITEMS
|
max_allowed_items=MAX_ALLOWED_ITEMS,
|
||||||
|
protective_marking='amber',
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@api.route('/web/onion', methods=['GET'])
|
||||||
|
def list_onions() -> ResponseReturnValue:
|
||||||
|
domain_name_filter = request.args.get('DomainName')
|
||||||
|
group_id_filter = request.args.get('GroupId')
|
||||||
|
|
||||||
|
filters: List[ListFilter] = []
|
||||||
|
|
||||||
|
if domain_name_filter:
|
||||||
|
if len(domain_name_filter) > MAX_DOMAIN_NAME_LENGTH:
|
||||||
|
abort(400, description=f"DomainName cannot exceed {MAX_DOMAIN_NAME_LENGTH} characters.")
|
||||||
|
if not DOMAIN_NAME_REGEX.match(domain_name_filter):
|
||||||
|
abort(400, description="DomainName contains invalid characters.")
|
||||||
|
filters.append(Onion.domain_name.ilike(f"%{domain_name_filter}%"))
|
||||||
|
|
||||||
|
if group_id_filter:
|
||||||
|
try:
|
||||||
|
filters.append(Onion.group_id == int(group_id_filter))
|
||||||
|
except ValueError:
|
||||||
|
abort(400, description="GroupId must be a valid integer.")
|
||||||
|
|
||||||
|
return list_resources(
|
||||||
|
model=Onion,
|
||||||
|
serialize_func=lambda onion: onion.to_dict(),
|
||||||
|
filters=filters,
|
||||||
|
resource_name='OnionsList',
|
||||||
|
max_allowed_items=MAX_ALLOWED_ITEMS,
|
||||||
|
protective_marking='amber',
|
||||||
)
|
)
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import base64
|
import base64
|
||||||
import hashlib
|
import hashlib
|
||||||
from typing import Optional
|
from typing import Optional, TypedDict
|
||||||
|
|
||||||
from sqlalchemy.orm import Mapped, mapped_column, relationship
|
from sqlalchemy.orm import Mapped, mapped_column, relationship
|
||||||
|
|
||||||
|
@ -10,6 +10,12 @@ from app.models import AbstractConfiguration, AbstractResource
|
||||||
from app.models.base import Group
|
from app.models.base import Group
|
||||||
|
|
||||||
|
|
||||||
|
class OnionDict(TypedDict):
|
||||||
|
Id: int
|
||||||
|
DomainName: str
|
||||||
|
OnionName: str
|
||||||
|
|
||||||
|
|
||||||
class Onion(AbstractConfiguration):
|
class Onion(AbstractConfiguration):
|
||||||
@property
|
@property
|
||||||
def brn(self) -> BRN:
|
def brn(self) -> BRN:
|
||||||
|
@ -49,6 +55,13 @@ class Onion(AbstractConfiguration):
|
||||||
onion = base64.b32encode(result).decode("utf-8").strip("=")
|
onion = base64.b32encode(result).decode("utf-8").strip("=")
|
||||||
return onion.lower()
|
return onion.lower()
|
||||||
|
|
||||||
|
def to_dict(self) -> OnionDict:
|
||||||
|
return {
|
||||||
|
"Id": self.id,
|
||||||
|
"DomainName": self.domain_name,
|
||||||
|
"OnionName": self.onion_name,
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
class Eotk(AbstractResource):
|
class Eotk(AbstractResource):
|
||||||
group_id: Mapped[int] = mapped_column(db.Integer(), db.ForeignKey("group.id"))
|
group_id: Mapped[int] = mapped_column(db.Integer(), db.ForeignKey("group.id"))
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue