# crx-manifest-parser
[](https://crates.io/crates/crx-manifest-parser)
[](https://docs.rs/crx-manifest-parser)
Parse a Chrome / Chromium **Manifest V3** `manifest.json` string into a
strongly-typed [`Manifest`](https://docs.rs/crx-manifest-parser) struct
exposing the fields an extension security scanner actually cares about:
- `name`, `version`, `description`, `manifest_version`
- `permissions` and `optional_permissions` (named API tokens)
- `host_permissions` (match-patterns granting site access)
- `content_scripts` (the script + match list — the biggest cross-origin
exposure surface)
Pure Rust, **zero dependencies** (no `serde`, no `serde_json`), `#![forbid(unsafe_code)]`.
Ships its own minimal, fully-tested JSON value parser so a manifest can be
decoded without dragging a JSON library into the build graph.
This is the manifest-decode layer behind the [**zovo.one**](https://zovo.one/)
Chrome-extension privacy & security scanner, which audits the permissions
requested by any installed extension and flags the ones that can read your
data across every site.
## Why parse the manifest
The `manifest.json` is the single source of truth for what an extension is
allowed to do. Two extensions that both "just change your new tab page" can
declare wildly different access: one asks for `storage`, the other for
`<all_urls>` + `cookies` + content scripts on every site. The manifest is the
first thing a privacy review opens — this crate turns it into a typed value
you can branch on, render, or feed to a permission auditor (see the
companion [`permission-auditor`](https://crates.io/crates/permission-auditor)
crate).
## Install
```toml
[dependencies]
crx-manifest-parser = "0.1"
```
## Quick start
```rust
use crx_manifest_parser::Manifest;
let json = r#"{
"manifest_version": 3,
"name": "My Extension",
"version": "1.4.2",
"permissions": ["activeTab", "storage"],
"host_permissions": ["https://*.example.com/*"],
"content_scripts": [
{ "matches": ["https://*.example.com/*"], "js": ["content.js"] }
]
}"#;
let manifest = Manifest::from_json(json).expect("valid manifest");
assert_eq!(manifest.name.as_deref(), Some("My Extension"));
assert_eq!(manifest.manifest_version, Some(3));
assert_eq!(manifest.permissions, ["activeTab", "storage"]);
assert_eq!(manifest.host_permissions, ["https://*.example.com/*"]);
assert_eq!(manifest.content_scripts.len(), 1);
assert!(manifest.is_mv3());
// The full set of grant tokens, ready for a permission auditor.
assert_eq!(manifest.all_grants(), ["activeTab", "storage", "https://*.example.com/*"]);
```
## API surface
| `Manifest` | Typed struct over the security-relevant fields. |
| `ContentScript` | One `content_scripts` entry (`matches`, `js`, `css`, ...). |
| `Manifest::from_json(s)` | Parse a manifest string into a `Manifest`. |
| `Manifest::from_json_value(&v)` | Build from an already-parsed `Json` value. |
| `Manifest::all_grants()` | `permissions` + `host_permissions` concatenated. |
| `Manifest::content_match_patterns()` | Deduped site match-patterns across all content scripts. |
| `Manifest::is_mv3()` / `is_mv2()` | Manifest-version predicates. |
| `Json`, `ParseError` | The bundled JSON value model + parse error. |
## Design choices
- **Zero dependencies.** No `serde`, no `serde_json`. The crate carries a
small recursive-descent JSON parser so it works in any sandboxed or
constrained build context.
- **Missing fields are tolerated.** Manifests routinely omit keys; a missing
`permissions` array is an empty `Vec`, not an error. A parse error only
fires for malformed JSON or a field with the wrong JSON type (e.g.
`permissions` given as a string).
- **No `unsafe`.** `#![forbid(unsafe_code)]` — there is no unsafe anywhere
in the crate.
- **UTF-8 and escape fidelity.** Strings are decoded with full
`\uXXXX` / surrogate-pair / `\b \f \n \r \t` handling, and raw control
characters are rejected (per RFC 8259) so a manifest can't smuggle
unescaped control bytes.
## License
MIT.
## Links
- **zovo.one** — the Chrome-extension privacy & security scanner that
uses this parser: <https://zovo.one/>
- Source (zovo monorepo): <https://github.com/theluckystrike/zovo>
- Full API docs: <https://docs.rs/crx-manifest-parser>