Metadata-Version: 2.4
Name: larzarchive
Version: 0.1.0
Summary: Create and extract zip/tar archives with safe (zip-slip-proof) extraction by default. Pure Python, zero dependencies.
Author: larz-scripter
License: MIT
Project-URL: Homepage, https://github.com/larz-scripter/larzarchive
Project-URL: Repository, https://github.com/larz-scripter/larzarchive
Project-URL: Issues, https://github.com/larz-scripter/larzarchive/issues
Keywords: archive,zip,tar,zip-slip,extraction,security,tarfile,zipfile,compression,zero-dependency
Classifier: Development Status :: 4 - Beta
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: MIT License
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.8
Classifier: Programming Language :: Python :: 3.9
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Topic :: Software Development :: Libraries :: Python Modules
Requires-Python: >=3.8
Description-Content-Type: text/markdown
License-File: LICENSE
Dynamic: license-file

# larzarchive

**zip/tar with safe extraction. Pure Python, zero dependencies.**

Extracting an untrusted archive is a classic vulnerability: a member named
`../../etc/cron.d/x` or an absolute path escapes the destination ("Zip Slip").
larzarchive refuses those by resolving every member's real path and checking it
stays inside the target - and it skips symlink/device members in tars. A clean
create/extract/list API over the standard library, auto-detecting format.

```python
from larzarchive import create, extract, listing

create("bundle.zip", "myfolder")
create("bundle.tar.gz", ["a.txt", "b.txt"])
extract("bundle.zip", "out/")        # raises UnsafeArchive on a malicious member
listing("bundle.zip")
```

## Why

- **Safe by default.** `extract()` validates every member's resolved path against
  the destination, so path-traversal ("Zip Slip") archives raise `UnsafeArchive`
  instead of overwriting files outside the target. It also skips symlink/hardlink/
  device entries in tars. (`safe=False` is a documented escape hatch.)
- **One API, every format.** zip, tar, tar.gz, tar.bz2, tar.xz - detected from the
  filename. `create` takes a directory, a single file, or a list of paths (or
  `(path, arcname)` pairs).
- **Zero dependencies.** A thin, hardened layer over `zipfile`/`tarfile`.

## Install

```bash
pip install larzarchive
```

## Usage

```python
from larzarchive import create, extract, listing

create("release.tar.gz", "dist")               # a directory
create("files.zip", ["a.txt", "b.txt"])         # a list of files
listing("release.tar.gz")                       # -> member names
paths = extract("release.tar.gz", "unpacked/")  # safe; returns extracted paths
```

## Tests

```bash
python -m unittest discover -s tests -v   # 7 tests incl. zip-slip + tar-slip rejection
```

## The Larz stack

One of 30+ pure-Python, zero-dependency libraries at
[github.com/larz-scripter](https://github.com/larz-scripter).

## License

MIT (c) larz-scripter
