--
This commit is contained in:
@@ -56,6 +56,7 @@
|
||||
<button type="button" class="tls-tab" data-tab="vulnerabilities" role="tab" aria-selected="false">脆弱性</button>
|
||||
<button type="button" class="tls-tab" data-tab="compatibility" role="tab" aria-selected="false">互換性</button>
|
||||
<button type="button" class="tls-tab" data-tab="log" role="tab" aria-selected="false">ログ</button>
|
||||
<button type="button" class="tls-tab" data-tab="history" role="tab" aria-selected="false">テスト履歴</button>
|
||||
<button type="button" class="tls-tab" data-tab="json" role="tab" aria-selected="false">JSON</button>
|
||||
</nav>
|
||||
</header>
|
||||
@@ -399,6 +400,30 @@
|
||||
</section>
|
||||
</div>
|
||||
|
||||
{# -------- テスト履歴 -------- #}
|
||||
<div class="tls-tab-panel" data-panel="history">
|
||||
<section class="tls-section">
|
||||
<h2 class="tls-section-title">過去のテスト結果 (同一対象)</h2>
|
||||
{% if history %}
|
||||
<table class="tls-table">
|
||||
<thead><tr><th>実行日時</th><th>ランク</th><th>スコア</th><th>リンク</th></tr></thead>
|
||||
<tbody>
|
||||
{% for h in history %}
|
||||
<tr>
|
||||
<td>{{ h.finished_at_display or '—' }}</td>
|
||||
<td>{{ h.rank or '—' }}</td>
|
||||
<td>{{ "%.0f"|format(h.score or 0) }}</td>
|
||||
<td><a href="/tools/tls-test/results/{{ h.id }}/" class="text-bright-green">{{ h.id[:8] }}…</a></td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
{% else %}
|
||||
<div class="tls-log-row"><span class="tls-log-cat text-tx-alt">[info]</span><span class="tls-log-msg text-tx-alt">過去のテスト結果はありません</span></div>
|
||||
{% endif %}
|
||||
</section>
|
||||
</div>
|
||||
|
||||
{# -------- JSON -------- #}
|
||||
<div class="tls-tab-panel" data-panel="json">
|
||||
<section class="tls-section">
|
||||
|
||||
@@ -58,6 +58,7 @@ class TlsTestDB:
|
||||
);
|
||||
CREATE INDEX IF NOT EXISTS idx_tests_expires ON tests(expires_at);
|
||||
CREATE INDEX IF NOT EXISTS idx_tests_ip_created ON tests(client_ip, created_at);
|
||||
CREATE INDEX IF NOT EXISTS idx_tests_target ON tests(target, created_at);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS test_progress (
|
||||
test_id TEXT NOT NULL,
|
||||
@@ -185,6 +186,30 @@ class TlsTestDB:
|
||||
finally:
|
||||
conn.close()
|
||||
|
||||
def get_history_by_target(self, target: str, exclude_id: str | None = None, limit: int = 10) -> list[dict[str, Any]]:
|
||||
conn = self._conn()
|
||||
try:
|
||||
cur = conn.cursor()
|
||||
if exclude_id:
|
||||
cur.execute(
|
||||
"SELECT id, target, status, created_at, finished_at, rank, score, error_message"
|
||||
" FROM tests WHERE target = ? AND id != ? AND status = 'done'"
|
||||
" ORDER BY created_at DESC LIMIT ?",
|
||||
(target, exclude_id, limit),
|
||||
)
|
||||
else:
|
||||
cur.execute(
|
||||
"SELECT id, target, status, created_at, finished_at, rank, score, error_message"
|
||||
" FROM tests WHERE target = ? AND status = 'done'"
|
||||
" ORDER BY created_at DESC LIMIT ?",
|
||||
(target, limit),
|
||||
)
|
||||
rows = cur.fetchall()
|
||||
cols = [c[0] for c in cur.description]
|
||||
return [dict(zip(cols, r)) for r in rows]
|
||||
finally:
|
||||
conn.close()
|
||||
|
||||
def count_ip_in_window(self, client_ip: str, window_seconds: int) -> int:
|
||||
cutoff = int(time.time()) - window_seconds
|
||||
conn = self._conn()
|
||||
|
||||
@@ -159,8 +159,12 @@ async def _gather(report: ReportProgress, finds: ReportFinding, result: ScanResu
|
||||
# SSL 2/3 → vulnerability findings; also record them as safety findings.
|
||||
if sslv2_supported:
|
||||
await emit(Finding("SSL/TLS Version", "SSL 2.0 supported", "SSLv2 は完全に破綻しています (DROWN)", "serious", 10, group=G_SAF))
|
||||
else:
|
||||
await emit(Finding("SSL/TLS Version", "SSL 2.0 disabled", "", "good", 0, group=G_SAF))
|
||||
if sslv3_supported:
|
||||
await emit(Finding("SSL/TLS Version", "SSL 3.0 supported", "POODLE 攻撃が可能", "serious", 10, group=G_SAF))
|
||||
else:
|
||||
await emit(Finding("SSL/TLS Version", "SSL 3.0 disabled", "", "good", 0, group=G_SAF))
|
||||
if version_support.get(C.TLS_1_0):
|
||||
await emit(Finding("SSL/TLS Version", "TLS 1.0 supported", "RFC 8996 で廃止済み", "notgood", 4, group=G_SAF))
|
||||
else:
|
||||
|
||||
@@ -80,6 +80,15 @@ def tls_results_context(job: dict, test_id: str, request: Request, tls_test_db)
|
||||
if step not in seen_steps:
|
||||
log_entries += [{"kind": "finding", "finding": f} for f in fs]
|
||||
|
||||
target = (result.get("target") or job.get("target") or "").strip()
|
||||
history = tls_test_db.get_history_by_target(target, exclude_id=test_id, limit=10) if target else []
|
||||
for h in history:
|
||||
try:
|
||||
ts = h.get("finished_at") or h.get("created_at") or 0
|
||||
h["finished_at_display"] = datetime.datetime.fromtimestamp(int(ts)).strftime("%Y-%m-%dT%H:%M:%S") if ts else ""
|
||||
except Exception:
|
||||
h["finished_at_display"] = ""
|
||||
|
||||
return {
|
||||
"test_id": test_id,
|
||||
"job": job,
|
||||
@@ -90,4 +99,5 @@ def tls_results_context(job: dict, test_id: str, request: Request, tls_test_db)
|
||||
"finished_at_display": finished_at_display,
|
||||
"share_url": str(request.url).split("#", 1)[0],
|
||||
"log_entries": log_entries,
|
||||
"history": history,
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user