templates_dnsbldir = $(templatesdir)/dnsbl
templates_dnsbl_lists_DATA = \
+ src/templates/dnsbl/lists/domain.html \
src/templates/dnsbl/lists/history.html \
src/templates/dnsbl/lists/index.html \
src/templates/dnsbl/lists/reports.html \
return [History(self._backend, **data) for data in response]
+ async def get_domain_history(self, name):
+ """
+ Fetches the history of a specific domain on this list
+ """
+ response = await self._backend.dnsbl._fetch(
+ "/lists/%s/domains/%s" % (self.slug, name),
+ )
+
+ return [DomainHistory(self._backend, **data) for data in response]
+
class Source(Model):
"""
# Domains Removed
domains_removed: typing.List[str] = []
+
+
+class DomainHistory(Model):
+ # Name
+ name: str
+
+ # Timestamp
+ timestamp: datetime.datetime
+
+ # Type
+ type: str
+
+ # Block?
+ block: bool = True
+
+ # By
+ by: str | None = None
+
+ # Source Name
+ source_name: str | None = None
+
+ # Report ID
+ report_id: uuid.UUID | None = None
+
+ # Blocks
+ blocks: int = 0
+
+ # Allows
+ allows: int = 0
--- /dev/null
+{% extends "../../base.html" %}
+
+{% block head %}
+ {% module OpenGraph(
+ title=_("IPFire DNSBL - %(list)s - Domain %(domain)s") %\
+ { "list" : list, "domain" : name },
+ description=list.description,
+ ) %}
+{% end block %}
+
+{% block title %}
+ {{ _("IPFire DNSBL") }} - {{ list }} - {{ _("Domain %s") % name }}
+{% end block %}
+
+{% block container %}
+ <section class="hero is-dark">
+ <div class="hero-body">
+ <div class="container">
+ <nav class="breadcrumb" aria-label="breadcrumbs">
+ <ul>
+ <li>
+ <a href="/dnsbl">
+ {{ _("IPFire DNSBL") }}
+ </a>
+ </li>
+
+ <li>
+ <a href="/dnsbl/lists">
+ {{ _("Lists") }}
+ </a>
+ </li>
+
+ <li>
+ <a href="/dnsbl/lists/{{ list.slug }}">
+ {{ list }}
+ </a>
+ </li>
+
+ <li class="is-active">
+ <a href="#" aria-current="page">{{ name }}</a>
+ </li>
+ </ul>
+ </nav>
+
+ <div class="columns is-vcentered">
+ <div class="column">
+ <h1 class="title">
+ {{ name }}
+ </h1>
+
+ <h3 class="subtitle">
+ {{ _("Listing on %s") % list }}
+ </h3>
+ </div>
+
+ <div class="column is-narrow">
+ {% for event in events %}
+ {# Allowed? #}
+ {% if event.allows %}
+ <span class="tag is-large is-success">
+ {{ _("Allowed") }}
+ </span>
+
+ {# Blocked? #}
+ {% elif event.blocks %}
+ <span class="tag is-large is-danger">
+ {{ _("Blocked") }}
+ </span>
+
+ {# Not Listed #}
+ {% else %}
+ <span class="tag is-large is-white">
+ {{ _("Not Listed") }}
+ </span>
+ {% end %}
+
+ {# Only use the latest result #}
+ {% break %}
+
+ {# If there are no events, this has never been listed #}
+ {% else %}
+ <span class="tag is-large is-white">
+ {{ _("Not Listed") }}
+ </span>
+ {% end %}
+ </div>
+ </div>
+ </div>
+ </div>
+ </section>
+
+ {# History #}
+ {% if events %}
+ <section class="section">
+ <div class="container">
+ <h5 class="title is-5">
+ {{ _("History") }}
+ </h5>
+
+ <table class="table is-hoverable is-fullwidth">
+ <tbody>
+ {% for event in events %}
+ <tr>
+ {# Timestamp #}
+ <td class="is-narrow">
+ {{ locale.format_date(event.timestamp, shorter=True) }}
+ </td>
+
+ {# What happened? #}
+ <td>
+ {% if event.type == "added" %}
+ {% if event.block %}
+ {{ _("A block was added by %s") % (event.by or event.source_name) }}
+ {% else %}
+ {{ _("The domain was exempted by %s") % (event.by or event.source_name) }}
+ {% end %}
+
+ {% elif event.type == "removed" %}
+ {% if event.block %}
+ {{ _("A block was lifted by %s") % (event.by or event.source_name) }}
+ {% else %}
+ {{ _("An exemption was removed by %s") % (event.by or event.source_name) }}
+ {% end %}
+ {% end %}
+ </td>
+
+ {# Show the current status #}
+ {% if event.allows %}
+ <td class="is-narrow is-success">
+ {{ _("Allowed") }}
+ </td>
+ {% elif event.blocks %}
+ <td class="is-narrow is-danger">
+ {{ _("Blocked") }}
+ </td>
+ {% else %}
+ <td class="is-narrow">
+ {{ _("Not Listed") }}
+ </td>
+ {% end %}
+ </tr>
+ {% end %}
+ </tbody>
+ </table>
+ </div>
+ </section>
+ {% end %}
+{% end block %}
<ul>
{# Domains Allowed #}
{% for domain in event.domains_allowed %}
- <li class="has-text-info" title="{{ _("Allowed") }}">
- + {{ format_domain(domain) }}
+ <li title="{{ _("Allowed") }}">
+ <a class="has-text-info" href="/dnsbl/lists/{{ list.slug }}/domains/{{ domain }}">
+ + {{ format_domain(domain) }}
+ </a>
</li>
{% end %}
{# Domains Blocked #}
{% for domain in event.domains_blocked %}
- <li class="has-text-success" title="{{ _("Blocked") }}">
- + {{ format_domain(domain) }}
+ <li title="{{ _("Blocked") }}">
+ <a class="has-text-success" href="/dnsbl/lists/{{ list.slug }}/domains/{{ domain }}">
+ + {{ format_domain(domain) }}
+ </a>
</li>
{% end %}
{# Domains Removed #}
{% for domain in event.domains_removed %}
- <li class="has-text-danger" title="{{ _("Removed") }}">
- − {{ format_domain(domain) }}
+ <li title="{{ _("Removed") }}">
+ <a class="has-text-danger" href="/dnsbl/lists/{{ list.slug }}/domains/{{ domain }}">
+ − {{ format_domain(domain) }}
+ </a>
</li>
{% end %}
</ul>
<ul>
{% for domain in domains %}
<li>
- {{ domain }}
+ <a href="/dnsbl/lists/{{ list.slug }}/domains/{{ domain }}">
+ {{ format_domain(domain) }}
+ </a>
</li>
{% end %}
</ul>
(r"/dnsbl/?", StaticHandler, { "template" : "dnsbl/index.html" }),
(r"/dnsbl/lists", dnsbl.ListsHandler),
(r"/dnsbl/lists/(\w+)", dnsbl.ListHandler),
+ (r"/dnsbl/lists/(\w+)/domains/(.*)", dnsbl.ListDomainHandler),
(r"/dnsbl/lists/(\w+)/history", dnsbl.ListHistoryHandler),
(r"/dnsbl/lists/(\w+)/reports", dnsbl.ListReportsHandler),
(r"/dnsbl/lists/(\w+)/sources", dnsbl.ListSourcesHandler),
self.render("dnsbl/lists/sources.html", list=list, sources=sources)
+class ListDomainHandler(base.AnalyticsMixin, BaseHandler):
+ async def get(self, slug, name):
+ # Fetch the list
+ list = await self.backend.dnsbl.get_list(slug)
+ if not list:
+ raise tornado.web.HTTPError(404, "Could not find list '%s'" % slug)
+
+ # Fetch the events
+ events = await list.get_domain_history(name)
+
+ # Render the page
+ self.render("dnsbl/lists/domain.html", list=list, name=name, events=events)
+
+
class SubmitReportHandler(base.AnalyticsMixin, BaseHandler):
async def get(self):
# Fetch all lists