web: Format code files
This commit is contained in:
parent
035e864de4
commit
ac9b567025
22 changed files with 964 additions and 459 deletions
|
|
@ -1,5 +1,5 @@
|
|||
<script lang="ts">
|
||||
import type { AuthResult, DmarcRecord, HeaderAnalysis } from "$lib/api/types.gen";
|
||||
import type { DmarcRecord, HeaderAnalysis } from "$lib/api/types.gen";
|
||||
import { getScoreColorClass } from "$lib/score";
|
||||
import { theme } from "$lib/stores/theme";
|
||||
import GradeDisplay from "./GradeDisplay.svelte";
|
||||
|
|
@ -38,7 +38,14 @@
|
|||
<div class="mb-3">
|
||||
<h5>Issues</h5>
|
||||
{#each headerAnalysis.issues as issue}
|
||||
<div class="alert alert-{issue.severity === 'critical' || issue.severity === 'high' ? 'danger' : issue.severity === 'medium' ? 'warning' : 'info'} py-2 px-3 mb-2">
|
||||
<div
|
||||
class="alert alert-{issue.severity === 'critical' ||
|
||||
issue.severity === 'high'
|
||||
? 'danger'
|
||||
: issue.severity === 'medium'
|
||||
? 'warning'
|
||||
: 'info'} py-2 px-3 mb-2"
|
||||
>
|
||||
<div class="d-flex justify-content-between align-items-start">
|
||||
<div>
|
||||
<strong>{issue.header}</strong>
|
||||
|
|
@ -58,24 +65,48 @@
|
|||
{/if}
|
||||
|
||||
{#if headerAnalysis.domain_alignment}
|
||||
{@const spfStrictAligned = headerAnalysis.domain_alignment.from_domain === headerAnalysis.domain_alignment.return_path_domain}
|
||||
{@const spfRelaxedAligned = headerAnalysis.domain_alignment.from_org_domain === headerAnalysis.domain_alignment.return_path_org_domain}
|
||||
{@const spfStrictAligned =
|
||||
headerAnalysis.domain_alignment.from_domain ===
|
||||
headerAnalysis.domain_alignment.return_path_domain}
|
||||
{@const spfRelaxedAligned =
|
||||
headerAnalysis.domain_alignment.from_org_domain ===
|
||||
headerAnalysis.domain_alignment.return_path_org_domain}
|
||||
<div class="card mb-3" id="domain-alignment">
|
||||
<div class="card-header">
|
||||
<h5 class="mb-0">
|
||||
<i class="bi {headerAnalysis.domain_alignment.aligned ? 'bi-check-circle-fill text-success' : headerAnalysis.domain_alignment.relaxed_aligned ? 'bi-check-circle text-info' : 'bi-x-circle-fill text-danger'}"></i>
|
||||
<i
|
||||
class="bi {headerAnalysis.domain_alignment.aligned
|
||||
? 'bi-check-circle-fill text-success'
|
||||
: headerAnalysis.domain_alignment.relaxed_aligned
|
||||
? 'bi-check-circle text-info'
|
||||
: 'bi-x-circle-fill text-danger'}"
|
||||
></i>
|
||||
Domain Alignment
|
||||
</h5>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<p class="card-text small text-muted">
|
||||
Domain alignment ensures that the visible "From" domain matches the domain used for authentication (Return-Path or DKIM signature). Proper alignment is crucial for DMARC compliance, regardless of the policy. It helps prevent email spoofing by verifying that the sender domain is consistent across all authentication layers. Only one of the following lines needs to pass.
|
||||
Domain alignment ensures that the visible "From" domain matches the domain
|
||||
used for authentication (Return-Path or DKIM signature). Proper alignment is
|
||||
crucial for DMARC compliance, regardless of the policy. It helps prevent
|
||||
email spoofing by verifying that the sender domain is consistent across all
|
||||
authentication layers. Only one of the following lines needs to pass.
|
||||
</p>
|
||||
{#if headerAnalysis.domain_alignment.issues && headerAnalysis.domain_alignment.issues.length > 0}
|
||||
<div class="mt-3">
|
||||
{#each headerAnalysis.domain_alignment.issues as issue}
|
||||
<div class="alert alert-{headerAnalysis.domain_alignment.relaxed_aligned ? 'info' : 'warning'} py-2 small mb-2">
|
||||
<i class="bi bi-{headerAnalysis.domain_alignment.relaxed_aligned ? 'info-circle' : 'exclamation-triangle'} me-1"></i>
|
||||
<div
|
||||
class="alert alert-{headerAnalysis.domain_alignment
|
||||
.relaxed_aligned
|
||||
? 'info'
|
||||
: 'warning'} py-2 small mb-2"
|
||||
>
|
||||
<i
|
||||
class="bi bi-{headerAnalysis.domain_alignment
|
||||
.relaxed_aligned
|
||||
? 'info-circle'
|
||||
: 'exclamation-triangle'} me-1"
|
||||
></i>
|
||||
{issue}
|
||||
</div>
|
||||
{/each}
|
||||
|
|
@ -84,7 +115,10 @@
|
|||
</div>
|
||||
<div class="list-group list-group-flush">
|
||||
<div class="list-group-item d-flex ps-0">
|
||||
<div class="d-flex align-items-center justify-content-center" style="writing-mode: vertical-rl; transform: rotate(180deg); font-size: 1.5rem; font-weight: bold; min-width: 3rem;">
|
||||
<div
|
||||
class="d-flex align-items-center justify-content-center"
|
||||
style="writing-mode: vertical-rl; transform: rotate(180deg); font-size: 1.5rem; font-weight: bold; min-width: 3rem;"
|
||||
>
|
||||
SPF
|
||||
</div>
|
||||
<div class="flex-fill">
|
||||
|
|
@ -92,9 +126,17 @@
|
|||
<div class="col-md-3">
|
||||
<small class="text-muted">Strict Alignment</small>
|
||||
<div>
|
||||
<span class="badge" class:bg-success={spfStrictAligned} class:bg-danger={!spfStrictAligned}>
|
||||
<i class="bi {spfStrictAligned ? 'bi-check-circle-fill' : 'bi-x-circle-fill'} me-1"></i>
|
||||
<strong>{spfStrictAligned ? 'Pass' : 'Fail'}</strong>
|
||||
<span
|
||||
class="badge"
|
||||
class:bg-success={spfStrictAligned}
|
||||
class:bg-danger={!spfStrictAligned}
|
||||
>
|
||||
<i
|
||||
class="bi {spfStrictAligned
|
||||
? 'bi-check-circle-fill'
|
||||
: 'bi-x-circle-fill'} me-1"
|
||||
></i>
|
||||
<strong>{spfStrictAligned ? "Pass" : "Fail"}</strong>
|
||||
</span>
|
||||
</div>
|
||||
<div class="small text-muted mt-1">Exact domain match</div>
|
||||
|
|
@ -102,38 +144,78 @@
|
|||
<div class="col-md-3">
|
||||
<small class="text-muted">Relaxed Alignment</small>
|
||||
<div>
|
||||
<span class="badge" class:bg-success={spfRelaxedAligned} class:bg-danger={!spfRelaxedAligned}>
|
||||
<i class="bi {spfRelaxedAligned ? 'bi-check-circle-fill' : 'bi-x-circle-fill'} me-1"></i>
|
||||
<strong>{spfRelaxedAligned ? 'Pass' : 'Fail'}</strong>
|
||||
<span
|
||||
class="badge"
|
||||
class:bg-success={spfRelaxedAligned}
|
||||
class:bg-danger={!spfRelaxedAligned}
|
||||
>
|
||||
<i
|
||||
class="bi {spfRelaxedAligned
|
||||
? 'bi-check-circle-fill'
|
||||
: 'bi-x-circle-fill'} me-1"
|
||||
></i>
|
||||
<strong>{spfRelaxedAligned ? "Pass" : "Fail"}</strong>
|
||||
</span>
|
||||
</div>
|
||||
<div class="small text-muted mt-1">Organizational domain match</div>
|
||||
<div class="small text-muted mt-1">
|
||||
Organizational domain match
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-3">
|
||||
<small class="text-muted">From Domain</small>
|
||||
<div><code>{headerAnalysis.domain_alignment.from_domain || '-'}</code></div>
|
||||
<div>
|
||||
<code>
|
||||
{headerAnalysis.domain_alignment.from_domain || "-"}
|
||||
</code>
|
||||
</div>
|
||||
{#if headerAnalysis.domain_alignment.from_org_domain && headerAnalysis.domain_alignment.from_org_domain !== headerAnalysis.domain_alignment.from_domain}
|
||||
<div class="small text-muted mt-1">Org: <code>{headerAnalysis.domain_alignment.from_org_domain}</code></div>
|
||||
<div class="small text-muted mt-1">
|
||||
Org:
|
||||
<code>
|
||||
{headerAnalysis.domain_alignment.from_org_domain}
|
||||
</code>
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
<div class="col-md-3">
|
||||
<small class="text-muted">Return-Path Domain</small>
|
||||
<div><code>{headerAnalysis.domain_alignment.return_path_domain || '-'}</code></div>
|
||||
<div>
|
||||
<code>
|
||||
{headerAnalysis.domain_alignment.return_path_domain ||
|
||||
"-"}
|
||||
</code>
|
||||
</div>
|
||||
{#if headerAnalysis.domain_alignment.return_path_org_domain && headerAnalysis.domain_alignment.return_path_org_domain !== headerAnalysis.domain_alignment.return_path_domain}
|
||||
<div class="small text-muted mt-1">Org: <code>{headerAnalysis.domain_alignment.return_path_org_domain}</code></div>
|
||||
<div class="small text-muted mt-1">
|
||||
Org:
|
||||
<code>
|
||||
{headerAnalysis.domain_alignment
|
||||
.return_path_org_domain}
|
||||
</code>
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Alignment Information based on DMARC policy -->
|
||||
{#if dmarcRecord && headerAnalysis.domain_alignment.return_path_domain && headerAnalysis.domain_alignment.return_path_domain !== headerAnalysis.domain_alignment.from_domain}
|
||||
<div class="alert mt-2 mb-0 small py-2 {dmarcRecord.spf_alignment === 'strict' ? 'alert-warning' : 'alert-info'}">
|
||||
{#if dmarcRecord.spf_alignment === 'strict'}
|
||||
<div
|
||||
class="alert mt-2 mb-0 small py-2 {dmarcRecord.spf_alignment ===
|
||||
'strict'
|
||||
? 'alert-warning'
|
||||
: 'alert-info'}"
|
||||
>
|
||||
{#if dmarcRecord.spf_alignment === "strict"}
|
||||
<i class="bi bi-exclamation-triangle me-1"></i>
|
||||
<strong>Strict SPF alignment required</strong> — Your DMARC policy requires exact domain match. The Return-Path domain must exactly match the From domain for SPF to pass DMARC alignment.
|
||||
<strong>Strict SPF alignment required</strong> — Your DMARC policy
|
||||
requires exact domain match. The Return-Path domain must exactly
|
||||
match the From domain for SPF to pass DMARC alignment.
|
||||
{:else}
|
||||
<i class="bi bi-info-circle me-1"></i>
|
||||
<strong>Relaxed SPF alignment allowed</strong> — Your DMARC policy allows organizational domain matching. As long as both domains share the same organizational domain (e.g., mail.example.com and example.com), SPF alignment can pass.
|
||||
<strong>Relaxed SPF alignment allowed</strong> — Your DMARC policy
|
||||
allows organizational domain matching. As long as both domains
|
||||
share the same organizational domain (e.g., mail.example.com
|
||||
and example.com), SPF alignment can pass.
|
||||
{/if}
|
||||
</div>
|
||||
{/if}
|
||||
|
|
@ -141,10 +223,16 @@
|
|||
</div>
|
||||
|
||||
{#each headerAnalysis.domain_alignment.dkim_domains as dkim_domain}
|
||||
{@const dkim_aligned = dkim_domain.domain === headerAnalysis.domain_alignment.from_domain}
|
||||
{@const dkim_relaxed_aligned = dkim_domain.org_domain === headerAnalysis.domain_alignment.from_org_domain}
|
||||
{@const dkim_aligned =
|
||||
dkim_domain.domain === headerAnalysis.domain_alignment.from_domain}
|
||||
{@const dkim_relaxed_aligned =
|
||||
dkim_domain.org_domain ===
|
||||
headerAnalysis.domain_alignment.from_org_domain}
|
||||
<div class="list-group-item d-flex ps-0">
|
||||
<div class="d-flex align-items-center justify-content-center" style="writing-mode: vertical-rl; transform: rotate(180deg); font-size: 1.5rem; font-weight: bold; min-width: 3rem;">
|
||||
<div
|
||||
class="d-flex align-items-center justify-content-center"
|
||||
style="writing-mode: vertical-rl; transform: rotate(180deg); font-size: 1.5rem; font-weight: bold; min-width: 3rem;"
|
||||
>
|
||||
DKIM
|
||||
</div>
|
||||
<div class="flex-fill">
|
||||
|
|
@ -153,35 +241,72 @@
|
|||
<div class="col-md-3">
|
||||
<small class="text-muted">Strict Alignment</small>
|
||||
<div>
|
||||
<span class="badge" class:bg-success={dkim_aligned} class:bg-danger={!dkim_aligned}>
|
||||
<i class="bi {dkim_aligned ? 'bi-check-circle-fill' : 'bi-x-circle-fill'} me-1"></i>
|
||||
<strong>{dkim_aligned ? 'Pass' : 'Fail'}</strong>
|
||||
<span
|
||||
class="badge"
|
||||
class:bg-success={dkim_aligned}
|
||||
class:bg-danger={!dkim_aligned}
|
||||
>
|
||||
<i
|
||||
class="bi {dkim_aligned
|
||||
? 'bi-check-circle-fill'
|
||||
: 'bi-x-circle-fill'} me-1"
|
||||
></i>
|
||||
<strong>{dkim_aligned ? "Pass" : "Fail"}</strong
|
||||
>
|
||||
</span>
|
||||
</div>
|
||||
<div class="small text-muted mt-1">Exact domain match</div>
|
||||
<div class="small text-muted mt-1">
|
||||
Exact domain match
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-3">
|
||||
<small class="text-muted">Relaxed Alignment</small>
|
||||
<div>
|
||||
<span class="badge" class:bg-success={dkim_relaxed_aligned} class:bg-danger={!dkim_relaxed_aligned}>
|
||||
<i class="bi {dkim_relaxed_aligned ? 'bi-check-circle-fill' : 'bi-x-circle-fill'} me-1"></i>
|
||||
<strong>{dkim_relaxed_aligned ? 'Pass' : 'Fail'}</strong>
|
||||
<span
|
||||
class="badge"
|
||||
class:bg-success={dkim_relaxed_aligned}
|
||||
class:bg-danger={!dkim_relaxed_aligned}
|
||||
>
|
||||
<i
|
||||
class="bi {dkim_relaxed_aligned
|
||||
? 'bi-check-circle-fill'
|
||||
: 'bi-x-circle-fill'} me-1"
|
||||
></i>
|
||||
<strong
|
||||
>{dkim_relaxed_aligned
|
||||
? "Pass"
|
||||
: "Fail"}</strong
|
||||
>
|
||||
</span>
|
||||
</div>
|
||||
<div class="small text-muted mt-1">Organizational domain match</div>
|
||||
<div class="small text-muted mt-1">
|
||||
Organizational domain match
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-3">
|
||||
<small class="text-muted">From Domain</small>
|
||||
<div><code>{headerAnalysis.domain_alignment.from_domain || '-'}</code></div>
|
||||
<div>
|
||||
<code
|
||||
>{headerAnalysis.domain_alignment.from_domain ||
|
||||
"-"}</code
|
||||
>
|
||||
</div>
|
||||
{#if headerAnalysis.domain_alignment.from_org_domain && headerAnalysis.domain_alignment.from_org_domain !== headerAnalysis.domain_alignment.from_domain}
|
||||
<div class="small text-muted mt-1">Org: <code>{headerAnalysis.domain_alignment.from_org_domain}</code></div>
|
||||
<div class="small text-muted mt-1">
|
||||
Org: <code
|
||||
>{headerAnalysis.domain_alignment
|
||||
.from_org_domain}</code
|
||||
>
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
<div class="col-md-3">
|
||||
<small class="text-muted">Signature Domain</small>
|
||||
<div><code>{dkim_domain.domain || '-'}</code></div>
|
||||
<div><code>{dkim_domain.domain || "-"}</code></div>
|
||||
{#if dkim_domain.domain !== dkim_domain.org_domain}
|
||||
<div class="small text-muted mt-1">Org: <code>{dkim_domain.org_domain}</code></div>
|
||||
<div class="small text-muted mt-1">
|
||||
Org: <code>{dkim_domain.org_domain}</code>
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -189,13 +314,25 @@
|
|||
<!-- Alignment Information based on DMARC policy -->
|
||||
{#if dmarcRecord && dkim_domain.domain !== headerAnalysis.domain_alignment.from_domain}
|
||||
{#if dkim_domain.org_domain === headerAnalysis.domain_alignment.from_org_domain}
|
||||
<div class="alert mt-2 mb-0 small py-2 {dmarcRecord.dkim_alignment === 'strict' ? 'alert-warning' : 'alert-info'}">
|
||||
{#if dmarcRecord.dkim_alignment === 'strict'}
|
||||
<div
|
||||
class="alert mt-2 mb-0 small py-2 {dmarcRecord.dkim_alignment ===
|
||||
'strict'
|
||||
? 'alert-warning'
|
||||
: 'alert-info'}"
|
||||
>
|
||||
{#if dmarcRecord.dkim_alignment === "strict"}
|
||||
<i class="bi bi-exclamation-triangle me-1"></i>
|
||||
<strong>Strict DKIM alignment required</strong> — Your DMARC policy requires exact domain match. The DKIM signature domain must exactly match the From domain for DKIM to pass DMARC alignment.
|
||||
<strong>Strict DKIM alignment required</strong> —
|
||||
Your DMARC policy requires exact domain match. The
|
||||
DKIM signature domain must exactly match the From
|
||||
domain for DKIM to pass DMARC alignment.
|
||||
{:else}
|
||||
<i class="bi bi-info-circle me-1"></i>
|
||||
<strong>Relaxed DKIM alignment allowed</strong> — Your DMARC policy allows organizational domain matching. As long as both domains share the same organizational domain (e.g., mail.example.com and example.com), DKIM alignment can pass.
|
||||
<strong>Relaxed DKIM alignment allowed</strong> —
|
||||
Your DMARC policy allows organizational domain matching.
|
||||
As long as both domains share the same organizational
|
||||
domain (e.g., mail.example.com and example.com),
|
||||
DKIM alignment can pass.
|
||||
{/if}
|
||||
</div>
|
||||
{/if}
|
||||
|
|
@ -224,9 +361,9 @@
|
|||
</thead>
|
||||
<tbody>
|
||||
{#each Object.entries(headerAnalysis.headers).sort((a, b) => {
|
||||
const importanceOrder = { 'required': 0, 'recommended': 1, 'optional': 2, 'newsletter': 3 };
|
||||
const aImportance = importanceOrder[a[1].importance || 'optional'];
|
||||
const bImportance = importanceOrder[b[1].importance || 'optional'];
|
||||
const importanceOrder = { required: 0, recommended: 1, optional: 2, newsletter: 3 };
|
||||
const aImportance = importanceOrder[a[1].importance || "optional"];
|
||||
const bImportance = importanceOrder[b[1].importance || "optional"];
|
||||
return aImportance - bImportance;
|
||||
}) as [name, check]}
|
||||
<tr>
|
||||
|
|
@ -235,23 +372,39 @@
|
|||
</td>
|
||||
<td>
|
||||
{#if check.importance}
|
||||
<small class="text-{check.importance === 'required' ? 'danger' : check.importance === 'recommended' ? 'warning' : 'secondary'}">
|
||||
<small
|
||||
class="text-{check.importance === 'required'
|
||||
? 'danger'
|
||||
: check.importance === 'recommended'
|
||||
? 'warning'
|
||||
: 'secondary'}"
|
||||
>
|
||||
{check.importance}
|
||||
</small>
|
||||
{/if}
|
||||
</td>
|
||||
<td>
|
||||
<i class="bi {check.present ? 'bi-check-circle text-success' : 'bi-x-circle text-danger'}"></i>
|
||||
<i
|
||||
class="bi {check.present
|
||||
? 'bi-check-circle text-success'
|
||||
: 'bi-x-circle text-danger'}"
|
||||
></i>
|
||||
</td>
|
||||
<td>
|
||||
{#if check.present && check.valid !== undefined}
|
||||
<i class="bi {check.valid ? 'bi-check-circle text-success' : 'bi-x-circle text-warning'}"></i>
|
||||
<i
|
||||
class="bi {check.valid
|
||||
? 'bi-check-circle text-success'
|
||||
: 'bi-x-circle text-warning'}"
|
||||
></i>
|
||||
{:else}
|
||||
-
|
||||
{/if}
|
||||
</td>
|
||||
<td>
|
||||
<small class="text-muted text-truncate" title={check.value}>{check.value || '-'}</small>
|
||||
<small class="text-muted text-truncate" title={check.value}
|
||||
>{check.value || "-"}</small
|
||||
>
|
||||
{#if check.issues && check.issues.length > 0}
|
||||
{#each check.issues as issue}
|
||||
<div class="text-warning small">
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue