- engine: add analyse_text() to extract visible page text and evaluate
category="text" rules; collect matched phrases and expose as
`content_snippet` (deduped, length-capped via settings.ui.snippet_preview_len).
- engine: removed unused code
- browser: removed double call for enrichment
- engine: improve regex compilation — honor per-rule flags (string or list)
and default IGNORECASE when category=="text".
- engine: add dispatch logging "[engine] applying categories: …" gated by
settings.app.print_rule_dispatch.
- ui(templates): add `templates/partials/result_text.html` mirroring the forms
table; renders page-level records and their matched rules.
- ui(controller): wire `analyse_text()` into scan path and expose
`payload["suspicious_text"]`.
- rules(text): add `identity_verification_prompt`, `gated_document_access`,
`email_collection_prompt`; broaden `credential_reset`.
fix: text indicators were not displayed due to missing analyzer and mismatched result shape.
Result shape:
suspicious_text: [
{
"type": "page",
"content_snippet": "...matched phrases…",
"rules": [
{"name": "...", "description": "...", "severity": "medium", "tags": ["..."]}
]
}
]
58 lines
2.3 KiB
HTML
58 lines
2.3 KiB
HTML
<!-- /templates/partials/result_enrichment.html -->
|
|
<section id="enrichment" class="bg-card border border-gray-800 rounded-xl p-4">
|
|
<h2 class="text-lg font-semibold mb-3">Enrichment</h2>
|
|
|
|
{% if enrichment.whois %}
|
|
<h3 class="text-base font-semibold mt-2 mb-2">WHOIS</h3>
|
|
<div class="overflow-x-auto">
|
|
<table class="min-w-full text-sm">
|
|
<thead class="text-gray-400 border-b border-gray-800">
|
|
<tr>
|
|
<th class="text-left py-2 pr-4">Field</th>
|
|
<th class="text-left py-2 pr-4">Value</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
{% for k, v in enrichment.whois.items() %}
|
|
<tr class="border-b border-gray-900">
|
|
<td class="py-2 pr-4 whitespace-nowrap">{{ k.replace('_', ' ').title() }}</td>
|
|
<td class="py-2 pr-4 break-all">{{ v }}</td>
|
|
</tr>
|
|
{% endfor %}
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
{% endif %}
|
|
|
|
{% if enrichment.raw_whois %}
|
|
<h3 class="text-base font-semibold mt-4 mb-2">Raw WHOIS</h3>
|
|
<pre class="bg-[#0b0f14] border border-gray-800 rounded-lg p-3 overflow-x-auto text-sm">{{ enrichment.raw_whois }}</pre>
|
|
{% endif %}
|
|
|
|
{% if enrichment.geoip %}
|
|
<h3 class="text-base font-semibold mt-4 mb-2">GeoIP</h3>
|
|
{% for ip, info in enrichment.geoip.items() %}
|
|
<details class="border border-gray-800 rounded-lg mb-2">
|
|
<summary class="px-3 py-2 cursor-pointer hover:bg-gray-900/50">{{ ip }}</summary>
|
|
<div class="px-3 pb-3 overflow-x-auto">
|
|
<table class="min-w-full text-sm">
|
|
<tbody>
|
|
{% for key, val in info.items() %}
|
|
<tr class="border-b border-gray-900">
|
|
<td class="py-2 pr-4 whitespace-nowrap text-gray-400">{{ key.replace('_', ' ').title() }}</td>
|
|
<td class="py-2 pr-4 break-all">{{ val }}</td>
|
|
</tr>
|
|
{% endfor %}
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
</details>
|
|
{% endfor %}
|
|
{% endif %}
|
|
|
|
{% if not enrichment.whois and not enrichment.raw_whois and not enrichment.geoip and not enrichment.bec_words %}
|
|
<p class="text-sm text-gray-500">No enrichment data available.</p>
|
|
{% endif %}
|
|
|
|
<p class="mt-2"><a href="#url-overview" class="text-sm text-gray-400 hover:text-blue-400">Back to top</a></p>
|
|
</section> |