firecrawl / firecrawl/anydoc

Accept a password for encrypted OOXML files instead of terminating at `Encrypted`

Open
#102 2 comments 0 reactions 0 assignees View on GitHub
enhancement P2
Dominant language
Rust
Stars
21.5k
Forks
1.3k
Avg merge
42m
Merged PRs (30d)
17

Description

## Summary

A password-protected `.xlsx`/`.docx`/`.pptx` always ends in `ConvertError::Encrypted`, and there is no way to supply the password. The rejection is precise and deliberate today: `probe_ole` (`src/package/archive.rs`) identifies the OLE container with `EncryptionInfo`/`EncryptedPackage` streams and returns `Encrypted`.

For a caller that *has* the password, the file is still unconvertible.

## Why this matters

Document-ingestion pipelines (the LLM/RAG use case the README targets) receive password-protected spreadsheets and documents routinely, and the password is usually known: it arrived alongside the file.

Rust users can already work around this by composing the `office-crypto` crate with `to_markdown_bytes`:

```rust
let decrypted = office_crypto::decrypt_from_bytes(std::fs::read(path)?, "secret")?;
let md = anydoc::to_markdown_bytes(&decrypted, None)?;
```

But Node, Python, wasm, and CLI users have no equivalent: there is no solid OOXML-decryption library on those sides, so for the bindings the file is a dead end.

## Proposed shape (narrowest version)

- An optional password on the byte-level entry points, e.g. `to_markdown_bytes(bytes, format, password: Option<&str>)` or `_with_password` variants, mirrored in the bindings.
- CLI: `--password ` (plus perhaps an env-var fallback, since argv leaks into shell history and `ps`).
- Where `probe_ole` currently returns `Encrypted`: if a password was supplied, decrypt via `office-crypto` and re-enter `Format::from_bytes` -> conversion with the plaintext. All existing resource limits then apply to the decrypted package unchanged. No password supplied, or wrong password: `Encrypted`, exactly as today.

`office-crypto` (v0.3.0) is pure Rust, its dependencies are all RustCrypto crates plus `quick-xml` (already a dependency here), and decryption needs no randomness, so the wasm target should be unaffected. Decryption cost is milliseconds.

## Out of scope

- Legacy encrypted `.xls`/`.ppt` (RC4 CryptoAPI): not supported by office-crypto; would keep returning `Encrypted`.
- Encrypted ODF: a different scheme entirely; would keep returning `Encrypted`.

---

*This issue was written with AI assistance (Claude Fable 5).*

Contributor guide

No contributing guide indexed for this repository

Research direction

Read src/package/archive.rs, especially probe_ole and the Format::from_bytes conversion path; then inspect the byte-level entry points and binding and CLI surfaces named by the issue. Check how existing errors and resource limits are propagated before settling the password API. Done means supplied-password OOXML reaches conversion, while missing or wrong passwords and out-of-scope encrypted formats retain Encrypted behavior.

Written by the indexing model from the issue text.

Assessment

Tech stack
node.js, python, rust, wasm
Domain
api, cli, security
Issue type
Feature
Difficulty
5/5
Estimated time
Over a week
Activity status
Quiet
Clarity
Mostly clear
Newbie friendliness
38/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.