diff --git a/lnbits/core/crud/audit.py b/lnbits/core/crud/audit.py index 4131ea69e..38bdccb50 100644 --- a/lnbits/core/crud/audit.py +++ b/lnbits/core/crud/audit.py @@ -1,8 +1,8 @@ from typing import Optional from lnbits.core.db import db -from lnbits.core.models import AuditEntry -from lnbits.db import Connection +from lnbits.core.models import AuditEntry, AuditFilters +from lnbits.db import Connection, Filters, Page async def create_audit_entry( @@ -10,3 +10,16 @@ async def create_audit_entry( conn: Optional[Connection] = None, ) -> None: await (conn or db).insert("audit", entry) + + +async def get_audit_entries( + filters: Optional[Filters[AuditFilters]] = None, + conn: Optional[Connection] = None, +) -> Page[AuditEntry]: + return await (conn or db).fetch_page( + "SELECT * from audit", + [], + {}, + filters=filters, + model=AuditEntry, + ) diff --git a/lnbits/core/models/__init__.py b/lnbits/core/models/__init__.py index d5ffe7282..4b33064a8 100644 --- a/lnbits/core/models/__init__.py +++ b/lnbits/core/models/__init__.py @@ -1,4 +1,4 @@ -from .audit import AuditEntry +from .audit import AuditEntry, AuditFilters from .lnurl import CreateLnurl, CreateLnurlAuth, PayLnurlWData from .misc import ( BalanceDelta, @@ -44,6 +44,7 @@ from .webpush import CreateWebPushSubscription, WebPushSubscription __all__ = [ # audit "AuditEntry", + "AuditFilters", # lnurl "CreateLnurl", "CreateLnurlAuth", diff --git a/lnbits/core/models/audit.py b/lnbits/core/models/audit.py index 7b438512f..25422fbc1 100644 --- a/lnbits/core/models/audit.py +++ b/lnbits/core/models/audit.py @@ -5,6 +5,7 @@ from typing import Optional from pydantic import BaseModel, Field +from lnbits.db import FilterModel from lnbits.settings import settings @@ -23,8 +24,27 @@ class AuditEntry(BaseModel): created_at: datetime = Field(default_factory=lambda: datetime.now(timezone.utc)) def __init__(self, **data): - super.__init__(**data) - if settings.lnbits_audit_retention_days > 0: - self.delete_at = self.created_at + timedelta( - days=settings.lnbits_audit_retention_days - ) + super().__init__(**data) + retention_days = max(0, settings.lnbits_audit_retention_days) or 365 + self.delete_at = self.created_at + timedelta(days=retention_days) + + +class AuditFilters(FilterModel): + __search_fields__ = [ + "ip_address", + "user_id", + "path", + "route_path", + "request_method", + "response_code", + ] + __sort_fields__ = [ + "duration", + ] + + ip_address: Optional[str] = None + user_id: Optional[str] = None + path: Optional[str] = None + route_path: Optional[str] = None + request_method: Optional[str] = None + response_code: Optional[str] = None diff --git a/lnbits/settings.py b/lnbits/settings.py index 6631558c8..37158226d 100644 --- a/lnbits/settings.py +++ b/lnbits/settings.py @@ -527,7 +527,9 @@ class AuditSettings(LNbitsSettings): # List of HTTP methods to be included. Empty lists means all. # Options (case-sensitive): GET, POST, PUT, PATCH, DELETE, HEAD, OPTIONS - lnbits_audit_http_methods: list[str] = Field(default=[]) + lnbits_audit_http_methods: list[str] = Field( + default=["POST", "PUT", "PATCH", "DELETE"] + ) # List of HTTP codes to be included (regex match). Empty lists means all. lnbits_audit_http_response_codes: list[str] = Field(default=[])