Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
91da98f
fix: resolve linting issues and pyproject.toml duplicate key
Sparkleeop Aug 19, 2026
a788ac1
Merge branch 'main' into fix/linting-fixes
Sparkleeop Aug 19, 2026
b0fc9d4
fix: migrate ruff config to [tool.ruff.lint] section
Sparkleeop Aug 19, 2026
cf7893a
fix: correct setuptools packages.find config to fix pip install -e .
Sparkleeop Aug 19, 2026
42ec9f6
fix: install setuptools and wheel for no-isolation build in Docker
Sparkleeop Aug 19, 2026
a2060db
fix: add .dockerignore to exclude local build artifacts from docker c…
Sparkleeop Aug 19, 2026
6804d1b
fix: use isolated build in Docker to avoid stale bundled setuptools
Sparkleeop Aug 19, 2026
46847b0
fix: run docker image without redundant stash arg (entrypoint already…
Sparkleeop Aug 19, 2026
1866df8
docs: add complete documentation suite
Sparkleeop Aug 19, 2026
4f68d21
chore: stop tracking coverage.xml, add to gitignore
Sparkleeop Aug 19, 2026
3759301
docs: add releasing guide
Sparkleeop Aug 20, 2026
753fa4e
docs: trigger CI
Sparkleeop Aug 20, 2026
95ec659
resolve: merge main (remove coverage.xml)
Sparkleeop Aug 20, 2026
bd6b221
feat: implement repository master key (RMK) hierarchy with keyring st…
Sparkleeop Aug 20, 2026
b62f130
update version string
Sparkleeop Aug 20, 2026
309ac8f
fix: fix unlock flow for locked repositories
Sparkleeop Aug 20, 2026
90af30b
docs: update README, docs, requirements.txt for RMK-based key management
Sparkleeop Aug 20, 2026
c2a1d7f
docs: update README to enhance image display and alignment
Sparkleeop Aug 20, 2026
6ea8d9f
docs: update README for improved layout and badge links
Sparkleeop Aug 20, 2026
beb0bca
docs: remove fake claims from README and docs - be honest about what'…
Sparkleeop Aug 20, 2026
c6a5cbb
docs: remove test_restored.md to eliminate outdated content
Sparkleeop Aug 20, 2026
a398a8d
merge: resolve conflicts with main (keep cleaned-up docs)
Sparkleeop Aug 20, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
314 changes: 47 additions & 267 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,19 +40,19 @@ Files are encrypted locally, split into chunks, and uploaded as ciphertext. Chun
Storage Engine
┌─────────────┴─────────────┐
│ │
Encryption Chunking
│ │
└─────────────┬─────────────┘
Storage Router
┌─────────────┴─────────────┐
│ │
Telegram Discord
│ │
encrypted chunks encrypted chunks
┌─────────────┴─────────────┐
│ │
Encryption Chunking
│ │
└─────────────┬─────────────┘
Storage Router
┌─────────────┴─────────────┐
│ │
Telegram Discord
│ │
encrypted chunks encrypted chunks
```

Stashify does **not** provide the underlying storage.
Expand All @@ -72,10 +72,8 @@ Stashify separates those concepts.
| Vendor lock-in | Provider-agnostic storage abstraction |
| Provider sees plaintext | Files are encrypted before upload |
| Large files | Automatic chunking |
| Provider-specific limits | Provider-aware chunking and routing |
| Provider-specific limits | Provider-aware chunking |
| Single provider dependency | Multi-provider storage |
| Interrupted uploads | Resumable operations |
| Manual file management | Unified CLI/TUI |
| Provider-specific APIs | One consistent interface |

---
Expand All @@ -98,7 +96,7 @@ Your files are encrypted **before they leave your device**.
Chunking
Encrypted ciphertext
Encrypted ciphertext
┌──────────┴──────────┐
▼ ▼
Expand Down Expand Up @@ -200,69 +198,6 @@ Ready

---

## Why Stashify?

Traditional cloud storage usually means trusting one provider with both your data and your storage.

Stashify separates those concepts.

| Problem | Stashify |
| -------------------------- | ------------------------------------- |
| Vendor lock-in | Provider-agnostic storage abstraction |
| Provider sees plaintext | Files are encrypted before upload |
| Large files | Automatic chunking |
| Provider-specific limits | Provider-aware chunking and routing |
| Single provider dependency | Multi-provider storage |
| Interrupted uploads | Resumable operations |
| Manual file management | Unified CLI |
| Provider-specific APIs | One consistent interface |

---

## Features

### Client-side encryption

Your files are encrypted **before they leave your device**.

```text
YOUR DEVICE
Plaintext
Encryption
Chunking
Encrypted ciphertext
┌──────────┴──────────┐
▼ ▼
Telegram Discord
```

Storage providers should only receive ciphertext.

Stashify is designed around:

* Client-side encryption
* Authenticated encryption (AEAD)
* Per-file cryptographic keys
* Proper key derivation
* Cryptographically secure randomness
* No custom cryptographic primitives
* Authenticated chunk integrity
* Local key management

Stashify uses established cryptographic libraries rather than implementing cryptography from scratch.

> **Security note:** Stashify does not claim that multi-provider storage makes encryption stronger. Confidentiality comes from the cryptographic design and key management. Multi-provider storage primarily provides distribution, redundancy, and provider independence.

---

## Chunked storage

Large files are automatically split into manageable chunks.
Expand Down Expand Up @@ -290,30 +225,16 @@ The storage engine can account for provider-specific upload limitations without

## Multi-provider storage

Stashify can distribute a file across multiple storage providers.
Stashify can store files across multiple storage providers. Currently only the **Single** strategy is implemented (all chunks on one provider). Additional strategies are planned.

For example:
Current strategies:

```text
100 encrypted chunks

Telegram:
0 2 4 6 8 10 12 ...

Discord:
1 3 5 7 9 11 13 ...
```

Multiple storage strategies are planned:

| Strategy | Description |
| -------------- | ----------------------------------------------------- |
| **Single** | Store all chunks on one provider |
| **Split** | Distribute chunks across multiple providers |
| **Balanced** | Dynamically distribute chunks based on provider state |
| **Replicated** | Store copies across multiple providers |

This allows Stashify to build storage around the providers available to you instead of forcing you into a single backend.
| Strategy | Status | Description |
| -------------- | ------------ | ----------------------------------------------------- |
| **Single** | ✅ Implemented | Store all chunks on one provider |
| **Split** | 🚧 Planned | Distribute chunks across multiple providers |
| **Balanced** | 🚧 Planned | Dynamically distribute chunks based on provider state |
| **Replicated** | 🚧 Planned | Store copies across multiple providers |

---

Expand Down Expand Up @@ -348,159 +269,17 @@ Planned providers include:

---

## Asynchronous transfers

Stashify is designed around asynchronous I/O.

Large uploads can consist of hundreds or thousands of chunks, so operations should run concurrently with bounded workers.

```text
Upload Queue
┌───────────┼───────────┐
▼ ▼ ▼
Worker 1 Worker 2 Worker 3
│ │ │
Telegram Discord Telegram
```

The transfer system is designed to support:

* Concurrent uploads
* Concurrent downloads
* Bounded concurrency
* Retries
* Exponential backoff
* Provider-aware rate limiting
* Cancellation
* Progress reporting
* Failed-job tracking
* Resumable operations

---

## Resumable uploads

Interrupted transfers shouldn't mean starting from zero.

```text
200 chunks

chunk 000 ✓
chunk 001 ✓
chunk 002 ✓
...
chunk 147 ✓
chunk 148 ✗
chunk 149 ✗
...
```

Stashify keeps track of individual chunks so completed work can be preserved across interruptions.

---

## Integrity verification

Encrypted chunks are authenticated and tracked using local metadata.

Stashify is designed to detect:

* Missing chunks
* Corrupted chunks
* Modified ciphertext
* Incomplete downloads
* Invalid manifests
* Incorrect chunk ordering
* Failed reconstruction

The final reconstructed file can also be verified against file-level integrity information.

---

## Manifest-based storage

Every stored file has a manifest describing how it can be reconstructed.

Conceptually:

```text
File
├── ID
├── Original name
├── Original size
├── Chunk size
├── Chunk count
├── Encryption metadata
├── Integrity information
└── Chunks
├── 0 → Telegram → remote ID
├── 1 → Discord → remote ID
├── 2 → Telegram → remote ID
└── ...
```

Local metadata is stored in `.stash/metadata/`.

---

## CLI

Stashify can be used entirely from the command line.

```bash
# Initialize (generates RMK, stores in OS keyring, shows recovery key)
stash init

# Configure providers
stash provider add telegram
stash provider add discord

# List providers
stash provider list

# Upload (no password prompt — uses RMK from keyring)
stash put ./movie.mkv

# List stored files
stash ls

# Inspect a file
stash info movie.mkv

# Download (no password prompt)
stash get movie.mkv

# Delete
stash rm movie.mkv

# Verify
stash verify movie.mkv

# Check status
stash status

# Key management
stash key-commands status
stash key-commands lock
stash key-commands unlock --recovery-key <hex>
stash key-commands recovery
```

---

## Provider Support

| Provider | Status |
| ---------------- | -------------- |
| Telegram | Implemented |
| Discord | Implemented |
| S3-compatible | Planned |
| Backblaze B2 | Planned |
| Google Drive | Planned |
| Local filesystem | Planned |
| WebDAV | Planned |
| Telegram | ✅ Implemented |
| Discord | ✅ Implemented |
| S3-compatible | 🚧 Planned |
| Backblaze B2 | 🚧 Planned |
| Google Drive | 🚧 Planned |
| Local filesystem | 🚧 Planned |
| WebDAV | 🚧 Planned |

Provider availability and capabilities are subject to the APIs, limits, and policies of the respective services.

Expand Down Expand Up @@ -594,7 +373,7 @@ At a high level:
┌────────────┼────────────┐
▼ ▼ ▼
Telegram Discord Future
Providers
Providers
```

The architecture intentionally separates:
Expand All @@ -620,20 +399,20 @@ The architecture is being actively developed and APIs may change significantly.
| Component | Status |
| ---------------------- | ----------- |
| Project architecture | In progress |
| Python CLI | In progress |
| Encryption | Implemented |
| Chunking | Implemented |
| Manifest / metadata | Implemented |
| Provider abstraction | In progress |
| Telegram provider | Implemented |
| Discord provider | Implemented |
| Async job engine | Implemented |
| **Key management (RMK)** | **Implemented** |
| Resumable transfers | Planned |
| Multi-provider routing | Planned |
| Verification | Planned |
| Repair / recovery | Future |
| Additional providers | Future |
| Python CLI | ✅ Implemented |
| Encryption | Implemented |
| Chunking | Implemented |
| Manifest / metadata | Implemented (JSON) |
| Provider abstraction | ✅ Implemented |
| Telegram provider | Implemented |
| Discord provider | Implemented |
| Async job engine | Implemented |
| Key management (RMK) | ✅ Implemented |
| Multi-provider routing | 🚧 Planned |
| Resumable transfers | 🚧 Planned |
| Integrity verification | 🚧 Planned |
| Repair / recovery | 🚧 Planned |
| Additional providers | 🚧 Planned |

Features marked **Planned** or **Future** should not be considered implemented.

Expand Down Expand Up @@ -678,12 +457,13 @@ The long-term goal is to turn Stashify into a flexible encrypted storage layer t

* [x] Core encryption pipeline
* [x] Chunking
* [x] SQLite metadata
* [x] JSON metadata
* [x] Telegram provider
* [x] Discord provider
* [x] Async transfer system
* [x] **Repository Master Key (RMK) hierarchy**
* [ ] Resumable uploads
* [ ] Multi-provider routing

### Medium term

Expand Down
Loading