feat: add whitelist checks to IP blacklist endpoint and rename checks to blacklists
All checks were successful
continuous-integration/drone/push Build is passing

This commit is contained in:
nemunaire 2026-03-09 16:01:52 +07:00
commit 8b6154c183
4 changed files with 41 additions and 18 deletions

View file

@ -1346,7 +1346,7 @@ components:
type: object
required:
- ip
- checks
- blacklists
- listed_count
- score
- grade
@ -1355,7 +1355,7 @@ components:
type: string
description: The IP address that was checked
example: "192.0.2.1"
checks:
blacklists:
type: array
items:
$ref: '#/components/schemas/BlacklistCheck'
@ -1375,3 +1375,8 @@ components:
enum: [A+, A, B, C, D, E, F]
description: Letter grade representation of the score
example: "A+"
whitelists:
type: array
items:
$ref: '#/components/schemas/BlacklistCheck'
description: List of DNS whitelist check results (informational only)

View file

@ -41,7 +41,7 @@ import (
type EmailAnalyzer interface {
AnalyzeEmailBytes(rawEmail []byte, testID uuid.UUID) (reportJSON []byte, err error)
AnalyzeDomain(domain string) (dnsResults *DNSResults, score int, grade string)
CheckBlacklistIP(ip string) (checks []BlacklistCheck, listedCount int, score int, grade string, err error)
CheckBlacklistIP(ip string) (checks []BlacklistCheck, whitelists []BlacklistCheck, listedCount int, score int, grade string, err error)
}
// APIHandler implements the ServerInterface for handling API requests
@ -359,7 +359,7 @@ func (h *APIHandler) CheckBlacklist(c *gin.Context) {
}
// Perform blacklist check using analyzer
checks, listedCount, score, grade, err := h.analyzer.CheckBlacklistIP(request.Ip)
checks, whitelists, listedCount, score, grade, err := h.analyzer.CheckBlacklistIP(request.Ip)
if err != nil {
c.JSON(http.StatusBadRequest, Error{
Error: "invalid_ip",
@ -372,7 +372,8 @@ func (h *APIHandler) CheckBlacklist(c *gin.Context) {
// Build response
response := BlacklistCheckResponse{
Ip: request.Ip,
Checks: checks,
Blacklists: checks,
Whitelists: &whitelists,
ListedCount: listedCount,
Score: score,
Grade: BlacklistCheckResponseGrade(grade),

View file

@ -121,12 +121,12 @@ func (a *APIAdapter) AnalyzeDomain(domain string) (*api.DNSResults, int, string)
return dnsResults, score, grade
}
// CheckBlacklistIP checks a single IP address against DNS blacklists
func (a *APIAdapter) CheckBlacklistIP(ip string) ([]api.BlacklistCheck, int, int, string, error) {
// CheckBlacklistIP checks a single IP address against DNS blacklists and whitelists
func (a *APIAdapter) CheckBlacklistIP(ip string) ([]api.BlacklistCheck, []api.BlacklistCheck, int, int, string, error) {
// Check the IP against all configured RBLs
checks, listedCount, err := a.analyzer.generator.rblChecker.CheckIP(ip)
if err != nil {
return nil, 0, 0, "", err
return nil, nil, 0, 0, "", err
}
// Calculate score using the existing function
@ -138,5 +138,11 @@ func (a *APIAdapter) CheckBlacklistIP(ip string) ([]api.BlacklistCheck, int, int
}
score, grade := a.analyzer.generator.rblChecker.CalculateScore(results)
return checks, listedCount, score, grade, nil
// Check the IP against all configured DNSWLs (informational only)
whitelists, _, err := a.analyzer.generator.dnswlChecker.CheckIP(ip)
if err != nil {
whitelists = nil
}
return checks, whitelists, listedCount, score, grade, nil
}

View file

@ -3,7 +3,7 @@
import { onMount } from "svelte";
import { checkBlacklist } from "$lib/api";
import type { BlacklistCheckResponse } from "$lib/api/types.gen";
import { BlacklistCard, GradeDisplay, TinySurvey } from "$lib/components";
import { BlacklistCard, GradeDisplay, TinySurvey, WhitelistCard } from "$lib/components";
import { theme } from "$lib/stores/theme";
let ip = $derived($page.params.ip);
@ -122,8 +122,8 @@
>
<p class="mb-0 mt-1 small">
This IP address is listed on {result.listed_count} of
{result.checks.length} checked blacklist{result
.checks.length > 1
{result.blacklists.length} checked blacklist{result
.blacklists.length > 1
? "s"
: ""}.
</p>
@ -150,12 +150,23 @@
</div>
</div>
<!-- Blacklist Results Card -->
<BlacklistCard
blacklists={{ [result.ip]: result.checks }}
blacklistScore={result.score}
blacklistGrade={result.grade}
/>
<div class="row">
<!-- Blacklist Results Card -->
<div class="col col-lg-6">
<BlacklistCard
blacklists={{ [result.ip]: result.blacklists }}
blacklistScore={result.score}
blacklistGrade={result.grade}
/>
</div>
<!-- Whitelist Results Card -->
{#if result.whitelists && result.whitelists.length > 0}
<div class="col col-lg-6">
<WhitelistCard whitelists={{ [result.ip]: result.whitelists }} />
</div>
{/if}
</div>
<!-- Information Card -->
<div class="card shadow-sm mt-4">