@nightowne/tas-cli 2.4.0 → 3.0.0
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 +154 -0
- package/FAQ.md +33 -0
- package/QUICKSTART.md +47 -0
- package/README.md +356 -196
- package/package.json +11 -5
- package/src/cli.js +758 -213
- package/src/db/index.js +307 -24
- package/src/fuse/mount.js +336 -175
- package/src/index.js +187 -123
- package/src/manifest.js +104 -0
- package/src/share/server.js +7 -9
- package/src/sync/sync.js +105 -34
- package/src/telegram/client.js +10 -3
- package/src/telegram/pool.js +105 -0
- package/src/utils/branding.js +2 -2
- package/src/utils/chunker.js +4 -3
- package/src/utils/cli-helpers.js +90 -10
- package/src/utils/download-stream.js +10 -4
- package/src/utils/logical-path.js +44 -0
package/README.md
CHANGED
|
@@ -1,232 +1,327 @@
|
|
|
1
1
|
<p align="center">
|
|
2
|
-
<img src="assets/demo.gif" alt="TAS — Telegram as Storage" width="
|
|
2
|
+
<img src="assets/demo.gif" alt="TAS — Telegram as Storage CLI demo" width="680">
|
|
3
3
|
</p>
|
|
4
4
|
|
|
5
|
-
<h1 align="center">
|
|
6
|
-
📦 TAS — Telegram as Storage
|
|
7
|
-
</h1>
|
|
5
|
+
<h1 align="center">📦 TAS</h1>
|
|
8
6
|
|
|
9
7
|
<h3 align="center">
|
|
10
|
-
|
|
11
|
-
|
|
8
|
+
Encrypted file transport for data you already keep backed up.<br>
|
|
9
|
+
<strong>Local index. Verifiable restores. Explicit provider risk.</strong>
|
|
12
10
|
</h3>
|
|
13
11
|
|
|
14
12
|
<p align="center">
|
|
15
|
-
<a href="https://github.com/ixchio/tas/actions/workflows/ci.yml"><img src="https://github.com/ixchio/tas/actions/workflows/ci.yml/badge.svg" alt="CI"></a>
|
|
16
|
-
<a href="https://www.npmjs.com/package/@nightowne/tas-cli"><img src="https://img.shields.io/npm/v/@nightowne/tas-cli?color=cb3837&label=npm" alt="npm version"></a>
|
|
17
|
-
<a href="https://www.npmjs.com/package/@nightowne/tas-cli"><img src="https://img.shields.io/npm/dm/@nightowne/tas-cli?color=blue" alt="Downloads"></a>
|
|
18
|
-
<a href="https://opensource.org/licenses/MIT"><img src="https://img.shields.io/badge/license-MIT-
|
|
13
|
+
<a href="https://github.com/ixchio/tas/actions/workflows/ci.yml"><img src="https://github.com/ixchio/tas/actions/workflows/ci.yml/badge.svg" alt="CI Status"></a>
|
|
14
|
+
<a href="https://www.npmjs.com/package/@nightowne/tas-cli"><img src="https://img.shields.io/npm/v/@nightowne/tas-cli?color=cb3837&label=npm&logo=npm" alt="npm version"></a>
|
|
15
|
+
<a href="https://www.npmjs.com/package/@nightowne/tas-cli"><img src="https://img.shields.io/npm/dm/@nightowne/tas-cli?color=blue&label=downloads&logo=npm" alt="Monthly Downloads"></a>
|
|
16
|
+
<a href="https://opensource.org/licenses/MIT"><img src="https://img.shields.io/badge/license-MIT-brightgreen.svg" alt="License: MIT"></a>
|
|
19
17
|
<a href="https://github.com/ixchio/tas/stargazers"><img src="https://img.shields.io/github/stars/ixchio/tas?style=social" alt="GitHub Stars"></a>
|
|
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
|
+
<img src="https://img.shields.io/badge/node-%3E%3D18-brightgreen?logo=node.js" alt="Node.js >= 18">
|
|
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-97%20passing-success" alt="97 Tests Passing">
|
|
20
22
|
</p>
|
|
21
23
|
|
|
22
24
|
<p align="center">
|
|
23
|
-
<a href="
|
|
24
|
-
<a href="
|
|
25
|
-
<a href="
|
|
26
|
-
<a href="
|
|
27
|
-
<a href="#-
|
|
28
|
-
<a href="#-
|
|
25
|
+
<a href="QUICKSTART.md"><strong>📚 Quick Start</strong></a> •
|
|
26
|
+
<a href="FAQ.md">FAQ</a> •
|
|
27
|
+
<a href="#why-tas">Why TAS?</a> •
|
|
28
|
+
<a href="#-features">Features</a> •
|
|
29
|
+
<a href="#-security-model">Security</a> •
|
|
30
|
+
<a href="#-cli-reference">CLI Docs</a> •
|
|
31
|
+
<a href="#-docker--cicd">Docker / CI</a> •
|
|
32
|
+
<a href="CHANGELOG.md">Changelog</a>
|
|
29
33
|
</p>
|
|
30
34
|
|
|
31
35
|
---
|
|
32
36
|
|
|
33
|
-
|
|
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.
|
|
34
38
|
|
|
35
|
-
|
|
39
|
+
---
|
|
40
|
+
|
|
41
|
+
## What TAS Is
|
|
42
|
+
|
|
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.
|
|
36
44
|
|
|
37
|
-
|
|
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.
|
|
38
46
|
|
|
39
|
-
|
|
47
|
+
---
|
|
40
48
|
|
|
41
|
-
##
|
|
49
|
+
## How It Works
|
|
42
50
|
|
|
43
|
-
**TAS** compresses, encrypts, and uploads
|
|
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.
|
|
44
52
|
|
|
45
53
|
```
|
|
46
|
-
Your Machine
|
|
47
|
-
|
|
48
|
-
│
|
|
49
|
-
│
|
|
50
|
-
│
|
|
51
|
-
│
|
|
52
|
-
│
|
|
53
|
-
│
|
|
54
|
-
│
|
|
55
|
-
|
|
56
|
-
|
|
54
|
+
Your Machine Telegram Cloud
|
|
55
|
+
┌─────────────────────────────┐ ┌──────────────────────────┐
|
|
56
|
+
│ │ │ │
|
|
57
|
+
│ tas push secret.tar.gz │──→ gzip ──→ │ 🔒 Encrypted Blob #1 │
|
|
58
|
+
│ tas mount ~/cloud │──→ AES-256 ──→│ 🔒 Encrypted Blob #2 │
|
|
59
|
+
│ tas sync start │──→ chunk ──→ │ 🔒 Encrypted Blob #3 │
|
|
60
|
+
│ │ │ (Private Bot Chat) │
|
|
61
|
+
│ tas pull secret.tar.gz │←── decrypt ←──│ │
|
|
62
|
+
│ (SHA-256 verified) │←── decomp ←──│ ← Stream on demand │
|
|
63
|
+
│ │ │ │
|
|
64
|
+
└─────────────────────────────┘ └──────────────────────────┘
|
|
65
|
+
SQLite Index Remote Bot Messages
|
|
57
66
|
```
|
|
58
67
|
|
|
59
|
-
|
|
68
|
+
---
|
|
60
69
|
|
|
61
70
|
## ⚡ Quick Start
|
|
62
71
|
|
|
63
|
-
Three commands
|
|
72
|
+
**Three commands to try it. Keep another copy of every file.**
|
|
64
73
|
|
|
65
74
|
```bash
|
|
75
|
+
# 1. Install globally
|
|
66
76
|
npm install -g @nightowne/tas-cli
|
|
67
77
|
|
|
68
|
-
|
|
69
|
-
tas
|
|
70
|
-
|
|
78
|
+
# 2. Connect your Telegram bot (guided wizard — takes ~60 seconds)
|
|
79
|
+
tas init
|
|
80
|
+
|
|
81
|
+
# 3. Start using it
|
|
82
|
+
tas push secret.pdf # Encrypt + compress + upload
|
|
83
|
+
tas pull secret.pdf # Download + decrypt + verify
|
|
84
|
+
tas list # See everything you've stored
|
|
71
85
|
```
|
|
72
86
|
|
|
73
|
-
|
|
87
|
+
> **Need a Telegram bot?** Open Telegram → search `@BotFather` → `/newbot` → copy the token. That's it.
|
|
74
88
|
|
|
75
|
-
|
|
89
|
+
---
|
|
76
90
|
|
|
77
|
-
##
|
|
91
|
+
## Why TAS?
|
|
78
92
|
|
|
79
|
-
|
|
80
|
-
<tr>
|
|
81
|
-
<td width="50%">
|
|
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.
|
|
82
94
|
|
|
83
|
-
|
|
84
|
-
-
|
|
85
|
-
-
|
|
86
|
-
-
|
|
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.
|
|
87
100
|
|
|
88
|
-
|
|
89
|
-
- ❌ $12/mo for 2 TB
|
|
90
|
-
- ❌ Can access your data
|
|
91
|
-
- ❌ No CLI-first experience
|
|
101
|
+
---
|
|
92
102
|
|
|
93
|
-
|
|
94
|
-
- ❌ Freemium with tight caps
|
|
95
|
-
- ❌ Closed source encryption
|
|
96
|
-
- ❌ Can't self-host or script
|
|
103
|
+
## 🔥 Features
|
|
97
104
|
|
|
98
|
-
|
|
99
|
-
<td width="50%">
|
|
105
|
+
### 🗂️ Mount as a Local Folder (FUSE)
|
|
100
106
|
|
|
101
|
-
|
|
102
|
-
- ✅ **$0/month** — forever, no caps
|
|
103
|
-
- ✅ **Zero-knowledge** — only you can decrypt
|
|
104
|
-
- ✅ **AES-256-GCM** — military-grade encryption
|
|
105
|
-
- ✅ **Mount as folder** — FUSE filesystem
|
|
106
|
-
- ✅ **Auto-sync** — Dropbox-style folder sync
|
|
107
|
-
- ✅ **Share links** — expiring, download-limited
|
|
108
|
-
- ✅ **CLI-first** — cron, Docker, CI/CD ready
|
|
109
|
-
- ✅ **Open source** — audit every line
|
|
107
|
+
Use Telegram storage exactly like a USB drive — drag and drop, open in any app.
|
|
110
108
|
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
109
|
+
```bash
|
|
110
|
+
tas mount ~/cloud # Mount your Telegram storage as ~/cloud
|
|
111
|
+
ls ~/cloud # Browse your encrypted files normally
|
|
112
|
+
cp report.pdf ~/cloud/ # Drop files in — auto-encrypted and uploaded
|
|
113
|
+
tas unmount ~/cloud # Clean unmount when done
|
|
114
|
+
```
|
|
114
115
|
|
|
115
|
-
|
|
116
|
+
> **Linux only for this release:** install `fuse`/`libfuse-dev`, then run `tas doctor` for a real mount → readdir → unmount smoke test. macOS mount is explicitly unsupported because `fuse-native@2.x` targets obsolete OSXFUSE APIs and is not validated with current macFUSE or Apple Silicon. Push, pull, sync, and share still work on macOS.
|
|
116
117
|
|
|
117
|
-
|
|
118
|
+
---
|
|
119
|
+
|
|
120
|
+
### 🔄 Auto-Sync Folders (Dropbox-style)
|
|
121
|
+
|
|
122
|
+
Register a local folder and TAS watches it. Any new or changed file is automatically encrypted and uploaded.
|
|
123
|
+
|
|
124
|
+
```bash
|
|
125
|
+
tas sync add ~/Documents # Register ~/Documents for auto-sync
|
|
126
|
+
tas sync start # Start the watcher (runs in background)
|
|
127
|
+
tas sync pull # Pull all synced files back down
|
|
128
|
+
tas sync status # See what's queued / synced / pending
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
---
|
|
132
|
+
|
|
133
|
+
### 🤖 Experimental Multi-Bot Pool
|
|
118
134
|
|
|
119
|
-
|
|
120
|
-
Drag and drop files into Telegram storage like it's a regular drive.
|
|
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.
|
|
121
136
|
|
|
122
137
|
```bash
|
|
123
|
-
tas
|
|
124
|
-
|
|
125
|
-
tas
|
|
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
|
|
126
143
|
```
|
|
127
144
|
|
|
128
|
-
>
|
|
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.
|
|
129
146
|
|
|
130
|
-
###
|
|
131
|
-
|
|
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`.
|
|
132
150
|
|
|
133
151
|
```bash
|
|
134
|
-
tas
|
|
135
|
-
tas
|
|
136
|
-
tas sync pull # Download everything back
|
|
137
|
-
tas sync status # See what's synced
|
|
152
|
+
tas index backup # Publish a fresh encrypted recovery point
|
|
153
|
+
tas index rebuild # Authenticate and rebuild index.db
|
|
138
154
|
```
|
|
139
155
|
|
|
140
|
-
|
|
141
|
-
|
|
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
|
+
|
|
160
|
+
### 🔗 Expiring Share Links
|
|
161
|
+
|
|
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.**
|
|
142
163
|
|
|
143
164
|
```bash
|
|
144
|
-
tas share create report.pdf --expire
|
|
145
|
-
# → http://localhost:3000/d/
|
|
165
|
+
tas share create report.pdf --expire 24h --max-downloads 5
|
|
166
|
+
# → http://localhost:3000/d/a1b2c3d4e5f6...
|
|
146
167
|
|
|
147
|
-
tas share
|
|
148
|
-
tas share
|
|
168
|
+
tas share create backup.tar.gz --expire 1h --max-downloads 1 # Burn-after-read
|
|
169
|
+
tas share list # See active links with expiry info
|
|
170
|
+
tas share revoke a1b2c3d4 # Revoke instantly, anytime
|
|
149
171
|
```
|
|
150
172
|
|
|
151
|
-
|
|
152
|
-
|
|
173
|
+
---
|
|
174
|
+
|
|
175
|
+
### 🏷️ Tags & Full-Text Search
|
|
153
176
|
|
|
154
177
|
```bash
|
|
155
|
-
tas tag add report.pdf work Q4
|
|
156
|
-
tas
|
|
157
|
-
tas search
|
|
178
|
+
tas tag add report.pdf work Q4 finance
|
|
179
|
+
tas tag add keys.env secrets production
|
|
180
|
+
tas search "report" # Search by filename pattern
|
|
181
|
+
tas search -t work # All files tagged "work"
|
|
182
|
+
tas search -t secrets # Quickly find your credentials
|
|
158
183
|
```
|
|
159
184
|
|
|
185
|
+
---
|
|
186
|
+
|
|
160
187
|
### 🩺 Self-Diagnostics
|
|
161
|
-
One command to check if everything is healthy.
|
|
162
188
|
|
|
163
189
|
```bash
|
|
164
190
|
tas doctor
|
|
165
191
|
# ✓ Node.js 20.11.0
|
|
166
|
-
# ✓ Config
|
|
167
|
-
# ✓ Database: 42 files, 1.3 GB total
|
|
192
|
+
# ✓ Config v3 (encrypted multi-bot token set)
|
|
193
|
+
# ✓ Database: 42 files, 1.3 GB total across 28 chunks
|
|
168
194
|
# ✓ Disk space: 50 GB free (32% used)
|
|
169
|
-
# ✓ Encryption: AES-256-GCM
|
|
195
|
+
# ✓ Encryption: AES-256-GCM · PBKDF2-SHA512 · 600,000 iterations (OWASP 2025)
|
|
196
|
+
# ✓ FUSE runtime: mount → readdir → unmount passed (Linux)
|
|
197
|
+
# ✓ Telegram connectivity: 2/2 bots OK
|
|
170
198
|
# ✨ All systems go!
|
|
171
199
|
```
|
|
172
200
|
|
|
173
|
-
|
|
174
|
-
|
|
201
|
+
---
|
|
202
|
+
|
|
203
|
+
### 🤖 Built for Automation — CI/CD, Docker, Cron
|
|
204
|
+
|
|
205
|
+
TAS is fully scriptable. No interactive prompts needed when `TAS_PASSWORD` is set.
|
|
175
206
|
|
|
176
207
|
```bash
|
|
177
|
-
|
|
178
|
-
export
|
|
208
|
+
# Environment-based automation
|
|
209
|
+
export TAS_PASSWORD="your-password"
|
|
210
|
+
export TAS_DATA_DIR="/custom/path"
|
|
211
|
+
|
|
212
|
+
# Pipe to jq
|
|
213
|
+
tas list --json | jq '.[].filename'
|
|
214
|
+
tas list --json | jq '.[] | select(.size > 1000000)' # Files > 1MB
|
|
215
|
+
|
|
216
|
+
# GitHub Actions backup step
|
|
217
|
+
tas push db-backup-$(date +%Y%m%d).sql.gz
|
|
179
218
|
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
tas status --json # Machine-readable status
|
|
219
|
+
# cron: nightly backup at 2am
|
|
220
|
+
0 2 * * * TAS_PASSWORD=$SECRET tas push /var/backups/db.tar.gz
|
|
183
221
|
|
|
184
|
-
#
|
|
222
|
+
# JSON machine output everywhere
|
|
223
|
+
tas status --json
|
|
224
|
+
tas list --json
|
|
185
225
|
```
|
|
186
226
|
|
|
187
|
-
|
|
227
|
+
---
|
|
228
|
+
|
|
229
|
+
## 🐳 Docker & CI/CD
|
|
188
230
|
|
|
189
|
-
|
|
231
|
+
```dockerfile
|
|
232
|
+
FROM node:20-alpine
|
|
190
233
|
|
|
191
|
-
|
|
234
|
+
RUN npm install -g @nightowne/tas-cli
|
|
192
235
|
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
| **Cipher** | AES-256-GCM | Same cipher used by governments & banks |
|
|
196
|
-
| **Key Derivation** | PBKDF2-SHA512, **600k iterations** | OWASP 2025 compliant — brute-force resistant |
|
|
197
|
-
| **Salt** | 32 bytes, cryptographically random | Unique per file — no rainbow tables |
|
|
198
|
-
| **IV** | 12 bytes, cryptographically random | Unique per file — no pattern analysis |
|
|
199
|
-
| **Auth Tag** | 16 bytes GCM authentication | Tamper detection — any bit flip = rejected |
|
|
200
|
-
| **Bot Token** | Encrypted at rest (AES-256-GCM) | Even your config file is protected |
|
|
201
|
-
| **Password Hash** | Timing-safe PBKDF2 verification | Resistant to timing side-channel attacks |
|
|
202
|
-
| **Config Permissions** | `chmod 600` on config.json | Other users on your system can't read your credentials |
|
|
203
|
-
| **Integrity** | SHA-256 verified on every download | Bit-perfect downloads, guaranteed |
|
|
204
|
-
| **Share Server** | Localhost-only, XSS-safe, RFC 6266 | Binds to 127.0.0.1 by default — your LAN doesn't see it |
|
|
236
|
+
ENV TAS_PASSWORD=""
|
|
237
|
+
ENV TAS_DATA_DIR="/data"
|
|
205
238
|
|
|
206
|
-
|
|
239
|
+
VOLUME ["/data"]
|
|
207
240
|
|
|
241
|
+
CMD ["tas", "status"]
|
|
208
242
|
```
|
|
209
|
-
|
|
243
|
+
|
|
244
|
+
```yaml
|
|
245
|
+
# .github/workflows/backup.yml
|
|
246
|
+
name: Nightly Backup
|
|
247
|
+
|
|
248
|
+
on:
|
|
249
|
+
schedule:
|
|
250
|
+
- cron: '0 2 * * *'
|
|
251
|
+
|
|
252
|
+
jobs:
|
|
253
|
+
backup:
|
|
254
|
+
runs-on: ubuntu-latest
|
|
255
|
+
steps:
|
|
256
|
+
- name: Install TAS
|
|
257
|
+
run: npm install -g @nightowne/tas-cli
|
|
258
|
+
|
|
259
|
+
- name: Push backup
|
|
260
|
+
env:
|
|
261
|
+
TAS_PASSWORD: ${{ secrets.TAS_PASSWORD }}
|
|
262
|
+
TAS_DATA_DIR: ${{ runner.temp }}/tas-data
|
|
263
|
+
run: |
|
|
264
|
+
tas init --token ${{ secrets.TELEGRAM_BOT_TOKEN }} --chat ${{ secrets.TELEGRAM_CHAT_ID }}
|
|
265
|
+
tar czf backup-$(date +%Y%m%d).tar.gz ./important-data/
|
|
266
|
+
tas push backup-$(date +%Y%m%d).tar.gz
|
|
210
267
|
```
|
|
211
268
|
|
|
212
|
-
|
|
269
|
+
---
|
|
270
|
+
|
|
271
|
+
## 🛡️ Security Model
|
|
272
|
+
|
|
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.
|
|
274
|
+
|
|
275
|
+
| Layer | Implementation | Standard |
|
|
276
|
+
|---|---|---|
|
|
277
|
+
| **Cipher** | AES-256-GCM (authenticated encryption) | NIST FIPS 197 |
|
|
278
|
+
| **Key Derivation** | PBKDF2-SHA512, **600,000 iterations** | OWASP 2025 |
|
|
279
|
+
| **Salt** | 32 bytes, `crypto.randomBytes()` — unique per file | No rainbow tables |
|
|
280
|
+
| **IV/Nonce** | 12 bytes, `crypto.randomBytes()` — unique per file | No nonce reuse |
|
|
281
|
+
| **Auth Tag** | 16 bytes GCM tag — any tampered bit = instant rejection | Tamper detection |
|
|
282
|
+
| **Bot Tokens** | Encrypted independently at rest in `config.json` | Config v3 |
|
|
283
|
+
| **Password Verification** | `crypto.timingSafeEqual()` on both PBKDF2 and legacy paths | Timing-safe |
|
|
284
|
+
| **Config Permissions** | `chmod 600 config.json` on creation | No world-readable secrets |
|
|
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 |
|
|
287
|
+
| **Share Server** | Binds `127.0.0.1` by default, XSS-escaped, RFC 6266 filenames | LAN-safe |
|
|
213
288
|
|
|
214
|
-
|
|
289
|
+
### What Telegram Actually Sees
|
|
290
|
+
|
|
291
|
+
```
|
|
292
|
+
chunk-000000.tas — 12.4 MB — caption: tas:c1:42:1/2
|
|
293
|
+
```
|
|
294
|
+
|
|
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.
|
|
296
|
+
|
|
297
|
+
### Threat Model
|
|
298
|
+
|
|
299
|
+
| Threat | Mitigated? | How |
|
|
300
|
+
|---|---|---|
|
|
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 |
|
|
307
|
+
|
|
308
|
+
---
|
|
215
309
|
|
|
216
310
|
## 🔄 Reliability
|
|
217
311
|
|
|
218
|
-
|
|
312
|
+
Reliability mechanisms implemented by TAS (not an SLA):
|
|
219
313
|
|
|
220
|
-
| Feature |
|
|
221
|
-
|
|
314
|
+
| Feature | Implementation |
|
|
315
|
+
|---|---|
|
|
222
316
|
| **Exponential Backoff** | Auto-retry with jitter on Telegram 429 errors and network timeouts |
|
|
223
|
-
| **Rate Limiting** |
|
|
224
|
-
| **Integrity Verification** | SHA-256 hash
|
|
225
|
-
| **Resume Uploads** |
|
|
226
|
-
| **
|
|
227
|
-
| **
|
|
317
|
+
| **Rate Limiting** | One serialized send queue per configured bot within a TAS process; parallel TAS processes and Telegram's dynamic limits still apply |
|
|
318
|
+
| **Integrity Verification** | SHA-256 hash verified after every single download |
|
|
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 Linux FUSE smoke mount |
|
|
228
323
|
|
|
229
|
-
|
|
324
|
+
---
|
|
230
325
|
|
|
231
326
|
## 📋 CLI Reference
|
|
232
327
|
|
|
@@ -234,16 +329,20 @@ Built like professional backup tools (inspired by restic, rclone, borg):
|
|
|
234
329
|
<summary><strong>Core Commands</strong></summary>
|
|
235
330
|
|
|
236
331
|
```bash
|
|
237
|
-
tas init
|
|
238
|
-
tas push <
|
|
239
|
-
tas pull <file|hash>
|
|
240
|
-
tas list [-l] [--json]
|
|
241
|
-
tas delete <file|hash>
|
|
242
|
-
tas status [--json]
|
|
243
|
-
tas search <query>
|
|
244
|
-
tas resume
|
|
245
|
-
tas verify
|
|
246
|
-
tas
|
|
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
|
+
tas pull <file|hash> # ⬇️ Download + decrypt + verify
|
|
335
|
+
tas list [-l] [--json] # 📋 List all stored files
|
|
336
|
+
tas delete <file|hash> # 🗑️ Remove from index (--hard removes from Telegram)
|
|
337
|
+
tas status [--json] # 📊 Storage stats & database health
|
|
338
|
+
tas search <query> [-t tag] # 🔍 Find by filename or tag
|
|
339
|
+
tas resume # 🔄 Resume interrupted uploads
|
|
340
|
+
tas verify # ✅ Check every Telegram file reference
|
|
341
|
+
tas verify --deep # ✅ Download/decrypt/hash every file (slow and bandwidth-heavy)
|
|
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
|
|
247
346
|
```
|
|
248
347
|
|
|
249
348
|
</details>
|
|
@@ -252,15 +351,15 @@ tas doctor # 🩺 System health check
|
|
|
252
351
|
<summary><strong>Mount & Sync</strong></summary>
|
|
253
352
|
|
|
254
353
|
```bash
|
|
255
|
-
# FUSE Mount (
|
|
256
|
-
tas mount <path>
|
|
257
|
-
tas unmount <path>
|
|
258
|
-
|
|
259
|
-
#
|
|
260
|
-
tas sync add <folder>
|
|
261
|
-
tas sync start
|
|
262
|
-
tas sync pull
|
|
263
|
-
tas sync status
|
|
354
|
+
# FUSE Mount (Linux only in this release)
|
|
355
|
+
tas mount <path> # Mount Telegram storage as a local folder
|
|
356
|
+
tas unmount <path> # Clean unmount
|
|
357
|
+
|
|
358
|
+
# Dropbox-style Folder Sync
|
|
359
|
+
tas sync add <folder> # Register folder for auto-sync
|
|
360
|
+
tas sync start # Start watching for changes
|
|
361
|
+
tas sync pull # Download all synced files locally
|
|
362
|
+
tas sync status # Show sync queue and status
|
|
264
363
|
```
|
|
265
364
|
|
|
266
365
|
</details>
|
|
@@ -269,94 +368,155 @@ tas sync status # Show sync status
|
|
|
269
368
|
<summary><strong>Share & Tags</strong></summary>
|
|
270
369
|
|
|
271
370
|
```bash
|
|
272
|
-
#
|
|
273
|
-
tas share create <file> [--expire 24h] [--max-downloads
|
|
274
|
-
tas share list
|
|
275
|
-
tas share revoke <token>
|
|
276
|
-
|
|
277
|
-
# File
|
|
278
|
-
tas tag add <file> <
|
|
279
|
-
tas tag remove <file> <
|
|
280
|
-
tas tag list [tag]
|
|
371
|
+
# Expiring Share Links
|
|
372
|
+
tas share create <file> [--expire 1h|24h|7d] [--max-downloads N] [--host 0.0.0.0] [--port 3000]
|
|
373
|
+
tas share list # Active links with expiry countdown
|
|
374
|
+
tas share revoke <token> # Instantly revoke a share
|
|
375
|
+
|
|
376
|
+
# File Tagging
|
|
377
|
+
tas tag add <file> <tag> [tag2...]
|
|
378
|
+
tas tag remove <file> <tag>
|
|
379
|
+
tas tag list [tag] # List all tags, or files with a specific tag
|
|
281
380
|
```
|
|
282
381
|
|
|
283
382
|
</details>
|
|
284
383
|
|
|
285
|
-
<
|
|
384
|
+
<details>
|
|
385
|
+
<summary><strong>Environment Variables</strong></summary>
|
|
386
|
+
|
|
387
|
+
```bash
|
|
388
|
+
TAS_PASSWORD="..." # Skip password prompts (CI/CD, cron, Docker)
|
|
389
|
+
TAS_DATA_DIR="/custom/path" # Override default ~/.tas data directory
|
|
390
|
+
```
|
|
391
|
+
|
|
392
|
+
</details>
|
|
393
|
+
|
|
394
|
+
---
|
|
286
395
|
|
|
287
396
|
## 🏗️ Architecture
|
|
288
397
|
|
|
289
398
|
```
|
|
290
399
|
src/
|
|
291
|
-
├── cli.js
|
|
292
|
-
├── index.js
|
|
400
|
+
├── cli.js # Commander-based CLI — all commands defined here
|
|
401
|
+
├── index.js # Core streaming upload/download pipeline
|
|
402
|
+
├── manifest.js # Encrypted remote index backup/rebuild
|
|
293
403
|
├── crypto/
|
|
294
|
-
│ └── encryption.js
|
|
404
|
+
│ └── encryption.js # AES-256-GCM + PBKDF2-SHA512 (600k iterations)
|
|
295
405
|
├── db/
|
|
296
|
-
│ └── index.js
|
|
406
|
+
│ └── index.js # SQLite index: files, chunks, tags, shares, sync
|
|
297
407
|
├── telegram/
|
|
298
|
-
│
|
|
408
|
+
│ ├── client.js # Bot API wrapper — retry + serialized send queue
|
|
409
|
+
│ └── pool.js # Stable per-chunk multi-bot routing
|
|
299
410
|
├── fuse/
|
|
300
|
-
│ └── mount.js
|
|
411
|
+
│ └── mount.js # FUSE filesystem — mount Telegram as a local folder
|
|
301
412
|
├── share/
|
|
302
|
-
│ └── server.js
|
|
413
|
+
│ └── server.js # HTTP server — expiring encrypted share links
|
|
303
414
|
├── sync/
|
|
304
|
-
│ └── sync.js
|
|
415
|
+
│ └── sync.js # fs.watch folder watcher — Dropbox-style auto-sync
|
|
305
416
|
└── utils/
|
|
306
|
-
├── download-stream.js
|
|
307
|
-
├── compression.js
|
|
308
|
-
├── chunker.js
|
|
309
|
-
├──
|
|
310
|
-
├──
|
|
311
|
-
├──
|
|
312
|
-
|
|
417
|
+
├── download-stream.js # Shared Telegram→Decrypt→Decompress pipeline
|
|
418
|
+
├── compression.js # Smart gzip (skips already-compressed formats)
|
|
419
|
+
├── chunker.js # 19 MiB payloads + metadata-free public WAS1 headers
|
|
420
|
+
├── logical-path.js # Portable exact paths + virtual directory tree
|
|
421
|
+
├── progress.js # Terminal progress bars with MB/s + ETA
|
|
422
|
+
├── throttle.js # Bandwidth limiter (stream transform)
|
|
423
|
+
├── branding.js # ASCII art + version display
|
|
424
|
+
└── cli-helpers.js # Password management + config resolution
|
|
313
425
|
```
|
|
314
426
|
|
|
315
|
-
**Tech stack:** Node.js · better-sqlite3 · node-telegram-bot-api · fuse-native · Commander · Chalk · Ora · Inquirer
|
|
427
|
+
**Tech stack:** Node.js 18+ · better-sqlite3 · node-telegram-bot-api · fuse-native · Commander · Chalk · Ora · Inquirer
|
|
316
428
|
|
|
317
|
-
|
|
429
|
+
---
|
|
430
|
+
|
|
431
|
+
## 💡 Perfect For
|
|
432
|
+
|
|
433
|
+
| Use Case | Example |
|
|
434
|
+
|---|---|
|
|
435
|
+
| 📄 **Personal document vault** | Taxes, contracts, scans, receipts — encrypted |
|
|
436
|
+
| 🔑 **Secrets & credentials** | `.env` files, SSH private keys, API tokens |
|
|
437
|
+
| 🗝️ **Password manager sync** | KeePass `.kdbx`, 1Password vaults, Bitwarden exports |
|
|
438
|
+
| 📦 **Code project backups** | Git bundles, build artifacts, config files |
|
|
439
|
+
| 🎬 **Private media archive** | Photos, videos, music — encrypted & searchable |
|
|
440
|
+
| 🔗 **Ephemeral file sharing** | Burn-after-read links with download limits |
|
|
441
|
+
| 💾 **Offsite backup** | Nightly database dumps, system configs via cron |
|
|
442
|
+
| 🤖 **CI/CD artifacts** | Store build outputs, test reports, deployment keys |
|
|
443
|
+
|
|
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.
|
|
445
|
+
|
|
446
|
+
---
|
|
447
|
+
|
|
448
|
+
## ❓ Is This Allowed? (The Legal Question)
|
|
449
|
+
|
|
450
|
+
### Can Telegram restrict or terminate this use?
|
|
451
|
+
|
|
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
|
+
|
|
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
|
+
|
|
456
|
+
---
|
|
318
457
|
|
|
319
458
|
## ⚠️ Good to Know
|
|
320
459
|
|
|
321
460
|
| | |
|
|
322
461
|
|---|---|
|
|
323
|
-
| 📌 **Not a
|
|
324
|
-
| 📌 **
|
|
325
|
-
| 📌 **
|
|
326
|
-
| 📌 **FUSE = Linux
|
|
462
|
+
| 📌 **Not a replacement for backups** | Telegram can purge old messages. Use TAS alongside, not instead of, real backup solutions. |
|
|
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
|
+
| 📌 **FUSE = Linux only for now** | macOS mount is disabled until a maintained modern macFUSE backend and macOS CI exist. |
|
|
466
|
+
| 📌 **Recovery needs config** | `index.db` can be rebuilt from the encrypted manifest only if `config.json`, password, manifest message, and owning bot survive. |
|
|
327
467
|
| 📌 **No versioning (yet)** | Overwriting a file replaces the previous version. |
|
|
468
|
+
| 📌 **Internet required** | Telegram-backed — offline access requires files pulled locally first. |
|
|
328
469
|
|
|
329
|
-
|
|
470
|
+
---
|
|
330
471
|
|
|
331
472
|
## 🛠️ Development
|
|
332
473
|
|
|
333
474
|
```bash
|
|
334
475
|
git clone https://github.com/ixchio/tas
|
|
335
476
|
cd tas && npm install
|
|
336
|
-
|
|
477
|
+
|
|
478
|
+
npm test # Run all 97 tests (crypto, paths, migrations, multi-bot, resume, manifest, sync, shares)
|
|
479
|
+
npm test -- --watch # Watch mode for active development
|
|
337
480
|
```
|
|
338
481
|
|
|
339
|
-
|
|
482
|
+
**Test coverage:** streaming encrypt/decrypt roundtrips · cross-API compat (buffer↔stream) · small-chunk stress testing · truncation/corruption error paths · Unicode filename handling · WAS1 binary header parsing · timing-safe comparison paths
|
|
340
483
|
|
|
341
|
-
|
|
484
|
+
PRs welcome! See [CONTRIBUTING.md](CONTRIBUTING.md) for guidelines.
|
|
485
|
+
|
|
486
|
+
---
|
|
342
487
|
|
|
343
488
|
## 🌟 Contributing
|
|
344
489
|
|
|
345
|
-
TAS is open source and
|
|
490
|
+
TAS is open source and contributions are genuinely appreciated:
|
|
346
491
|
|
|
347
|
-
- 🐛 **Found a bug?** [Open an issue](https://github.com/ixchio/tas/issues)
|
|
348
|
-
- 💡 **Have
|
|
349
|
-
- 🔧 **Want to contribute?** Fork →
|
|
492
|
+
- 🐛 **Found a bug?** [Open an issue](https://github.com/ixchio/tas/issues) — include `tas doctor` output
|
|
493
|
+
- 💡 **Have a feature idea?** [Start a discussion](https://github.com/ixchio/tas/discussions)
|
|
494
|
+
- 🔧 **Want to contribute code?** Fork → branch → PR → 🎉
|
|
495
|
+
- ⭐ **Just want to help?** A GitHub star dramatically increases discoverability
|
|
350
496
|
|
|
351
|
-
|
|
497
|
+
---
|
|
352
498
|
|
|
353
499
|
## 📄 License
|
|
354
500
|
|
|
355
|
-
MIT — use it, fork it, ship it, sell it. Do whatever you want.
|
|
501
|
+
MIT — use it, fork it, ship it, sell it. Do whatever you want with it.
|
|
502
|
+
|
|
503
|
+
---
|
|
504
|
+
|
|
505
|
+
## Related Projects
|
|
506
|
+
|
|
507
|
+
If TAS fits your workflow, you might also find these useful:
|
|
508
|
+
|
|
509
|
+
- [rclone](https://github.com/rclone/rclone) — rsync for cloud storage (dozens of backends)
|
|
510
|
+
- [restic](https://github.com/restic/restic) — encrypted, deduplicated backup program
|
|
511
|
+
- [age](https://github.com/FiloSottile/age) — simple, modern file encryption tool
|
|
512
|
+
- [magic-wormhole](https://github.com/magic-wormhole/magic-wormhole) — encrypted file transfer between machines
|
|
356
513
|
|
|
357
514
|
---
|
|
358
515
|
|
|
359
516
|
<p align="center">
|
|
360
517
|
<sub>Built with ☕ and stubbornness by <a href="https://github.com/ixchio">@ixchio</a></sub><br>
|
|
361
|
-
<sub>If TAS saved you money,
|
|
518
|
+
<sub>If TAS saved you money, a ⭐ on GitHub is the best way to say thanks — it helps others find the project.</sub><br><br>
|
|
519
|
+
<a href="https://github.com/ixchio/tas/stargazers">
|
|
520
|
+
<img src="https://img.shields.io/github/stars/ixchio/tas?style=for-the-badge&logo=github&label=Star%20TAS&color=ffd700" alt="Star TAS on GitHub">
|
|
521
|
+
</a>
|
|
362
522
|
</p>
|