{{ strings.watermark }}
{# ═══════════ COVER ═══════════ #}
{{ strings.cover.badge }}

OSINT-D2

{{ strings.cover.subtitle }}

{% if identity_card.name or identity_card.avatar_url %}
{% if identity_card.avatar_url %} avatar {% endif %}
{% if identity_card.name %}
{{ identity_card.name }}
{% endif %} {% if primary_handle %}
@{{ primary_handle }}
{% elif identity_card.name %} {# El objetivo es un nombre propio, no un handle: no anteponemos @ #} {% else %}
{{ person.target }}
{% endif %}
{% endif %}
{{ strings.cover.target_label }} {{ person.target }}
{{ strings.cover.date_label }} {{ generated_at }}
{{ strings.cover.report_label }} {{ report_id }}
{{ strings.cover.confidentiality_label }} {{ strings.cover.confidentiality_value }}
{% if identity_card.confirmed_networks %}
{% for net in identity_card.confirmed_networks %} {{ net }} {% endfor %}
{% endif %}
{# ═══════════ TABLE OF CONTENTS ═══════════ #}

{{ strings.toc_title }}

{# ═══════════ 01 — EXECUTIVE SUMMARY ═══════════ #}

{{ strings.analysis_title }}

{# ── Stats row ── #}
{{ profiles_confirmed_count }}
{{ strings.analysis_card_labels.confirmed }}
{{ profiles_unconfirmed_count }}
{{ strings.analysis_card_labels.unconfirmed }}
{{ profiles_total }}
{{ strings.analysis_card_labels.total }}
{{ confidence_pct }}%
{{ strings.analysis_confidence_label }}
{% if person.analysis %} {# ── Confidence bar ── #}
{{ strings.analysis_confidence_label }} {{ confidence_pct }}%

{{ strings.analysis_model_label }}: {{ person.analysis.model or "" }}  |  {{ strings.analysis_generated_label }}: {{ person.analysis.generated_at }}

{# ── Identity Card ── #} {% if identity_card.name %}
{% if identity_card.avatar_url %} avatar {% else %}
{{ person.target[0] | upper }}
{% endif %}

{{ identity_card.name }}

{% if identity_card.bio %}

{{ identity_card.bio }}

{% endif %}
{% if identity_card.location %}
📍 Location {{ identity_card.location }}
{% endif %} {% if identity_card.blog %} {% endif %} {% if identity_card.created_at %}
📅 Since {{ identity_card.created_at }}
{% endif %} {% for email in identity_card.emails %}
✉️ Email {{ email }}
{% endfor %}
{% if identity_card.github_stats %}
📦 {{ identity_card.github_stats.repos }} repos
👥 {{ identity_card.github_stats.followers }} followers
➡️ {{ identity_card.github_stats.following }} following
{% endif %}
{% endif %} {# ── Highlights ── #} {% if person.analysis.highlights %}

{{ strings.analysis_highlights_title }}

{% endif %} {# ── AI Sections (parsed) ── #} {% set has_real_sections = ai_sections.identity or ai_sections.geotemporal or ai_sections.psychological or ai_sections.technical or ai_sections.ideology or ai_sections.opsec %} {% if has_real_sections %} {% if ai_sections.identity %}

🆔 {{ strings.ai_section_identity | default("Identity") }}

{{ ai_sections.identity | markdown }}
{% endif %} {% if ai_sections.geotemporal %}

🌍 {{ strings.ai_section_geotemporal | default("Geo-Temporal") }}

{{ ai_sections.geotemporal | markdown }}
{% endif %} {% if ai_sections.psychological %}

🧠 {{ strings.ai_section_psychological | default("OCEAN Profile") }}

{{ ai_sections.psychological | markdown }}
{% endif %} {% if ai_sections.technical %}

💻 {{ strings.ai_section_technical | default("Technical / Professional") }}

{{ ai_sections.technical | markdown }}
{% endif %} {% if ai_sections.ideology %}

⚖️ {{ strings.ai_section_ideology | default("Ideology") }}

{{ ai_sections.ideology | markdown }}
{% endif %} {% if ai_sections.opsec %}

⚠️ {{ strings.ai_section_opsec | default("OpSec / Attack Surface") }}

{{ ai_sections.opsec | markdown }}
{% endif %} {% elif person.analysis.summary %} {# Fallback: render full summary as markdown if parsing failed #}
{{ person.analysis.summary | markdown }}
{% endif %} {% else %}

{{ strings.analysis_absent }}

{% endif %}
{# ═══════════ 02 — CONFIRMED FOOTPRINT ═══════════ #}

{{ strings.confirmed_title }}

{{ strings.confirmed_hint }} — {{ profiles_confirmed_count }} profiles

{% for p in profiles_confirmed %} {% endfor %}
{{ strings.confirmed_headers.network }} {{ strings.confirmed_headers.username }} {{ strings.confirmed_headers.source }} {{ strings.confirmed_headers.status }} {{ strings.confirmed_headers.url }}
{{ p.network_name }} {{ p.username }} {{ p._source }} {{ strings.status_confirmed }} {{ p.url[:45] }}{% if p.url|length > 45 %}…{% endif %}
{# ═══════════ 03 — UNCONFIRMED LEADS ═══════════ #}

{{ strings.unconfirmed_title }}

{{ strings.unconfirmed_hint }}

{% if profiles_unconfirmed_count == 0 %}

{{ strings.unconfirmed_none }}

{% else %} {% for source, items in unconfirmed_by_source %}

{{ strings.unconfirmed_source_label }}: {{ source }} ({{ items|length }})

{% for p in items %} {% endfor %}
{{ strings.unconfirmed_headers.network }} {{ strings.unconfirmed_headers.username }} {{ strings.unconfirmed_headers.url }}
{{ p.network_name }} {{ p.username }} {{ p.url[:50] }}{% if p.url|length > 50 %}…{% endif %}
{% endfor %} {% if unconfirmed_capped %}

⚠️ Showing top {{ unconfirmed_cap }} of {{ profiles_unconfirmed_count }} unconfirmed leads.

{% endif %} {% endif %}
{# ═══════════ 04 — TEXTUAL EVIDENCE ═══════════ #}

{{ strings.textual_title }}

{{ strings.textual_hint }}

{% set ns = namespace(printed=0) %} {% for p in person.profiles %} {% if p.metadata and (p.metadata.recent_commits or p.metadata.recent_comments) %} {% if ns.printed < 4 %}

{{ p.network_name }} // {{ p.username }}

{% if p.metadata.recent_commits %}
{{ strings.textual_commits }}: {% for c in p.metadata.recent_commits[:10] %} - {{ c.message }}{% if c.timestamp %} ({{ c.timestamp }}){% endif %} {% endfor %}
{% endif %} {% if p.metadata.recent_comments %}
{{ strings.textual_comments }}: {% for c in p.metadata.recent_comments[:10] %} - {{ c.body }}{% if c.subreddit %} [r/{{ c.subreddit }}]{% endif %} {% endfor %}
{% endif %} {% set ns.printed = ns.printed + 1 %} {% endif %} {% endif %} {% endfor %} {% if ns.printed == 0 %}

{{ strings.textual_none }}

{% endif %}
{# ═══════════ 05 — METHODOLOGY ═══════════ #}

{{ strings.methodology_title }}

{{ strings.methodology_hint }}

    {% for item in strings.methodology_points %}
  • {{ item }}
  • {% endfor %}
{# ═══════════ 06 — LIMITATIONS ═══════════ #}

{{ strings.limitations_title }}

    {% for item in strings.limitations_points %}
  • {{ item }}
  • {% endfor %}
{# ═══════════ 07 — BREACHES ═══════════ #}

{{ strings.breaches_title }}

{{ strings.breaches_hint }}

{% if not breach_entries %}

{{ strings.breaches_none }}

{% else %} {% for entry in breach_entries %}

HIBP // {{ entry.email }}

{{ strings.breaches_email_label }}: {{ entry.email }} {{ strings.breaches_status_label }}: {{ entry.status_code or "" }}
{% set dump = entry.breaches %} {% set breaches = dump.breaches if dump and dump.breaches is defined else [] %} {% if entry.status_code != 200 %}

{{ strings.breaches_request_failed }}

{% elif not breaches %}

{{ strings.breaches_no_breaches }}

{% else %} {% for b in breaches %} {% endfor %}
{{ strings.breaches_headers.title }} {{ strings.breaches_headers.domain }} {{ strings.breaches_headers.date }} {{ strings.breaches_headers.records }} {{ strings.breaches_headers.classes }}
{{ b.title }} {{ b.domain }} {{ b.breach_date }} {{ b.pwn_count }} {{ b.data_classes | join(", ") }}
{% endif %} {% endfor %} {% endif %}