KD5RYN/pst-search

GitHub: KD5RYN/pst-search

本地化 Outlook PST 文件搜索工具,解决数据本地化搜索难题。

Stars: 1 | Forks: 0

# PST 搜索 Outlook PST 文件的本地搜索引擎。一次性索引,然后可以通过主题、正文、发件人、收件人、文件夹或日期进行搜索,并按需直接从源 PST 中提取附件。基于 SQLite FTS5 构建以实现即时全文搜索。 ![PST 搜索 UI — 文件夹树,搜索结果,消息详情](https://static.pigsec.cn/wp-content/uploads/repos/2026/06/63ed23db72104523.png) ## 适用于什么 `pst-search` 适用于拥有一个或多个 Outlook `.pst` 文件并需要实际搜索它们的人——无需安装 Outlook,无需上传存档到云服务,也无需编写一次性脚本。 它解决的常见情况: - **旧的邮箱存档。** 来自以前的工作、已退休的帐户或长时间运行的个人邮箱的电子邮件。PST 存储在某个驱动器上,您想在其中找到东西。 - **恢复和查找。** 某人给你一个 `.pst` 文件,并问“有没有关于 X 的电子邮件?”或“找到 Bob 在 2024 年的所有邮件。”你指向这个工具,工具告诉你。 - **转发特定消息。** 将单个旧电子邮件作为标准 `.eml` 文件(包含所有附件)提取出来,然后将其放入任何邮件客户端以转发、存档或附加到工单。 - **法医、发现或合规工作。** 在文件夹、发件人、收件人、附件和日期范围内进行结构化搜索。多 PST 库,您可以索引一系列存档并将它们一起搜索。 - **注重隐私的搜索。** 所有操作都在 `127.0.0.1` 上运行。数据不会离开机器,无需帐户,PST 文件永远不会上传到任何地方。 ### 为什么需要新工具? 大多数 Python 工具都基于 `libpff`,它有一个长期未修复的解析错误(`libpff_table_read: invalid table - missing data identifier`),这使得它无法读取某些现实世界的 PST 文件——尤其是那些由 Outlook 最新版本导出的 PST 文件。我们在一个真实的 8 GB 邮箱上遇到了这个问题,其中 libpff 无法读取任何消息。`pst-search` 通过一个独立的代码库(`pst-extractor`,`java-libpst` 的 Node.js 版本)进行路由,因此即使 libpff 无法读取的 PST 仍然可以在这里打开。 ## 功能 - **全文搜索**主题、正文、发件人、收件人和文件夹路径。FTS5 排名,带有 `` 突出显示的片段。 - **Gmail 风格的操作符**在搜索框中:`from:bob`、`to:alice`、`subject:budget`、`body:meeting`、`folder:inbox`,结合 `AND`/`OR`/`NOT`、引号短语、前缀匹配(`meet*`)和括号。点击搜索框旁边的 **?** 查看完整的作弊单。 - **浏览模式**——留空搜索框以按最新顺序列出消息;点击树中的任何文件夹以过滤到它。 - **按日期或相关性排序**——结果列表标题中的下拉菜单在最新(默认)、最早和相关性(搜索查询的 BM25 排名)之间切换。 - **过滤器**:发件人、收件人、文件夹、日期范围、附件。 - **懒加载附件**——索引仅存储文件名和大小。点击附件将重新打开 PST 并按需提取该文件。无需在磁盘上存储多 GB 的附件。 - **导出到 `.eml`**——每条消息都有一个下载按钮,可以生成一个标准的 RFC 5322 `.eml` 文件,包含标题、正文(纯文本 + HTML)和所有附件。在 Outlook、Thunderbird、Apple Mail 或任何网络邮件上传中打开。 - **一个索引中的多个 PST**。重新索引 PST 将替换其索引中的行。 - **仅本地**——所有操作都在 `127.0.0.1` 上运行。数据不会离开您的机器。 ## 要求 `pst-search` 在可以进行任何有用操作之前需要在机器上安装 **两个运行时**: - **Python 3.10 或更高版本**——索引器、搜索 API 和 CLI。 - **Node.js 18 或更高版本**——PST 解析器(`pst-extractor`)作为 Node 子进程运行。`npm` 随 Node 一起发货。 | | Windows | macOS | Linux (Ubuntu/Debian) | | --- | --- | --- | --- | | Python 3.10+ | `winget install Python.Python.3.12` | `brew install python@3.12` | `sudo apt install python3 python3-pip python3-tk python3-venv` | | Node.js 18+ | `winget install OpenJS.NodeJS.LTS` | `brew install node` | `sudo apt install nodejs npm` | ## 快速入门 ### 从 PyPI 安装 ``` pip install pst-search pstsearch setup # one-time: pulls down the Node-side pst-extractor library pstsearch serve ``` `pstsearch setup` 是 `npm install` 的包装器,用于捆绑的 Node 辅助程序。如果您跳过它,第一次索引运行将自动为您安装依赖项。 ### …或从源安装 ``` # 如果已安装 Git: git clone https://github.com/KD5RYN/pst-search cd pst-search pip install -e . (cd pst_search/node && npm install) pstsearch serve ``` …或从 (绿色 **代码** 按钮 → **下载 ZIP**)下载作为 ZIP 文件,然后解压,`cd` 到文件夹中,并运行相同的两个安装命令。 在 Windows PowerShell 中,第二个安装行是: ``` cd pst_search\node; npm install; cd ..\.. ``` ### 运行 ``` pstsearch serve ``` 浏览器标签页将在 打开。 1. 点击 **📁 管理PST → + 添加另一个PST** 2. 在原生对话框中选择您的 `.pst` 文件 3. **调整索引选项**(或接受默认值)并点击 **开始索引** 4. 一旦第一批到达,就可以立即搜索;其余的会随后流式传输 完成时,进行搜索。 搜索索引位于您的用户数据目录中: - Windows:%APPDATA%\pst-search\index.db - macOS:`~/Library/Application Support/pst-search/index.db` - Linux:`$XDG_DATA_HOME/pst-search/index.db`(默认 `~/.local/share/pst-search/index.db`) 删除该文件以擦除索引并重新开始。 ## 搜索语法 搜索框接受大多数用户已经从 Gmail 和 Outlook 熟悉的相同操作符,以及 SQLite FTS5 的所有原生查询语言。 **操作符:** | 类型 | 意义 | | --- | --- | | `from:bob` | 发件人姓名或电子邮件包含单词“bob” | | `to:alice` | 任何收件人(To/Cc/Bcc)包含单词“alice” | | `subject:budget` | 匹配限制在主题上 | | `body:meeting` | 匹配限制在正文上 | | `folder:inbox` | 文件夹路径包含单词“inbox” | | `cc:` / `bcc:` | 收件人(我们不区分 To/Cc/Bcc) | **组合:** | 形式 | 意义 | | --- | --- | | `a b` | 两个单词都存在(隐式 AND) | | `a AND b` | 两个——明确 | | `a OR b` | 任何一个 | | `a NOT b` | a 但不是 b | | `"q4 plan"` | 精确短语 | | `meet*` | 前缀——匹配单词的开头:meeting、meetup、meets、…(需要匹配部分单词) | | `(a OR b) AND c` | 带括号的组 | **示例:** `from:bob AND subject:budget NOT folder:trash` — Bob 关于预算的电子邮件,但不包含任何垃圾文件夹。 点击搜索框右边缘的 **?** 图标以查看此作弊单的弹出版本。 ## 索引选项 “添加 PST”对话框和 `pstsearch index` CLI 命令都公开了相同的三个旋钮。默认值适用于几乎每个邮箱;只有在默认值不适合您的数据时才进行调整。 | 选项 | GUI 标签 | CLI 标志 | 默认值 | 何时更改 | | --- | --- | --- | --- | --- | | 包含消息正文 | _索引消息正文_(复选框) | `--no-body` | 开启 | 关闭以用于 **巨大的存档**,当您只需要按主题/发件人搜索时——索引速度会显著提高。 | | 保留的最大正文长度 | _每条消息的最大正文长度_ | `--body-cap KB` | 32 KB | 如果您的真实内容电子邮件通常运行更长,则提高(最高 1024 KB);降低以缩小索引。 | | 跳过非常大的消息的正文 | _跳过大于_ | `--max-html-fetch MB` | 4 MB | 如果您想忽略巨大的新闻通讯风格的邮件,则降低;如果您特别希望从巨大的消息中获取正文文本,则将其提高到 100 MB。 | 在添加 PST 对话框中打开 **高级选项** 展开项以查看和调整最后两个。 ## 应用设置(⚙️ 按钮) 点击页眉中的齿轮图标以查看服务器当前正在做什么: - **监听地址**——服务器绑定的 URL - **网络访问**——确认您是本地-only 还是公开 - **索引数据库**——SQLite 文件所在位置,有一个 **打开数据文件夹** 按钮 这些是只读的,因为更改它们需要重新启动服务器。要更改它们,请向 `pstsearch serve`(见下文)传递标志。 ## 命令 ``` pstsearch serve [--host HOST] [--port PORT] [--db PATH] [--no-browser] Launch the web UI. Defaults: --host 127.0.0.1 --port 8765. Pass --host 0.0.0.0 to expose to your LAN (DO NOT do this on an untrusted network — anyone reaching the port can search your mail). pstsearch index FILE.pst [--no-body] [--body-cap KB] [--max-html-fetch MB] [--db PATH] Index a PST from the command line. Re-running on the same file replaces its rows. Options mirror the GUI Add-PST dialog. pstsearch list Show indexed PSTs (id, message count, path, indexed-at). pstsearch setup One-time install of the Node-side dependencies (pst-extractor and friends). Safe to re-run. Indexing will auto-bootstrap these on first use if you forget, so this command is mostly for users who want the install to happen up front rather than the first time they hit "Index". ``` ## 架构 ``` PST file --[Node + pst-extractor]--NDJSON--> Python indexer --[SQLite + FTS5]--> Search API --[HTML/JS]--> Browser | (on attachment click, spawn Node, extract one attachment by descriptor node ID) ``` | 层 | 文件 | 目的 | | --- | --- | --- | | PST 提取器 | `pst_search/node/extract.mjs` | 使用 `pst-extractor` 遍历 PST,每条消息流出一个 NDJSON 记录到 stdout。 | | 附件提取器 | `pst_search/node/attachment.mjs` | 通过描述符节点 ID 从 PST 中提取单个附件的字节。 | | 消息转储 | `pst_search/node/message.mjs` | 完整消息导出(标题 + 两种正文形式 + 每个附件)用于 `.eml` 构建。 | | Python 驱动程序 | `pst_search/pst.py` | 启动 Node,解析 NDJSON,公开 Python 迭代器、附件获取和完整消息导出。 | | 索引器 | `pst_search/indexer.py` | 消费消息流并将批量插入到 SQLite 中。 | | 索引作业 | `pst_search/jobs.py` | 背景索引线程 + 作业注册表。允许 Web UI 触发扫描并轮询进度。 | | 数据库 | `pst_search/db.py` | 架构 + FTS5 虚拟表 + 搜索/浏览查询 + Gmail 风格操作符转换。 | | 服务器 | `pst_search/server.py` | FastAPI 端点——见下文。 | | Web UI | `pst_search/web/index.html` | 单文件前端(HTML + 内联 CSS + JS),无需构建步骤。 | | CLI | `pst_search/cli.py` | `index` / `serve` / `list` 入口点。 | **HTTP API:** | 端点 | 方法 | 目的 | | --- | --- | --- | | `/api/search` | GET | 带筛选和排序的 FTS5 搜索。 | | `/api/folders` | GET | 唯一文件夹路径和消息计数(用于树)。 | | `/api/psts` | GET | 索引的 PST 列表。 | | `/api/psts/{pst_id}` | DELETE | 从索引中删除 PST。 | | `/api/pick-pst` | POST | 打开原生操作系统文件选择器对话框并返回选择的路径。 | | `/api/index` | POST | 启动后台索引作业。正文:`{path, options?}`。 | | `/api/jobs` / `/api/jobs/{id}` | GET | 作业进度轮询。 | | `/api/settings` | GET | 运行时配置(主机、端口、数据库路径、本地-only 标志)。 | | `/api/open-data-folder` | POST | 在操作系统文件管理器中打开索引 DB 文件夹。 | | `/api/message/{id}` | GET | 消息元数据和附件列表。 | | `/api/message/{id}/export.eml` | GET | 将消息作为标准 `.eml` 文件下载。 | | `/api/attachment/{msg}/{idx}` | GET | 从源 PST 中流式传输一个附件的字节。 | ## 性能说明 - 索引吞吐量在大约 35 条消息/秒。一个 8 GB / 27K 条消息的 PST 使用默认选项需要大约 13 分钟。 - 默认正文容量为每条消息 32 KB——大约 5,000+ 个单词,远远超过正常通信的长度。营销电子邮件包含数百 KB 的 HTML,但有用的内容(问候语、报价、号召行动)始终在前几个 KB 中。在添加 PST 对话框或通过 `--body-cap KB` 调整。 - 默认情况下,总大小超过 4 MB 的消息将完全跳过正文提取(主题/发件人/收件人/文件夹仍然索引)。在典型的邮箱中,这会影响不到 1% 的消息。通过 `--max-html-fetch MB` 调整。 - 完全跳过正文提取(`--no-body` 或取消选中 _索引消息正文_)使得对大型存档的索引速度显著提高,其中只有标题级别的搜索很重要。 - 收件人是从 `transportMessageHeaders` 解析的,而不是 `pst-extractor` 的 `getRecipient()` API,后者对每个收件人进行磁盘访问,在大型 PST 上主导索引时间(测量为 120 ms/消息,而标题解析几乎)。 - 附件下载和 `.eml` 导出每个都会启动一个新的 Node 进程(每次点击的延迟约为 100–300 毫秒)。适用于一次性使用;不是为批量导出而构建的。附件字节永远不会存储在索引中——它们按需直接从 PST 中流式传输。 ## 许可证 `pst-search` 是 MIT 许可的(见 `LICENSE`)。第三方依赖项及其许可证列在 `THIRD_PARTY_LICENSES.md` 中。 ## 关于“受密码保护”的 PST 文件的说明 Outlook 允许您对 PST 设置密码。尽管名称如此,**这并不是消息内容的加密**——它是在 PST 标头中存储的哈希,Outlook 在打开文件之前会检查它。实际的消息和附件以明文形式存储(或使用每个 PST 库都可以透明处理的弱公共字节置换密码)。 这意味着: - `pst-search` 无需请求密码即可读取受密码保护的 PST,因为底层解析器(pst-extractor)不遵守
标签:MITM代理, 逆向工具