]> git.mxchange.org Git - fba.git/commitdiff
Continued:
authorRoland Häder <roland@mxchange.org>
Sat, 24 Jun 2023 10:21:22 +0000 (12:21 +0200)
committerRoland Häder <roland@mxchange.org>
Sat, 24 Jun 2023 10:27:08 +0000 (12:27 +0200)
- rewrote api.py's router functions in a more flexible way: mode,value,amount
- for now only a few modes are supported: domain, reverse, reason, block_level

api.py
fba/models/blocks.py
templates/rss.xml
templates/views/index.html
templates/views/scoreboard.html
templates/views/top.html
templates/widgets/links.tpl

diff --git a/api.py b/api.py
index c3c7990c4dcf6d4f54203414790789473e84888d..3e0e8251ff5ff473aca5295a47b2161352bbc3cf 100644 (file)
--- a/api.py
+++ b/api.py
@@ -36,6 +36,8 @@ from fba.helpers import tidyup
 
 from fba.http import network
 
+from fba.models import blocks
+
 router = fastapi.FastAPI(docs_url=config.get("base_url") + "/docs", redoc_url=config.get("base_url") + "/redoc")
 templates = Jinja2Templates(directory="templates")
 
@@ -93,33 +95,67 @@ def api_scoreboard(mode: str, amount: int):
     return scores
 
 @router.get(config.get("base_url") + "/api/index.json", response_class=JSONResponse)
-def api_blocked(domain: str = None, reason: str = None, reverse: str = None):
-    if domain is None and reason is None and reverse is None:
-        raise HTTPException(status_code=400, detail="No filter specified")
-
-    if reason is not None:
-        reason = re.sub("(%|_)", "", tidyup.reason(reason))
-        if len(reason) < 3:
-            raise HTTPException(status_code=400, detail="Keyword is shorter than three characters")
-
-    if domain is not None:
-        domain = tidyup.domain(domain)
-        if not validators.domain(domain.split("/")[0]):
-            raise HTTPException(status_code=500, detail="Invalid domain")
+def api_index(request: Request, mode: str, value: str, amount: int):
+    if mode is None or value is None or amount is None:
+        raise HTTPException(status_code=500, detail="No filter specified")
+    elif amount > 500:
+        raise HTTPException(status_code=500, detail=f"amount={amount} is to big")
+
+    domain = whildchar = punycode = reason = None
+
+    if mode == "block_level":
+        database.cursor.execute(
+            "SELECT blocker, blocked, block_level, reason, first_seen, last_seen FROM blocks WHERE block_level = ? LIMIT ?", [value, amount]
+        )
+    elif mode in ["domain", "reverse"]:
+        domain = tidyup.domain(value)
+        if not utils.is_domain_wanted(domain):
+            raise HTTPException(status_code=500, detail=f"domain='{domain}' is not wanted")
 
         wildchar = "*." + ".".join(domain.split(".")[-domain.count("."):])
         punycode = domain.encode('idna').decode('utf-8')
+    elif mode == "reason":
+        reason = re.sub("(%|_)", "", tidyup.reason(value))
+        if len(reason) < 3:
+            raise HTTPException(status_code=400, detail="Keyword is shorter than three characters")
 
-        database.cursor.execute("SELECT blocker, blocked, block_level, reason, first_seen, last_seen FROM blocks WHERE blocked = ? OR blocked = ? OR blocked = ? OR blocked = ? OR blocked = ? OR blocked = ? ORDER BY first_seen ASC",
-                  (domain, "*." + domain, wildchar, utils.get_hash(domain), punycode, "*." + punycode))
-    elif reverse is not None:
-        reverse = tidyup.domain(reverse)
-        if not validators.domain(reverse):
-            raise HTTPException(status_code=500, detail="Invalid domain")
-
-        database.cursor.execute("SELECT blocker, blocked, block_level, reason, first_seen, last_seen FROM blocks WHERE blocker = ? ORDER BY first_seen ASC", [reverse])
-    else:
-        database.cursor.execute("SELECT blocker, blocked, block_level, reason, first_seen, last_seen FROM blocks WHERE reason like ? AND reason != '' ORDER BY first_seen ASC", ["%" + reason + "%"])
+    if mode == "domain":
+        database.cursor.execute("SELECT blocker, blocked, block_level, reason, first_seen, last_seen \
+FROM blocks \
+WHERE blocked = ? OR blocked = ? OR blocked = ? OR blocked = ? OR blocked = ? OR blocked = ? ORDER BY first_seen ASC LIMIT ?",
+            [
+                domain,
+                "*." + domain,
+                wildchar,
+                utils.get_hash(domain),
+                punycode,
+                "*." + punycode,
+                amount
+            ]
+        )
+    elif mode == "reverse":
+        database.cursor.execute("SELECT blocker, blocked, block_level, reason, first_seen, last_seen \
+FROM blocks \
+WHERE blocker = ? OR blocker = ? OR blocker = ? OR blocker = ? OR blocker = ? OR blocker = ? \
+ORDER BY first_seen ASC \
+LIMIT ?", [
+            domain,
+            "*." + domain,
+            wildchar,
+            utils.get_hash(domain),
+            punycode,
+            "*." + punycode,
+            amount
+        ])
+    elif mode == "reason":
+        database.cursor.execute("SELECT blocker, blocked, block_level, reason, first_seen, last_seen \
+FROM blocks \
+WHERE reason LIKE ? AND reason != '' \
+ORDER BY first_seen ASC \
+LIMIT ?", [
+            "%" + reason + "%",
+            amount
+        ])
 
     blocklist = database.cursor.fetchall()
 
@@ -225,51 +261,42 @@ def index(request: Request):
     })
 
 @router.get(config.get("base_url") + "/top")
-def top(request: Request, domain: str = None, reason: str = None, reverse: str = None):
-    if domain == "" or reason == "" or reverse == "":
-        raise HTTPException(status_code=500, detail="Insufficient parameter provided")
-
+def top(request: Request, mode: str, value: str, amount: int = 500):
     response = requests.get(f"http://{config.get('host')}:{config.get('port')}{config.get('base_url')}/api/info.json")
 
     if not response.ok:
         raise HTTPException(status_code=response.status_code, detail=response.text)
+    elif mode == "" or value == "" or amount == 0:
+        raise HTTPException(status_code=500, detail="Parameter mode, value and amount must always be set")
+    elif amount > 500:
+        raise HTTPException(status_code=500, detail=f"amount='{amount}' is to big")
 
     info = response.json()
     response = None
+    blocklist = list()
 
-    if domain is not None:
-        domain = tidyup.domain(domain)
-        if not validators.domain(domain.split("/")[0]):
-            raise HTTPException(status_code=500, detail="Invalid domain")
+    if mode == "block_level" and not blocks.is_valid_level(value):
+        raise HTTPException(status_code=500, detail="Invalid block level provided")
+    elif mode in ["domain", "reverse"] and not utils.is_domain_wanted(value):
+        raise HTTPException(status_code=500, detail="Invalid or blocked domain specified")
 
-        response = requests.get(f"http://{config.get('host')}:{config.get('port')}{config.get('base_url')}/api/index.json?domain={domain}")
-    elif reason is not None:
-        response = requests.get(f"http://{config.get('host')}:{config.get('port')}{config.get('base_url')}/api/index.json?reason={reason}")
-    elif reverse is not None:
-        reverse = tidyup.domain(reverse)
-        if not validators.domain(reverse):
-            raise HTTPException(status_code=500, detail="Invalid domain")
-
-        response = requests.get(f"http://{config.get('host')}:{config.get('port')}{config.get('base_url')}/api/index.json?reverse={reverse}")
+    response = requests.get(f"http://{config.get('host')}:{config.get('port')}{config.get('base_url')}/api/index.json?mode={mode}&value={value}&amount={amount}")
 
     if response is not None:
-        if not response.ok:
-            raise HTTPException(status_code=response.status_code, detail=response.text)
-
         blocklist = response.json()
 
-        for block_level in blocklist:
-            for block in blocklist[block_level]:
-                block["first_seen"] = datetime.utcfromtimestamp(block["first_seen"]).strftime(config.get("timestamp_format"))
-                block["last_seen"]  = datetime.utcfromtimestamp(block["last_seen"]).strftime(config.get("timestamp_format"))
+    for block_level in blocklist:
+        for block in blocklist[block_level]:
+            block["first_seen"] = datetime.utcfromtimestamp(block["first_seen"]).strftime(config.get("timestamp_format"))
+            block["last_seen"]  = datetime.utcfromtimestamp(block["last_seen"]).strftime(config.get("timestamp_format"))
 
     return templates.TemplateResponse("views/top.html", {
         "request": request,
-        "domain" : domain,
+        "mode"   : mode if response is not None else None,
+        "value"  : value if response is not None else None,
+        "amount" : amount if response is not None else None,
         "blocks" : blocklist,
-        "reason" : reason,
-        "reverse": reverse,
-        "info"   : info
+        "info"   : info,
     })
 
 @router.get(config.get("base_url") + "/rss")
index d568d5b766d4457b9838041c499e9b7da19ef290..2f66445fb322427b63e1f8190fbefd70427d3fd2 100644 (file)
@@ -164,3 +164,20 @@ def add_instance(blocker: str, blocked: str, reason: str, block_level: str):
         ])
 
     logger.debug("EXIT!")
+
+def is_valid_level(block_level: str) -> bool:
+    logger.debug("block_level='%s' - CALLED!", block_level)
+    if not isinstance(block_level, str):
+        raise ValueError(f"Parameter block_level[]='{type(block_level)}' is not of type 'str'")
+    elif block_level == "":
+        raise ValueError("Parameter 'block_level' is empty")
+
+    # Query database
+    database.cursor.execute(
+        "SELECT block_level FROM blocks WHERE block_level = ? LIMIT 1", [block_level]
+    )
+
+    valid = database.cursor.fetchone() is not None
+
+    logger.debug("valid='%s' - EXIT!", valid)
+    return valid
index f254a8cee7390bc3d92bd55504d90c7ae38c784c..5d2c06db2deff7ffdf6fec6ef51fe0e852e74b6a 100644 (file)
@@ -9,7 +9,7 @@
  <item>
   <title>{{block['blocker']}} has applied '{{block['block_level']}}' restriction to {{block['blocked']}}</title>
   <description>{{block['reason']}}</description>
-  <link>https://{{hostname}}/top?reverse={{block['blocker']}}</link>
+  <link>https://{{hostname}}/top?mode=reverse&amp;domain={{block['blocker']}}</link>
   <pubDate>{{block['first_seen']}}</pubDate>
  </item>
  {% endfor %}
index 79a0cd40553a369d59c4f90aedc71acd79b23649..5d0609f9f8a1a8bfd09a368f68785131ad3551da 100644 (file)
@@ -7,19 +7,22 @@
 {% block content %}
     <h2>Enter a Domain</h2>
     <form action="top">
-        <input type="text" name="domain" placeholder="example.com" required="required" />
+        <input type="hidden" name="mode" value="domain" />
+        <input type="text" name="value" placeholder="example.com" required="required" />
         <input type="submit" value="Submit" />
     </form>
 
     <h2>Enter a Reason</h2>
     <form action="top">
-        <input type="text" name="reason" placeholder="free speech" required="required" />
+        <input type="hidden" name="mode" value="reason" />
+        <input type="text" name="value" placeholder="free speech" required="required" />
         <input type="submit" value="Submit" />
     </form>
 
     <h2>Reverse search</h2>
     <form action="top">
-        <input type="text" name="reverse" placeholder="example.com" required="required" />
+        <input type="hidden" name="mode" value="reverse" />
+        <input type="text" name="value" placeholder="example.com" required="required" />
         <input type="submit" value="Submit" />
     </form>
 
index b08110c584075a11c0c92001a08217acebf6621d..b8449ad4fbc3896209b1a7a929aafe7be2efde72 100644 (file)
                 <tr>
                     <td>{{loop.index}}</td>
                     <td>
-                        {% if mode in ('software', 'command', 'error_code', 'detection_mode', 'avg_peers', 'obfuscator', 'obfuscation', 'block_level') %}
+                        {% if mode in ('software', 'command', 'error_code', 'detection_mode', 'avg_peers', 'obfuscator', 'obfuscation') %}
                             {{entry['domain']}}
                         {% elif entry['domain'] == None %}
                             -
+                        {% elif mode == 'block_level' %}
+                            <a href="{{base_url}}/top?mode=block_level&amp;value={{entry['domain']}}&amp;amount=50">{{entry['domain']}}</a>
                         {% else %}
                             {% with domain=entry['domain'] %}
                             {% include "widgets/links.tpl" %}
index 0489ba4ab53abb8e9dc8328ecc5d5ec44e57b936..c18da52000f202b9623aef4a340080c9427c11aa 100644 (file)
@@ -1,23 +1,23 @@
 {% extends "base.html" %}
 
-{% block title %}{% if domain %} - Instances that block {{domain}}{% elif reverse %} - Instances that are blocked by {{reverse}}{% endif %}{% endblock %}
+{% block title %}{% if mode == 'domain' %} - Instances that block {{value}}{% elif mode == 'reverse' %} - Instances that are blocked by {{value}}{% elif mode == 'reason' %} - Instances having block reason {{value}}{% endif %}{% endblock %}
 
 {% block rss %}
     {{ super() }}
-    {% if domain %}
-        <link rel="alternate" type="application/rss+xml" title="RSS Feed for blocked domain {{domain}}" href="{{base_url}}/rss?domain={{domain}}" />
-    {% elif reverse %}
-        <link rel="alternate" type="application/rss+xml" title="RSS Feed for blocking domain {{reverse}}" href="{{base_url}}/rss?reverse={{reverse}}" />
+    {% if mode == 'domain' %}
+        <link rel="alternate" type="application/rss+xml" title="RSS Feed for blocked domain {{value}}" href="{{base_url}}/rss?domain={{value}}" />
+    {% elif mode == 'reverse' %}
+        <link rel="alternate" type="application/rss+xml" title="RSS Feed for blocking domain {{value}}" href="{{base_url}}/rss?reverse={{value}}" />
     {% endif %}
 {% endblock %}
 
 {% block header %}
-    {% if reason %}
-        <h1>Instances that use "{{reason}}" in their reason</h1>
-    {% elif reverse %}
-        <h1>Instances that are blocked by {{reverse}}</h1>
-    {% elif domain %}
-        <h1>Instances that block {{domain}}</h1>
+    {% if mode == 'reason' %}
+        <h1>Instances that use "{{value}}" in their reason</h1>
+    {% elif mode == 'reverse' %}
+        <h1>Instances that are blocked by {{value}}</h1>
+    {% elif mode == 'domain' %}
+        <h1>Instances that block {{value}}</h1>
     {% endif %}
 {% endblock %}
 
index e946612bc26195b01b81267ddd4c19b827c987a9..46b435a701a5cb465472ac8e8c27b027851053ba 100644 (file)
@@ -1,3 +1,3 @@
-[<a class="listlink" href="{{base_url}}/top?reverse={{domain}}" title="Search {{domain}}">D</a>]
-[<a class="listlink" href="{{base_url}}/top?reverse={{domain}}" title="Reverse search {{domain}}">R</a>]
+[<a class="listlink" href="{{base_url}}/top?mode=domain&amp;value={{domain}}" title="Search {{domain}}">D</a>]
+[<a class="listlink" href="{{base_url}}/top?mode=reverse&amp;value={{domain}}" title="Reverse search {{domain}}">R</a>]
 <a href="https://{{domain}}" rel="nofollow noopener noreferrer">{{domain}}</a>