Files
Infosec/Forensic-Mail-Indexer/frontend/index.html
T
2026-09-13 20:09:20 +01:00

260 lines
13 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>PST Archive · Mail Indexer</title>
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Fraunces:ital,opsz,wght@0,9..144,300;0,9..144,500;0,9..144,700;1,9..144,400&family=JetBrains+Mono:wght@400;500;700&display=swap" rel="stylesheet">
<link rel="stylesheet" href="/styles.css" />
<script>
// Inline theme bootstrap — runs before CSS so no flash of wrong theme
(function() {
try {
var t = localStorage.getItem("pst-theme");
if (t !== "light" && t !== "dark") {
t = (window.matchMedia && window.matchMedia("(prefers-color-scheme: dark)").matches) ? "dark" : "light";
}
document.documentElement.dataset.theme = t;
} catch (e) {
document.documentElement.dataset.theme = "light";
}
})();
</script>
</head>
<body>
<div class="grain"></div>
<!-- Floating theme toggle (visible on all screens) -->
<button id="themeToggleFloat" class="theme-toggle theme-toggle-float" title="Toggle theme" aria-label="Toggle theme">
<svg class="icon-sun" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="4.5"/><line x1="12" y1="2" x2="12" y2="4.5"/><line x1="12" y1="19.5" x2="12" y2="22"/><line x1="2" y1="12" x2="4.5" y2="12"/><line x1="19.5" y1="12" x2="22" y2="12"/><line x1="4.9" y1="4.9" x2="6.7" y2="6.7"/><line x1="17.3" y1="17.3" x2="19.1" y2="19.1"/><line x1="4.9" y1="19.1" x2="6.7" y2="17.3"/><line x1="17.3" y1="6.7" x2="19.1" y2="4.9"/></svg>
<svg class="icon-moon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round"><path d="M20 14.5A9 9 0 019.5 4a7.5 7.5 0 1010.5 10.5z"/></svg>
</button>
<!-- SETUP WIZARD -->
<section id="setupScreen" class="auth-screen hidden">
<div class="auth-card">
<div class="auth-brand">
<svg viewBox="0 0 40 40" width="44" height="44" aria-hidden="true">
<rect x="3" y="8" width="34" height="26" fill="none" stroke="currentColor" stroke-width="1.5"/>
<path d="M3 8 L20 22 L37 8" fill="none" stroke="currentColor" stroke-width="1.5"/>
<line x1="3" y1="34" x2="14" y2="22" stroke="currentColor" stroke-width="1.5"/>
<line x1="37" y1="34" x2="26" y2="22" stroke="currentColor" stroke-width="1.5"/>
</svg>
<h1>PST Archive</h1>
<p class="auth-tagline">First-run setup</p>
</div>
<form id="setupForm" class="auth-form" novalidate>
<p class="auth-intro">Create the primary administrator account. This user will have full access to the archive and the admin panel.</p>
<label class="auth-label">
<span>Username</span>
<input type="text" name="username" autocomplete="username" required minlength="3" maxlength="64" />
</label>
<label class="auth-label">
<span>Password</span>
<input type="password" name="password" autocomplete="new-password" required minlength="8" />
<small>Minimum 8 characters. Use a passphrase you will remember.</small>
</label>
<label class="auth-label">
<span>Confirm password</span>
<input type="password" name="password2" autocomplete="new-password" required minlength="8" />
</label>
<button type="submit" class="auth-btn">Create administrator</button>
<div id="setupError" class="auth-error hidden"></div>
</form>
</div>
</section>
<!-- LOGIN -->
<section id="loginScreen" class="auth-screen hidden">
<div class="auth-card">
<div class="auth-brand">
<svg viewBox="0 0 40 40" width="44" height="44" aria-hidden="true">
<rect x="3" y="8" width="34" height="26" fill="none" stroke="currentColor" stroke-width="1.5"/>
<path d="M3 8 L20 22 L37 8" fill="none" stroke="currentColor" stroke-width="1.5"/>
<line x1="3" y1="34" x2="14" y2="22" stroke="currentColor" stroke-width="1.5"/>
<line x1="37" y1="34" x2="26" y2="22" stroke="currentColor" stroke-width="1.5"/>
</svg>
<h1>PST Archive</h1>
<p class="auth-tagline">Sign in to continue</p>
</div>
<form id="loginForm" class="auth-form" novalidate>
<label class="auth-label">
<span>Username</span>
<input type="text" name="username" autocomplete="username" required />
</label>
<label class="auth-label">
<span>Password</span>
<input type="password" name="password" autocomplete="current-password" required />
</label>
<label id="mfaField" class="auth-label hidden">
<span>Authentication code</span>
<input type="text" name="totp_code" autocomplete="one-time-code" inputmode="numeric" pattern="[0-9]*" maxlength="6" placeholder="6-digit code" />
<small>From your authenticator app</small>
</label>
<button type="submit" class="auth-btn">Sign in</button>
<div id="loginError" class="auth-error hidden"></div>
</form>
</div>
</section>
<!-- MAIN APP -->
<div id="mainApp" class="hidden">
<header class="masthead">
<div class="masthead-left">
<div class="logo-mark">
<svg viewBox="0 0 40 40" width="36" height="36" aria-hidden="true">
<rect x="3" y="8" width="34" height="26" fill="none" stroke="currentColor" stroke-width="1.5"/>
<path d="M3 8 L20 22 L37 8" fill="none" stroke="currentColor" stroke-width="1.5"/>
<line x1="3" y1="34" x2="14" y2="22" stroke="currentColor" stroke-width="1.5"/>
<line x1="37" y1="34" x2="26" y2="22" stroke="currentColor" stroke-width="1.5"/>
</svg>
</div>
<div class="masthead-title">
<h1>PST Archive</h1>
<p class="tagline">Forensic mail indexer · v1.0</p>
</div>
</div>
<div class="masthead-right">
<span id="statusDot" class="status-dot"></span>
<span id="statusText" class="status-text">connecting…</span>
<span id="userChip" class="user-chip"></span>
<button id="adminNavBtn" class="admin-nav-btn hidden" title="Open the administration section">Administration</button>
<button id="themeToggle" class="theme-toggle" title="Toggle theme" aria-label="Toggle theme">
<svg class="icon-sun" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="4.5"/><line x1="12" y1="2" x2="12" y2="4.5"/><line x1="12" y1="19.5" x2="12" y2="22"/><line x1="2" y1="12" x2="4.5" y2="12"/><line x1="19.5" y1="12" x2="22" y2="12"/><line x1="4.9" y1="4.9" x2="6.7" y2="6.7"/><line x1="17.3" y1="17.3" x2="19.1" y2="19.1"/><line x1="4.9" y1="19.1" x2="6.7" y2="17.3"/><line x1="17.3" y1="6.7" x2="19.1" y2="4.9"/></svg>
<svg class="icon-moon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round"><path d="M20 14.5A9 9 0 019.5 4a7.5 7.5 0 1010.5 10.5z"/></svg>
</button>
<button id="logoutBtn" class="logout-btn" title="Sign out">Sign out</button>
</div>
</header>
<main class="workspace">
<aside class="sidebar">
<section class="upload-block">
<h2 class="section-heading">01 · Ingest</h2>
<label class="dropzone" id="dropzone">
<input type="file" id="fileInput" accept=".pst,.ost" hidden />
<div class="dropzone-inner">
<svg viewBox="0 0 24 24" width="24" height="24" aria-hidden="true">
<path d="M12 3v12m0 0l-4-4m4 4l4-4M4 17v2a2 2 0 002 2h12a2 2 0 002-2v-2" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"/>
</svg>
<span class="dropzone-title">Drop <em>.pst</em> / <em>.ost</em></span>
<span class="dropzone-hint">or click to browse</span>
</div>
</label>
<div id="uploadProgress" class="upload-progress hidden">
<div class="progress-label"><span id="progressName"></span> <span id="progressPct">0%</span></div>
<div class="progress-track"><div id="progressBar" class="progress-bar"></div></div>
</div>
</section>
<section class="archive-block">
<div class="archive-head">
<h2 class="section-heading">02 · Archives</h2>
<div class="archive-actions">
<button id="newFolderBtn" class="icon-btn" title="New folder">
<svg viewBox="0 0 24 24" width="14" height="14"><path d="M3 7a2 2 0 012-2h4l2 2h8a2 2 0 012 2v8a2 2 0 01-2 2H5a2 2 0 01-2-2V7z" fill="none" stroke="currentColor" stroke-width="1.5"/><line x1="12" y1="11" x2="12" y2="17" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"/><line x1="9" y1="14" x2="15" y2="14" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"/></svg>
</button>
<button id="refreshBtn" class="icon-btn" title="Refresh list">
<svg viewBox="0 0 24 24" width="14" height="14"><path d="M4 4v6h6M20 20v-6h-6M20 10a8 8 0 00-14.9-3M4 14a8 8 0 0014.9 3" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"/></svg>
</button>
</div>
</div>
<ul id="pstList" class="pst-list">
<li class="empty-state">No archives yet.</li>
</ul>
</section>
</aside>
<section class="reader">
<div class="reader-head">
<div class="reader-title">
<h2 id="readerTitle">Select an archive</h2>
<p id="readerMeta" class="reader-meta">Upload a PST file or select one from the left to begin.</p>
</div>
<div class="search-wrap">
<input id="searchInput" type="search" placeholder="Search subject, sender, body…" disabled />
<select id="folderFilter" disabled>
<option value="">All folders</option>
</select>
</div>
</div>
<div class="reader-body">
<div id="messageList" class="message-list">
<div class="reader-placeholder">
<div class="placeholder-ornament"></div>
<p>The archive awaits.</p>
</div>
</div>
<article id="messageView" class="message-view hidden">
<button id="closeMessageBtn" class="close-btn" title="Close">×</button>
<header class="message-header">
<div class="message-subject" id="mvSubject"></div>
<dl class="message-meta">
<dt>From</dt><dd id="mvSender"></dd>
<dt>To</dt><dd id="mvRecipients"></dd>
<dt>Date</dt><dd id="mvDate"></dd>
<dt>Folder</dt><dd id="mvFolder"></dd>
<dt id="mvAttLabel" class="hidden">Attachments</dt>
<dd id="mvAttachments" class="hidden"></dd>
</dl>
</header>
<div class="message-body" id="mvBody"></div>
</article>
</div>
<div id="paginator" class="paginator hidden">
<button id="prevBtn">← Previous</button>
<span id="pageInfo"></span>
<button id="nextBtn">Next →</button>
</div>
</section>
</main>
<footer class="site-footer">© 2026 Martinhal IT - Joao Vaz - Version 2.2</footer>
</div>
<div id="toast" class="toast hidden"></div>
<!-- NEW FOLDER MODAL -->
<div id="folderModal" class="modal hidden">
<div class="modal-card">
<button class="modal-close" data-close>×</button>
<h2>New folder</h2>
<form id="folderForm" class="auth-form" novalidate>
<label class="auth-label">
<span>Folder name</span>
<input type="text" name="name" maxlength="80" required autocomplete="off" />
</label>
<button type="submit" class="auth-btn">Create folder</button>
<div id="folderError" class="auth-error hidden"></div>
</form>
</div>
</div>
<!-- MOVE PST MODAL -->
<div id="moveModal" class="modal hidden">
<div class="modal-card">
<button class="modal-close" data-close>×</button>
<h2>Move archive</h2>
<p class="modal-subtitle" id="moveSubject"></p>
<form id="moveForm" class="auth-form" novalidate>
<label class="auth-label">
<span>Folder</span>
<select name="folder_id" id="moveFolderSelect">
<option value="">Uncategorized</option>
</select>
</label>
<button type="submit" class="auth-btn">Move</button>
<div id="moveError" class="auth-error hidden"></div>
</form>
</div>
</div>
<script src="/app.js"></script>
</body>
</html>