@nightowne/tas-cli 2.4.1 → 3.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md ADDED
@@ -0,0 +1,162 @@
1
+ # Changelog
2
+
3
+ All notable changes to TAS (Telegram as Storage) will be documented in this file.
4
+
5
+ ## [3.0.1] - 2026-09-25
6
+
7
+ ### Fixed — current macFUSE mount support (#4)
8
+ - **System macFUSE build** — TAS no longer accepts the bundled OSXFUSE 3 library. On macOS it detects `/Library/Filesystems/macfuse.fs`, selects the installed `libfuse` headers and library, and rebuilds the optional `fuse-native` addon for the active CPU.
9
+ - **Apple Silicon support path** — the rebuilt addon uses macFUSE's supported v2 API surface rather than the legacy binary with no arm64 slice. TAS never installs, replaces, or removes a FUSE kernel extension.
10
+ - **Strict runtime guard** — TAS inspects the loaded native addon and refuses mount if it still links to `libosxfuse` or lacks a system-macFUSE build. `tas doctor` then performs the real mount → readdir → unmount smoke test.
11
+ - **Install guidance** — macOS requires current macFUSE and Xcode Command Line Tools before TAS is installed. A failed native build leaves push, pull, sync, and share available while mount stays disabled.
12
+
13
+ ## [3.0.0] - 2026-09-24
14
+
15
+ ### Fixed — FUSE and path correctness
16
+ - **Nested virtual directory tree (#3)** — sync-style names such as `subdir/file.txt` are now exposed as implicit directories. `readdir()` returns immediate children only; `getattr()` reports parent directories; file operations use exact normalized logical paths instead of fuzzy/basename lookup.
17
+ - **Disk-backed FUSE writes** — pending writes use private temp files instead of buffering the entire file in Node.js memory.
18
+ - **Safe truncate** — uncached remote content is downloaded before truncation; TAS no longer substitutes an empty buffer and silently destroys the rest of the file.
19
+ - **Duplicate-content paths** — migrated away from the legacy `UNIQUE(hash)` constraint, so identical bytes can exist at different logical paths without orphaning Telegram messages.
20
+ - **Safe unmount** — replaced interpolated shell commands with `execFileSync()` argument arrays.
21
+
22
+ ### Changed — platform support (#4)
23
+ - **macOS mount is explicitly unsupported** in this release. `fuse-native@2.x` targets obsolete OSXFUSE APIs and is not considered compatible with current macFUSE/Apple Silicon. Push, pull, sync, share, and index recovery remain available.
24
+ - **Real FUSE diagnostics** — `tas doctor` calls `Fuse.isConfigured()` and, on supported Linux hosts, performs a temporary mount → async `readdir` → unmount smoke test. Importing the JS module alone no longer counts as success.
25
+
26
+ ### Added — multi-bot and recovery
27
+ - **Config v3 bot pool** — `tas bot add/list/enable/disable/remove`, stable bot IDs, deterministic per-chunk routing, persisted `bot_id`, safe reads/deletes through the owning bot, and v1/v2 single-bot compatibility.
28
+ - **Explicit risk gate** — multi-bot setup requires acknowledgement and warns that it does not guarantee quota, durability, ban avoidance, or Terms compliance and must not be used to evade limits.
29
+ - **Encrypted remote manifest** — completed storage mutations publish a gzip-compressed AES-256-GCM manifest for files, chunks, ownership, and tags; ephemeral share tokens are excluded. `tas index backup` refreshes it and `tas index rebuild` authenticates and restores `index.db` while preserving a local backup.
30
+ - **Real resumable uploads** — encrypted chunks are staged on disk before network transfer, and normal uploads populate `pending_uploads`/`pending_chunks`. `tas resume` now continues actual interrupted uploads across bots.
31
+
32
+ ### Security and protocol correctness
33
+ - **Opaque chunk metadata** — new uploads omit filename and original size from Telegram-visible WAS1 headers, use generic document names, and use opaque captions. Legacy chunks remain readable.
34
+ - **Hosted Bot API round-trip safety** — payload chunks are 19 MiB so the full document remains below the documented 20 MB `getFile` download limit. `tas doctor` flags legacy oversized chunks.
35
+ - **Serialized per-bot sends** — concurrent sync workers share one bot pool and one send queue per bot instead of bursting through independent client limiters.
36
+ - **Honest product claims** — removed “unlimited,” “free forever,” “zero-knowledge,” and “no ban risk” claims. Documentation now states observed metadata, recovery dependencies, Telegram policy risk, and the independent-backup requirement.
37
+
38
+ ### Tests
39
+ - Added nested FUSE path integration tests, legacy schema migration tests, multi-bot routing/ownership tests, send-queue concurrency coverage, resumable-state tests, opaque-metadata tests, and encrypted manifest round-trip/rebuild coverage.
40
+
41
+ ## [2.5.0] - 2026-09-17
42
+
43
+ ### Fixed — reliability (failed uploads no longer brick files)
44
+ - **Atomic uploads** — `processFile` now deletes the partial `files` row + chunk rows + temp chunk if the pipeline throws, so retrying `tas push` no longer hits a phantom `File already uploaded (duplicate hash)`. DB connection is always closed on failure (was leaked).
45
+ - **Foreign keys enforced** — `FileIndex.init()` now sets `PRAGMA foreign_keys = ON` (SQLite disables it per connection), so `ON DELETE CASCADE` for chunks/tags/shares/sync-state actually works. Also sets `busy_timeout = 5000` for concurrent sync workers.
46
+ - **Exact-match lookup first** — `findByName`/`findByHash` now try exact match before LIKE fallback, so duplicate filenames resolve deterministically.
47
+ - **`tas resume` handles leftovers** — detects pre-2.5 incomplete file rows (`getIncompleteUploads`), offers one-shot cleanup, then resumes legacy `pending_uploads`. Finalize no longer hardcodes `compressed: true` or zero chunk sizes.
48
+ - **`tas sync pull` rewritten** — was skipping on mere existence and miscounting across folders. Now skips only when local content hash matches the index, re-pulls modified files, and downloads to the first registered folder.
49
+ - **Linux recursive watch** — `fs.watch({ recursive: true })` is macOS/Windows-only; `SyncEngine` now watches every subdirectory individually and picks up newly created subdirs. Previously subfolder changes were silently missed on Linux.
50
+ - **Sync no longer ignores dotfiles** — the generic `/^\./` ignore dropped `.env`/SSH keys while the README sells TAS as a secrets vault. Only junk (`.DS_Store`, `.git`, `node_modules`, `~`, `.swp`, `.tmp`) is ignored now.
51
+ - **FUSE large files** — `uploadFile` now chunks at 49MB like `tas push` (was single-chunk, so anything >~50MB failed), uploads atomically, cleans up its Telegram messages on failure, and no longer silently no-ops same-content-different-name copies. `rename` overwrites destination cleanly; `truncate` consults the on-disk cache.
52
+ - **Share download counting** — count increments after a successful stream (aborted connections no longer burn single-use links) and responses carry `Content-Length`.
53
+ - **`tas push <files...>`** — batch uploads with per-file results and a summary line; password verified once.
54
+
55
+ ### Added — adoption (time-to-first-success)
56
+ - **Non-interactive `tas init`** — `--token/--chat/--password` flags (plus `TAS_PASSWORD` env). The README's Docker/CI example (`tas init --token … --chat …`) previously referenced flags that didn't exist — now it works.
57
+ - **`tas share create --host`** — bind address flag the 2.4.0 changelog already promised (`--host 0.0.0.0` for LAN). Network URL is only printed when actually reachable, with a warning when bound to all interfaces.
58
+ - **`tas doctor` checks Telegram** — verifies Bot API connectivity when the token is available (plaintext v1, or v2 with `--password`/`TAS_PASSWORD`); otherwise explains how to enable the check.
59
+ - **Honest delete prompts** — default delete says the Telegram copy is retained; `--hard` warns `file_id` blobs can outlive the message.
60
+ - **npm discoverability** — added `telegram-bot`, `zero-knowledge`, `end-to-end-encryption`, `offsite-backup`, `file-sharing`, `dropbox-alternative` keywords.
61
+
62
+ ### Tests
63
+ - **78/78 passing** (was 71): new `tests/reliability.test.js` covers dotfile ignore rules, exact-match lookup, incomplete-upload detection, and cascade delete.
64
+
65
+ ## [2.4.1] - 2026-06-30
66
+
67
+ ### Security
68
+ - **Upgrade `node-telegram-bot-api` 0.66.0 → 1.1.2** — eliminates 9 vulnerabilities (2 critical, 7 moderate) inherited from the legacy `request` dependency: `form-data` CRLF injection, `qs` DoS via memory exhaustion, `tough-cookie` prototype pollution, `uuid` buffer bounds bypass
69
+ - **0 vulnerabilities** in full dependency tree after upgrade
70
+
71
+ ### Fixed
72
+ - **Broken navigation anchor** — README `Security` nav link had incorrect URL-encoded variation selector (`#%EF%B8%8F-security-model`); corrected to `#-security-model` (matches GitHub's anchor generation algorithm)
73
+ - **Missing `node_modules`** — `better-sqlite3` was not resolvable, causing `share`, `sync`, and `tags` test suites to fail with `ERR_MODULE_NOT_FOUND`
74
+
75
+ ### Tests
76
+ - **71/71 passing** after all fixes (was 41/71 due to missing dependency)
77
+
78
+ ## [2.4.0] - 2026-06-04
79
+
80
+
81
+ ### Security
82
+ - **Timing-safe password comparison** — `verifyPasswordHash` now uses `crypto.timingSafeEqual()` instead of `===` for both PBKDF2 and legacy SHA-256 paths, closing a timing side-channel
83
+ - **Config file permissions** — `config.json` is now `chmod 600` after creation, preventing other system users from reading your encrypted token and password hash
84
+ - **Share server binds to localhost** — Default bind address changed from `0.0.0.0` to `127.0.0.1` so the share server is no longer exposed to your entire LAN out of the box. Use `--host 0.0.0.0` if you need network access
85
+
86
+ ### Fixed
87
+ - **Streaming encryption empty-data bug** — `getEncryptStream()` now correctly emits the salt/IV header even when zero bytes are piped through it. Previously, encrypting an empty stream produced malformed output that couldn't be decrypted. The header is now written in `flush()` if `transform()` was never called
88
+
89
+ ### Added
90
+ - **31 new tests** — Streaming encryption/decryption (roundtrip, empty data, 1 MB, small-chunk stress, wrong password, truncation, cross-API compat) and WAS1 binary header (roundtrip, Unicode/CJK/emoji truncation, BigInt sizes, boundary values). Test count: 40 → 71
91
+ - **Shared download pipeline** — Extracted the triplicated Telegram→Decrypt→Decompress streaming pattern from `index.js`, `server.js`, and `mount.js` into a single reusable `createDownloadPipeline()` in `src/utils/download-stream.js`
92
+
93
+ ### Changed
94
+ - **SECURITY.md rewritten** — Corrected PBKDF2 iterations (was 100,000, actual is 600,000), updated supported versions table to include 2.x, documented config v2 encrypted token storage and share server security model
95
+ - Internal download code in `index.js`, `server.js`, and `mount.js` now uses the shared pipeline instead of duplicated stream wiring
96
+
97
+ ## [2.3.0] - 2026-05-30
98
+
99
+ ### Added
100
+ - Landing page (`docs/index.html`) for GitHub Pages — dark/light theme, responsive, no frameworks
101
+ - `tas doctor` — Self-diagnostic command that checks Node.js version, config, database health, disk space, encryption parameters
102
+ - `tas verify` — Verify all uploaded files still exist and are intact on Telegram
103
+ - JSON output for `tas list --json` and `tas status --json`
104
+
105
+ ### Changed
106
+ - README rewritten for Product Hunt — comparison table, collapsible CLI reference, security details table
107
+ - Config v2: bot token encrypted at rest with user's password (AES-256-GCM)
108
+ - PBKDF2 iterations raised to 600,000 (OWASP 2025 recommendation)
109
+
110
+ ### Fixed
111
+ - ARM64 install crash (#1) — fuse-native moved to `optionalDependencies`
112
+ - 413 Request Entity Too Large (#2) — chunk size reduced to 49 MB
113
+
114
+ ## [2.0.0] - 2026-02-12
115
+
116
+ ### Added
117
+ - **`tas share`** — Temporary encrypted file sharing via local HTTP server
118
+ - Create one-time download links with expiry (`--expire 1h/24h/7d`)
119
+ - Configurable download limits (`--max-downloads`)
120
+ - Dark-themed download page with file info
121
+ - `tas share list` and `tas share revoke` for management
122
+ - **FUSE mount** — Mount Telegram storage as a local folder (`tas mount`)
123
+ - **Folder sync** — Dropbox-style auto-sync with file watching (`tas sync start`)
124
+
125
+ ### Changed
126
+ - Major version bump for new feature set
127
+
128
+ ## [1.2.0] - 2026-01-24
129
+
130
+ ### Added
131
+ - Password automation — Use `-p/--password` flag or `TAS_PASSWORD` env var to skip prompts
132
+ - Batch operations — Upload multiple files without password prompts for each one
133
+ - CI/CD ready — Works with GitHub Actions, GitLab CI, Docker, cron jobs
134
+ - Config validation — Better error messages for missing/invalid configuration
135
+
136
+ ### Changed
137
+ - All password-required commands now support automated workflows
138
+ - Improved config loading with detailed error reporting
139
+
140
+ ## [1.1.0] - 2026-01-21
141
+
142
+ ### Added
143
+ - **Progress bars with speed** — See actual MB/s during uploads/downloads
144
+ - **`tas search`** — Search files by name or content
145
+ - **Resume uploads** — Interrupted uploads can be resumed with `tas resume`
146
+ - **Streaming FUSE reads** — Large files no longer buffer entirely in RAM
147
+
148
+ ### Changed
149
+ - README rewritten with technical focus (security model, architecture, limitations)
150
+
151
+ ### Fixed
152
+ - FUSE mount stability improvements
153
+
154
+ ## [1.0.0] - 2026-01-21
155
+
156
+ ### Added
157
+ - Initial release
158
+ - AES-256-GCM encryption with PBKDF2 key derivation
159
+ - FUSE filesystem mount support
160
+ - File tagging system
161
+ - Dropbox-style folder sync
162
+ - Chunked uploads for files >49MB
package/FAQ.md ADDED
@@ -0,0 +1,33 @@
1
+ # TAS 3 FAQ
2
+
3
+ ## Is storage unlimited or guaranteed?
4
+
5
+ No. Telegram gives TAS no storage quota, retention SLA, durability promise, or recovery service. Keep another tested copy.
6
+
7
+ ## Can Telegram restrict or ban this use?
8
+
9
+ Yes. A documented upload method is not a guarantee that a cloud-storage-style application is permitted. Telegram's current [Bot Developer Terms](https://telegram.org/tos/bot-developers) restrict divergent cloud-storage use cases and rate-limit circumvention. Multi-bot mode does not remove that risk.
10
+
11
+ ## Why are chunks 19 MiB when uploads allow more?
12
+
13
+ The hosted Bot API documents a larger upload allowance than its `getFile` download allowance. TAS keeps the payload at 19 MiB plus its 64-byte public routing header so newly uploaded chunks remain below the documented 20 MB read limit.
14
+
15
+ ## What metadata can Telegram see?
16
+
17
+ For new TAS 3 uploads, file content, user filename, original size, and remote recovery manifest contents are encrypted or omitted from public chunk fields. Telegram still observes bot/chat identity, timing, IP/network information, chunk count, encrypted sizes, message IDs, and generic TAS protocol captions. TAS 2.x chunks may contain filenames and original sizes in their legacy headers/captions.
18
+
19
+ ## Is TAS zero-knowledge?
20
+
21
+ TAS uses client-side AES-256-GCM and has no hosted TAS service, but it is not a formally analyzed zero-knowledge protocol and does not hide traffic metadata. Use a strong unique password and protect the local machine.
22
+
23
+ ## What happens if `index.db` is lost?
24
+
25
+ Run `tas index rebuild`. It downloads and authenticates the latest encrypted remote manifest referenced by `config.json`. Recovery still requires the password, config pointer, owning bot, and manifest message.
26
+
27
+ ## Does multi-bot mode provide redundancy?
28
+
29
+ No. Each chunk has one owning bot. TAS records that bot so reads and deletes route correctly, but all bots remain controlled by Telegram. A disabled bot stays configured for old chunks; removal is refused while chunks or the manifest depend on it.
30
+
31
+ ## Does mount work on macOS?
32
+
33
+ Yes with current macFUSE, Xcode Command Line Tools, and a locally rebuilt native addon. TAS never installs or replaces macFUSE; its install hook selects the system `libfuse` and compiles the optional addon for the active CPU. Run `tas doctor` before use. If the real mount/readdir/unmount smoke test does not pass, do not mount data.
package/QUICKSTART.md ADDED
@@ -0,0 +1,47 @@
1
+ # TAS 3 Quick Start
2
+
3
+ TAS is experimental encrypted file transport over Telegram bots. It is not an unlimited-storage or durability service. Telegram can limit or terminate access, and its current [Bot Developer Terms](https://telegram.org/tos/bot-developers) restrict external cloud-storage use cases. Use TAS at your own risk and keep an independent backup.
4
+
5
+ ## Install and initialize
6
+
7
+ ```bash
8
+ npm install -g @nightowne/tas-cli
9
+ tas init
10
+ tas doctor --password "$TAS_PASSWORD"
11
+ ```
12
+
13
+ `tas init` creates config v3 in `~/.tas/config.json`, encrypts the bot token with your TAS password, and creates the local SQLite index. Keep `config.json` and the password separately; both are needed for remote-manifest recovery.
14
+
15
+ ## Push, list, and pull
16
+
17
+ ```bash
18
+ tas push ./report.pdf
19
+ tas list --long
20
+ tas pull report.pdf ./restored-report.pdf
21
+ tas verify
22
+ ```
23
+
24
+ New data uses 19 MiB payload chunks so each stored document remains below the hosted Bot API's documented 20 MB `getFile` limit. Interrupted network-stage uploads can be continued with `tas resume`.
25
+
26
+ ## Recovery
27
+
28
+ ```bash
29
+ tas index backup
30
+ tas index rebuild
31
+ ```
32
+
33
+ TAS updates an authenticated encrypted remote manifest after storage mutations. `rebuild` restores the files/chunks/tags mapping if `index.db` is lost; it cannot help if the manifest message, owning bot, config pointer, or password is also lost.
34
+
35
+ ## Optional multi-bot pool
36
+
37
+ ```bash
38
+ tas bot add --name secondary
39
+ tas bot list
40
+ tas bot disable secondary
41
+ ```
42
+
43
+ Multi-bot mode distributes chunks. It is not redundancy, quota assurance, ban protection, or permission to evade Telegram limits.
44
+
45
+ ## Mount support
46
+
47
+ `tas mount` needs a native FUSE runtime. On Linux install `fuse` and `libfuse-dev`. On macOS install current macFUSE and Xcode Command Line Tools before installing TAS; TAS rebuilds its optional native addon against the installed macFUSE library. Run `tas doctor` first and mount only when its real mount/readdir/unmount smoke test passes.
package/README.md CHANGED
@@ -2,11 +2,11 @@
2
2
  <img src="assets/demo.gif" alt="TAS — Telegram as Storage CLI demo" width="680">
3
3
  </p>
4
4
 
5
- <h1 align="center">📦 TAS — Telegram as Storage</h1>
5
+ <h1 align="center">📦 TAS</h1>
6
6
 
7
7
  <h3 align="center">
8
- Turn your Telegram bot into unlimited, encrypted cloud storage.<br>
9
- <strong>Free forever. Zero-knowledge. No sign-up. No credit card. No limits.</strong>
8
+ Encrypted file transport for data you already keep backed up.<br>
9
+ <strong>Local index. Verifiable restores. Explicit provider risk.</strong>
10
10
  </h3>
11
11
 
12
12
  <p align="center">
@@ -18,13 +18,13 @@
18
18
  <a href="https://github.com/ixchio/tas/network/members"><img src="https://img.shields.io/github/forks/ixchio/tas?style=social" alt="GitHub Forks"></a>
19
19
  <img src="https://img.shields.io/badge/node-%3E%3D18-brightgreen?logo=node.js" alt="Node.js >= 18">
20
20
  <img src="https://img.shields.io/badge/encryption-AES--256--GCM-blueviolet?logo=shield" alt="AES-256-GCM">
21
- <img src="https://img.shields.io/badge/tests-71%20passing-success" alt="71 Tests Passing">
21
+ <img src="https://img.shields.io/badge/tests-101%20passing-success" alt="101 Tests Passing">
22
22
  </p>
23
23
 
24
24
  <p align="center">
25
25
  <a href="QUICKSTART.md"><strong>📚 Quick Start</strong></a> &nbsp;•&nbsp;
26
26
  <a href="FAQ.md">FAQ</a> &nbsp;•&nbsp;
27
- <a href="#-why-tas">Why TAS?</a> &nbsp;•&nbsp;
27
+ <a href="#why-tas">Why TAS?</a> &nbsp;•&nbsp;
28
28
  <a href="#-features">Features</a> &nbsp;•&nbsp;
29
29
  <a href="#-security-model">Security</a> &nbsp;•&nbsp;
30
30
  <a href="#-cli-reference">CLI Docs</a> &nbsp;•&nbsp;
@@ -34,30 +34,21 @@
34
34
 
35
35
  ---
36
36
 
37
- > **TL;DR** — One `npm install`, one `tas init`, then `tas push yourfile.pdf`. Your file is now AES-256 encrypted and stored for free on Telegram's infrastructure. No accounts, no fees, no vendor lock-in. Seriously.
37
+ > **TAS 3.0** — One `npm install`, one `tas init`, then `tas push yourfile.pdf`. TAS encrypts content locally and sends round-trip-safe chunks through the Bot API. It is experimental transport, not a durable backup service: Telegram can limit, remove, or terminate access. Keep an independent backup.
38
38
 
39
39
  ---
40
40
 
41
- ## The Problem With "Free" Cloud Storage
41
+ ## What TAS Is
42
42
 
43
- Every major cloud provider has one of three business models: **scanning your data**, **charging you money**, or **capping your storage**. There is no free lunch.
43
+ TAS is a local-first CLI for moving encrypted file blobs through your own Telegram bots. Its SQLite index lives on your machine; content is encrypted before upload; completed mutations publish an encrypted recovery manifest you can use to rebuild the index.
44
44
 
45
- | Provider | Free Tier | Reads Your Data? | CLI-First? | Encryption At Rest (by you)? |
46
- |---|---|---|---|---|
47
- | Google Drive | 15 GB | ✅ Yes (indexes for ads) | ❌ | ❌ |
48
- | Dropbox | 2 GB | ✅ Can access | ❌ | ❌ |
49
- | iCloud | 5 GB | ✅ Apple ToS | ❌ | ❌ |
50
- | Mega | 20 GB | ❓ Closed-source E2EE | ❌ | ❓ |
51
- | Backblaze B2 | 10 GB | ❌ | ✅ | ❌ (you add it) |
52
- | **TAS + Telegram** | **♾️ Unlimited** | **❌ Impossible (AES-256)** | **✅ First-class** | **✅ Always** |
53
-
54
- Meanwhile, Telegram gives every bot **unlimited file storage** via its public Bot API — and almost nobody is using it.
45
+ > **Operating boundary.** TAS is not unlimited storage, a backup guarantee, or a Telegram-supported cloud drive. Telegram provides no TAS quota, retention SLA, recovery service, or account guarantee. Its [Bot Developer Terms](https://telegram.org/tos/bot-developers) also restrict external apps that diverge into cloud-storage use cases. Use TAS only for data that already has an independent backup.
55
46
 
56
47
  ---
57
48
 
58
- ## The Solution
49
+ ## How It Works
59
50
 
60
- **TAS** compresses, encrypts (AES-256-GCM), chunks, and uploads your files to your own private Telegram bot chat. Your password never leaves your machine. Telegram only ever sees **encrypted noise**. You get a fully-featured, CLI-native cloud drive with FUSE mount, Dropbox-style sync, expiring share links, and tagging — at **$0/month, forever.**
51
+ **TAS** compresses, encrypts (AES-256-GCM), chunks, and uploads files to private bot chats. Your password stays local. Content, filenames, original sizes, and the recovery manifest are encrypted or omitted from Telegram-visible chunk metadata. Telegram still sees bot/chat identity, timing, chunk count, and encrypted sizes.
61
52
 
62
53
  ```
63
54
  Your Machine Telegram Cloud
@@ -71,14 +62,14 @@ Meanwhile, Telegram gives every bot **unlimited file storage** via its public Bo
71
62
  │ (SHA-256 verified) │←── decomp ←──│ ← Stream on demand │
72
63
  │ │ │ │
73
64
  └─────────────────────────────┘ └──────────────────────────┘
74
- SQLite Index Unlimited & Free
65
+ SQLite Index Remote Bot Messages
75
66
  ```
76
67
 
77
68
  ---
78
69
 
79
70
  ## ⚡ Quick Start
80
71
 
81
- **Three commands. Under two minutes. Zero cost.**
72
+ **Three commands to try it. Keep another copy of every file.**
82
73
 
83
74
  ```bash
84
75
  # 1. Install globally
@@ -97,36 +88,15 @@ tas list # See everything you've stored
97
88
 
98
89
  ---
99
90
 
100
- ## 💡 Why TAS?
101
-
102
- <table>
103
- <tr>
104
- <td width="50%" valign="top">
105
-
106
- ### ❌ The Alternative
107
- - Google Drive scans & indexes your files for ads
108
- - Dropbox costs $12/mo — and can read your data
109
- - iCloud locks you into the Apple ecosystem
110
- - Self-hosting (Nextcloud, MinIO) costs VPS money + maintenance time
111
- - S3 / B2 needs encryption wiring and costs per GB transferred
112
- - rclone + any backend still needs a paid backend
113
-
114
- </td>
115
- <td width="50%" valign="top">
116
-
117
- ### ✅ TAS gives you
118
- - **$0/month** — forever, no storage caps, no bandwidth fees
119
- - **Zero-knowledge** — only you hold the decryption key
120
- - **AES-256-GCM** — same cipher used by banks and governments
121
- - **FUSE mount** — Telegram storage appears as a real folder
122
- - **Auto-sync** — Dropbox-style folder watcher built-in
123
- - **Expiring share links** — send files without sharing your password
124
- - **CLI-first** — pipe to `jq`, run in cron, automate everything
125
- - **Open source** — audit every single line of crypto code
126
-
127
- </td>
128
- </tr>
129
- </table>
91
+ ## Why TAS?
92
+
93
+ TAS is for people who want a small, inspectable command-line transport rather than another account, dashboard, or opaque sync daemon. It makes the important state visible and keeps the recovery path in your hands.
94
+
95
+ - **A local source of truth.** The index is SQLite, paths are exact, and nested directories behave consistently in sync and FUSE.
96
+ - **A recovery story.** TAS writes an authenticated, encrypted remote manifest after completed changes; `tas index rebuild` can restore the file-to-message map when the local index is gone.
97
+ - **A clean automation surface.** Push, pull, search, tags, sync, and JSON output work from a shell, cron job, or CI runner.
98
+ - **Deliberate multi-bot routing.** Each chunk records its owner, so a pool is inspectable and reversible instead of a hidden round-robin trick.
99
+ - **No false promise.** The product is precise about the provider boundary: Telegram is not your storage vendor, and multi-bot mode is not a way around its rules.
130
100
 
131
101
  ---
132
102
 
@@ -143,7 +113,7 @@ cp report.pdf ~/cloud/ # Drop files in — auto-encrypted and uploaded
143
113
  tas unmount ~/cloud # Clean unmount when done
144
114
  ```
145
115
 
146
- > **Requirements:** `apt install fuse libfuse-dev` (Linux) · `brew install macfuse` (macOS)
116
+ > **Native FUSE is verified, not assumed:** Linux needs `fuse`/`libfuse-dev`. macOS uses current macFUSE and rebuilds the optional native addon against the installed system library on first install. Install Xcode Command Line Tools before TAS, then run `tas doctor`; mount is available only when its real mount → readdir → unmount smoke test passes.
147
117
 
148
118
  ---
149
119
 
@@ -160,6 +130,33 @@ tas sync status # See what's queued / synced / pending
160
130
 
161
131
  ---
162
132
 
133
+ ### 🤖 Experimental Multi-Bot Pool
134
+
135
+ TAS can distribute new chunks deterministically across multiple bots and records the owning bot on every chunk. Disabled bots remain configured for reads; a bot cannot be removed while indexed chunks or the recovery manifest depend on it.
136
+
137
+ ```bash
138
+ tas bot add --name archive-2 # Interactive token/chat setup + risk acknowledgement
139
+ tas bot list # IDs, state, chat, and dependent chunk counts
140
+ tas bot disable archive-2 # Stop new writes; old chunks remain readable
141
+ tas bot enable archive-2
142
+ tas bot remove archive-2 # Refuses unless no data depends on it
143
+ ```
144
+
145
+ > **Use at your own risk.** Multiple bots do not guarantee more quota, durability, ban avoidance, or Terms compliance. Do not use this feature to evade Telegram limits. All bots remain under Telegram's control, so this is distribution—not redundancy.
146
+
147
+ ### 🧯 Index Recovery
148
+
149
+ Every completed storage mutation publishes a gzip-compressed, AES-256-GCM-authenticated manifest containing the file/chunk mapping and tags. Ephemeral share tokens are deliberately excluded. The latest pointer is stored in `config.json`.
150
+
151
+ ```bash
152
+ tas index backup # Publish a fresh encrypted recovery point
153
+ tas index rebuild # Authenticate and rebuild index.db
154
+ ```
155
+
156
+ Keep `config.json` and your password separately: recovery cannot discover the latest manifest if both the database and config are lost.
157
+
158
+ ---
159
+
163
160
  ### 🔗 Expiring Share Links
164
161
 
165
162
  Generate time-limited, download-limited share links. Recipients get a clean dark-themed download page. **Your password is never shared — files are decrypted on-the-fly by the local server.**
@@ -192,11 +189,12 @@ tas search -t secrets # Quickly find your credentials
192
189
  ```bash
193
190
  tas doctor
194
191
  # ✓ Node.js 20.11.0
195
- # ✓ Config v2 (encrypted bot token — AES-256-GCM at rest)
192
+ # ✓ Config v3 (encrypted multi-bot token set)
196
193
  # ✓ Database: 42 files, 1.3 GB total across 28 chunks
197
194
  # ✓ Disk space: 50 GB free (32% used)
198
195
  # ✓ Encryption: AES-256-GCM · PBKDF2-SHA512 · 600,000 iterations (OWASP 2025)
199
- # ✓ Telegram connectivity: OK
196
+ # ✓ FUSE runtime: mount → readdir → unmount passed
197
+ # ✓ Telegram connectivity: 2/2 bots OK
200
198
  # ✨ All systems go!
201
199
  ```
202
200
 
@@ -272,7 +270,7 @@ jobs:
272
270
 
273
271
  ## 🛡️ Security Model
274
272
 
275
- TAS implements **zero-knowledge encryption** — we can't read your data, Telegram can't read your data, and nobody without your password ever can.
273
+ TAS applies **client-side authenticated encryption**. TAS has no hosted service that receives your password, but this is not a formal zero-knowledge protocol and it does not hide all traffic metadata from Telegram.
276
274
 
277
275
  | Layer | Implementation | Standard |
278
276
  |---|---|---|
@@ -281,45 +279,47 @@ TAS implements **zero-knowledge encryption** — we can't read your data, Telegr
281
279
  | **Salt** | 32 bytes, `crypto.randomBytes()` — unique per file | No rainbow tables |
282
280
  | **IV/Nonce** | 12 bytes, `crypto.randomBytes()` — unique per file | No nonce reuse |
283
281
  | **Auth Tag** | 16 bytes GCM tag — any tampered bit = instant rejection | Tamper detection |
284
- | **Bot Token** | Encrypted at rest in `config.json` (AES-256-GCM) | Config v2 |
282
+ | **Bot Tokens** | Encrypted independently at rest in `config.json` | Config v3 |
285
283
  | **Password Verification** | `crypto.timingSafeEqual()` on both PBKDF2 and legacy paths | Timing-safe |
286
284
  | **Config Permissions** | `chmod 600 config.json` on creation | No world-readable secrets |
287
- | **Integrity** | SHA-256 hash verified on every single download | Bit-perfect guarantee |
285
+ | **Recovery Manifest** | gzip + AES-256-GCM; authenticated before SQLite import | Remote index recovery |
286
+ | **Integrity** | SHA-256 hash verified on completed downloads | Detects mismatch/corruption |
288
287
  | **Share Server** | Binds `127.0.0.1` by default, XSS-escaped, RFC 6266 filenames | LAN-safe |
289
288
 
290
289
  ### What Telegram Actually Sees
291
290
 
292
291
  ```
293
- 📦 a7f3b2c1e9d4f820.tas — 12.4 MB — application/octet-stream
292
+ chunk-000000.tas — 12.4 MB — caption: tas:c1:42:1/2
294
293
  ```
295
294
 
296
- An opaque, encrypted blob. No filename. No content type. No metadata. Just noise.
295
+ New uploads expose no user filename or original size in the document name, caption, or public WAS1 routing header. Telegram can still observe encrypted size, chunk count, timing, bot/chat identity, IP/network data, and message identifiers. Files uploaded by TAS 2.5 and older may still expose filename/size metadata until re-uploaded.
297
296
 
298
297
  ### Threat Model
299
298
 
300
299
  | Threat | Mitigated? | How |
301
300
  |---|---|---|
302
- | Telegram reads your files | ✅ Yes | AES-256-GCM — mathematically impossible without key |
303
- | Someone steals your config.json | ✅ Yes | Bot token encrypted at rest; password hash is PBKDF2 |
304
- | Brute-force your password | ✅ Yes | 600k PBKDF2 iterations ≈ 100ms/attempt minimum |
305
- | Tampered download | ✅ Yes | SHA-256 check + GCM auth tag on every download |
306
- | Timing attack on password | ✅ Yes | `crypto.timingSafeEqual()` on all comparisons |
307
- | Share link exposure | ✅ Yes | Localhost-only by default; expiry + download limits |
301
+ | Telegram reads plaintext content | Mitigated | AES-256-GCM, assuming a strong password and uncompromised client |
302
+ | Telegram observes traffic metadata | Not mitigated | Bot/chat, timing, encrypted sizes, and chunk counts remain visible |
303
+ | Someone steals `config.json` | Partly mitigated | Tokens are encrypted; an offline password attack is still possible |
304
+ | Tampered download | Mitigated | GCM authentication plus final SHA-256 verification |
305
+ | Local machine compromise | Not mitigated | A process with password/filesystem access can read plaintext and tokens |
306
+ | Share link exposure | Limited | Localhost default, expiry, and download limits; the local server decrypts content |
308
307
 
309
308
  ---
310
309
 
311
310
  ## 🔄 Reliability
312
311
 
313
- Built with the same philosophy as professional backup tools (restic, borg, rclone):
312
+ Reliability mechanisms implemented by TAS (not an SLA):
314
313
 
315
314
  | Feature | Implementation |
316
315
  |---|---|
317
316
  | **Exponential Backoff** | Auto-retry with jitter on Telegram 429 errors and network timeouts |
318
- | **Rate Limiting** | Built-in 1 msg/sec — never trips Telegram's rate limits |
317
+ | **Rate Limiting** | One serialized send queue per configured bot within a TAS process; parallel TAS processes and Telegram's dynamic limits still apply |
319
318
  | **Integrity Verification** | SHA-256 hash verified after every single download |
320
- | **Resume Uploads** | `tas resume` picks up interrupted multi-chunk uploads |
321
- | **Graceful Shutdown** | SIGINT/SIGTERM handled — zero corruption risk on Ctrl-C |
322
- | **Self-Diagnostics** | `tas doctor` validates your entire setup end-to-end |
319
+ | **Resume Uploads** | Network-stage chunks are staged on disk and persisted in `pending_uploads`; `tas resume` continues them |
320
+ | **Index Recovery** | Authenticated encrypted remote manifest; `tas index rebuild` restores file/chunk ownership |
321
+ | **Graceful Shutdown** | SIGINT/SIGTERM handled; staged chunks and SQLite WAL reduce partial-state risk |
322
+ | **Self-Diagnostics** | Checks config/database/chunk limits, all bots, and a real native FUSE smoke mount |
323
323
 
324
324
  ---
325
325
 
@@ -329,16 +329,20 @@ Built with the same philosophy as professional backup tools (restic, borg, rclon
329
329
  <summary><strong>Core Commands</strong></summary>
330
330
 
331
331
  ```bash
332
- tas init # 🚀 Interactive setup wizard (create bot in ~60s)
333
- tas push <file> [file2...] # ⬆️ Encrypt + compress + upload
332
+ tas init [--token T --chat ID --password PW] # 🚀 Wizard, or fully non-interactive for CI/Docker
333
+ tas push <files...> # ⬆️ Encrypt + compress + upload (batch supported)
334
334
  tas pull <file|hash> # ⬇️ Download + decrypt + verify
335
335
  tas list [-l] [--json] # 📋 List all stored files
336
336
  tas delete <file|hash> # 🗑️ Remove from index (--hard removes from Telegram)
337
337
  tas status [--json] # 📊 Storage stats & database health
338
338
  tas search <query> [-t tag] # 🔍 Find by filename or tag
339
339
  tas resume # 🔄 Resume interrupted uploads
340
- tas verify # ✅ Verify every file still exists and is intact
340
+ tas verify # ✅ Check every Telegram file reference
341
+ tas verify --deep # ✅ Download/decrypt/hash every file (slow and bandwidth-heavy)
341
342
  tas doctor # 🩺 Full system health check
343
+ tas index backup # 🧯 Publish encrypted recovery manifest
344
+ tas index rebuild # 🧯 Restore index.db from that manifest
345
+ tas bot add|list|enable|disable|remove # 🤖 Manage experimental bot pool
342
346
  ```
343
347
 
344
348
  </details>
@@ -347,7 +351,7 @@ tas doctor # 🩺 Full system health check
347
351
  <summary><strong>Mount & Sync</strong></summary>
348
352
 
349
353
  ```bash
350
- # FUSE Mount
354
+ # FUSE Mount (Linux/libfuse or macOS/current macFUSE)
351
355
  tas mount <path> # Mount Telegram storage as a local folder
352
356
  tas unmount <path> # Clean unmount
353
357
 
@@ -365,7 +369,7 @@ tas sync status # Show sync queue and status
365
369
 
366
370
  ```bash
367
371
  # Expiring Share Links
368
- tas share create <file> [--expire 1h|24h|7d] [--max-downloads N]
372
+ tas share create <file> [--expire 1h|24h|7d] [--max-downloads N] [--host 0.0.0.0] [--port 3000]
369
373
  tas share list # Active links with expiry countdown
370
374
  tas share revoke <token> # Instantly revoke a share
371
375
 
@@ -395,12 +399,14 @@ TAS_DATA_DIR="/custom/path" # Override default ~/.tas data directory
395
399
  src/
396
400
  ├── cli.js # Commander-based CLI — all commands defined here
397
401
  ├── index.js # Core streaming upload/download pipeline
402
+ ├── manifest.js # Encrypted remote index backup/rebuild
398
403
  ├── crypto/
399
404
  │ └── encryption.js # AES-256-GCM + PBKDF2-SHA512 (600k iterations)
400
405
  ├── db/
401
406
  │ └── index.js # SQLite index: files, chunks, tags, shares, sync
402
407
  ├── telegram/
403
- │ └── client.js # Bot API wrapper — retry, rate-limit, streaming
408
+ │ ├── client.js # Bot API wrapper — retry + serialized send queue
409
+ │ └── pool.js # Stable per-chunk multi-bot routing
404
410
  ├── fuse/
405
411
  │ └── mount.js # FUSE filesystem — mount Telegram as a local folder
406
412
  ├── share/
@@ -410,7 +416,8 @@ src/
410
416
  └── utils/
411
417
  ├── download-stream.js # Shared Telegram→Decrypt→Decompress pipeline
412
418
  ├── compression.js # Smart gzip (skips already-compressed formats)
413
- ├── chunker.js # 49 MB chunks + WAS1 binary file headers
419
+ ├── chunker.js # 19 MiB payloads + metadata-free public WAS1 headers
420
+ ├── logical-path.js # Portable exact paths + virtual directory tree
414
421
  ├── progress.js # Terminal progress bars with MB/s + ETA
415
422
  ├── throttle.js # Bandwidth limiter (stream transform)
416
423
  ├── branding.js # ASCII art + version display
@@ -434,24 +441,17 @@ src/
434
441
  | 💾 **Offsite backup** | Nightly database dumps, system configs via cron |
435
442
  | 🤖 **CI/CD artifacts** | Store build outputs, test reports, deployment keys |
436
443
 
437
- **Not ideal for:** Mission-critical business data (use professional backup tools alongside this), team collaboration (no multi-user support yet), or replacing full backup systems — **Telegram can theoretically delete old messages.**
444
+ **Not appropriate for:** the only copy of any data, mission-critical/business backups, regulated retention, team storage, or workloads that require an SLA. Telegram can remove messages or terminate access without giving TAS a recovery channel.
438
445
 
439
446
  ---
440
447
 
441
448
  ## ❓ Is This Allowed? (The Legal Question)
442
449
 
443
- ### Will Telegram ban me?
444
-
445
- **No.** Here's the complete picture:
450
+ ### Can Telegram restrict or terminate this use?
446
451
 
447
- - ✅ **Bot API is a public, documented feature** — Telegram designed file uploads into the Bot API intentionally
448
- - ✅ **You're sending to your own private bot chat** — not a public channel, not spamming
449
- - ✅ **Content is encrypted** — Telegram cannot detect what you're storing
450
- - ✅ **No published storage limits** — individual files cap at 2 GB (TAS chunks automatically)
451
- - ✅ **Strong precedent** — thousands of file-sharing bots, backup tools, and media archives use this API
452
- - ⚠️ **Worst case** — Telegram might prune old messages to free infrastructure space. They won't ban you for using a documented API
452
+ **Yes.** The Bot API supports sending documents, but that technical capability is not permission or a storage guarantee. Telegram's current [Bot Developer Terms](https://telegram.org/tos/bot-developers) explicitly restrict external applications that diverge into cloud-storage use cases, prohibit circumventing rate limits, and allow bot/account termination. TAS cannot promise that one bot—or a multi-bot pool—will remain available.
453
453
 
454
- **Your responsibility:** Don't store illegal content. Telegram's ToS prohibits copyright infringement, malware, CSAM, etc. Use responsibly. See [FAQ.md](FAQ.md) for the full legal breakdown.
454
+ Use TAS only at your own risk, do not use multiple bots to evade limits, follow all applicable laws and Telegram terms, and keep a tested independent backup. Encryption protects content confidentiality; it does not make the usage invisible or policy-compliant.
455
455
 
456
456
  ---
457
457
 
@@ -460,9 +460,10 @@ src/
460
460
  | | |
461
461
  |---|---|
462
462
  | 📌 **Not a replacement for backups** | Telegram can purge old messages. Use TAS alongside, not instead of, real backup solutions. |
463
- | 📌 **49 MB chunk size** | Files are split automatically — fully transparent to you. Telegram's Bot API limit is 50 MB. |
464
- | 📌 **Single-user** | Designed for personal use. No multi-tenant or shared-account support. |
465
- | 📌 **FUSE = Linux/macOS only** | Mount requires `libfuse`. The CLI itself works anywhere Node.js 18+ runs. |
463
+ | 📌 **19 MiB payload chunks** | Hosted Bot API uploads permit more, but `getFile` documents only 20 MB downloads. TAS stays below the read limit. |
464
+ | 📌 **Multi-bot is experimental** | It distributes chunks and preserves ownership mapping; it is not redundancy or ban protection. |
465
+ | 📌 **macOS needs a native build** | Install current macFUSE and Xcode Command Line Tools before installing TAS. `tas doctor` must pass its real FUSE smoke test before you mount data. |
466
+ | 📌 **Recovery needs config** | `index.db` can be rebuilt from the encrypted manifest only if `config.json`, password, manifest message, and owning bot survive. |
466
467
  | 📌 **No versioning (yet)** | Overwriting a file replaces the previous version. |
467
468
  | 📌 **Internet required** | Telegram-backed — offline access requires files pulled locally first. |
468
469
 
@@ -474,7 +475,7 @@ src/
474
475
  git clone https://github.com/ixchio/tas
475
476
  cd tas && npm install
476
477
 
477
- npm test # Run all 71 tests (encryption, WAS1 headers, tags, sync, shares)
478
+ npm test # Run all 97 tests (crypto, paths, migrations, multi-bot, resume, manifest, sync, shares)
478
479
  npm test -- --watch # Watch mode for active development
479
480
  ```
480
481