weed-cli 2.1.0__tar.gz → 2.2.0__tar.gz
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.
- {weed_cli-2.1.0 → weed_cli-2.2.0}/PKG-INFO +72 -15
- {weed_cli-2.1.0 → weed_cli-2.2.0}/README.md +71 -14
- {weed_cli-2.1.0 → weed_cli-2.2.0}/node.py +356 -31
- {weed_cli-2.1.0 → weed_cli-2.2.0}/pyproject.toml +1 -1
- {weed_cli-2.1.0 → weed_cli-2.2.0}/shell.py +92 -50
- weed_cli-2.2.0/tests/test_discovery_relay.py +228 -0
- weed_cli-2.2.0/tests/test_timing_challenge.py +175 -0
- weed_cli-2.2.0/tests/test_tunnel_failover.py +143 -0
- {weed_cli-2.1.0 → weed_cli-2.2.0}/tests/test_web_ui_api.py +255 -0
- {weed_cli-2.1.0 → weed_cli-2.2.0}/web_ui.py +444 -31
- {weed_cli-2.1.0 → weed_cli-2.2.0}/weed.py +96 -26
- {weed_cli-2.1.0 → weed_cli-2.2.0}/weed_cli.egg-info/PKG-INFO +72 -15
- {weed_cli-2.1.0 → weed_cli-2.2.0}/weed_cli.egg-info/SOURCES.txt +2 -0
- weed_cli-2.1.0/tests/test_discovery_relay.py +0 -115
- {weed_cli-2.1.0 → weed_cli-2.2.0}/LICENSE +0 -0
- {weed_cli-2.1.0 → weed_cli-2.2.0}/dht.py +0 -0
- {weed_cli-2.1.0 → weed_cli-2.2.0}/discovery_relay.py +0 -0
- {weed_cli-2.1.0 → weed_cli-2.2.0}/lightning_settle.py +0 -0
- {weed_cli-2.1.0 → weed_cli-2.2.0}/poc_reputation.py +0 -0
- {weed_cli-2.1.0 → weed_cli-2.2.0}/setup.cfg +0 -0
- {weed_cli-2.1.0 → weed_cli-2.2.0}/tests/test_dht.py +0 -0
- {weed_cli-2.1.0 → weed_cli-2.2.0}/tests/test_host_live_reload.py +0 -0
- {weed_cli-2.1.0 → weed_cli-2.2.0}/tests/test_node_manifest.py +0 -0
- {weed_cli-2.1.0 → weed_cli-2.2.0}/tests/test_orbit_ws.py +0 -0
- {weed_cli-2.1.0 → weed_cli-2.2.0}/tests/testutil.py +0 -0
- {weed_cli-2.1.0 → weed_cli-2.2.0}/tunnel_relay.py +0 -0
- {weed_cli-2.1.0 → weed_cli-2.2.0}/weed_cli.egg-info/dependency_links.txt +0 -0
- {weed_cli-2.1.0 → weed_cli-2.2.0}/weed_cli.egg-info/entry_points.txt +0 -0
- {weed_cli-2.1.0 → weed_cli-2.2.0}/weed_cli.egg-info/requires.txt +0 -0
- {weed_cli-2.1.0 → weed_cli-2.2.0}/weed_cli.egg-info/top_level.txt +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: weed-cli
|
|
3
|
-
Version: 2.
|
|
3
|
+
Version: 2.2.0
|
|
4
4
|
Summary: Censorship-resistant video PoC — discovery/hosting/download over signed relay events, a real Kademlia DHT, or a TLS-capable NAT-traversal tunnel
|
|
5
5
|
License: MIT
|
|
6
6
|
Keywords: p2p,video,censorship-resistant,discovery,dht,kademlia,nat-traversal
|
|
@@ -116,6 +116,10 @@ weed discover --relay http://127.0.0.1:9101
|
|
|
116
116
|
weed download <content_hash_prefix> --relay http://127.0.0.1:9101 --out downloaded.mp4
|
|
117
117
|
weed like <content_hash> --relay http://127.0.0.1:9101
|
|
118
118
|
weed subscribe <target_pubkey> --relay http://127.0.0.1:9101
|
|
119
|
+
|
|
120
|
+
# --relay is repeatable everywhere: an event goes to every relay named,
|
|
121
|
+
# and this copies anything you signed that one relay has and another lacks
|
|
122
|
+
weed sync-relays --relay http://127.0.0.1:9101 --relay https://relay.example.org
|
|
119
123
|
```
|
|
120
124
|
|
|
121
125
|
`--advertise-host` matters once you're off localhost — there's no NAT
|
|
@@ -160,15 +164,39 @@ weed> download 7f2477c7ea675004ad5dbab6dc7c44327c724b880cc389807df1965b77966acc
|
|
|
160
164
|
`web_ui.py` wraps the same `node.py` functions behind a small stdlib
|
|
161
165
|
JSON API plus a static, no-build-step frontend — host/discover/download/
|
|
162
166
|
like/subscribe without memorizing CLI flags. Binds `127.0.0.1` by
|
|
163
|
-
default (
|
|
164
|
-
|
|
165
|
-
|
|
167
|
+
default (a local control surface, not something meant to face the
|
|
168
|
+
internet); `--bind 0.0.0.0` widens it and auto-detects your real LAN IP
|
|
169
|
+
for the printed/scanned QR code. Auth is optional: `--auth-token` (bare
|
|
170
|
+
for a generated token, or give one; `$WEED_UI_TOKEN` in Docker) gates
|
|
171
|
+
every API call behind a bearer token. The startup QR and printed URL
|
|
172
|
+
then carry it, so scanning is the login; the page shows an unlock
|
|
173
|
+
prompt if opened any other way; the stream URLs it hands to VLC carry
|
|
174
|
+
it as `?token=`, since a player can't send a cookie.
|
|
166
175
|
|
|
167
176
|
```bash
|
|
168
177
|
weed serve # alias for `web`, positional: serve [bind] [port]
|
|
169
178
|
weed serve 0.0.0.0 8080 # reachable from your phone; prints a scan-to-open QR
|
|
179
|
+
weed web --bind 0.0.0.0 --auth-token # same, behind a generated token (printed + in the QR)
|
|
180
|
+
weed web --bind 0.0.0.0 --tls --auth-token --stream-plain-port 8081
|
|
170
181
|
```
|
|
171
182
|
|
|
183
|
+
`--stream-token` (with `--auth-token`) adds a second, guest tier: a
|
|
184
|
+
browser opened with that token gets the **party view** and nothing
|
|
185
|
+
else — the live Orbit stream, what's playing, a vote on which
|
|
186
|
+
downloaded track plays next (one vote per person per track, toggleable),
|
|
187
|
+
and whatever links you set. The admin's **Party** tab holds the guest
|
|
188
|
+
link and its QR code, the title and links, the live tally with a ▶ per
|
|
189
|
+
track, and an "auto-play the top vote when a track ends" switch.
|
|
190
|
+
Guests can't host, download, like, subscribe, or read the library.
|
|
191
|
+
|
|
192
|
+
`--stream-plain-port` adds a plain-HTTP listener that serves *only* the
|
|
193
|
+
stream endpoints (the Orbit MJPEG stream and downloaded files), for
|
|
194
|
+
players that can't do TLS with a self-signed cert — a Roku IP-camera
|
|
195
|
+
viewer, a smart TV. Nothing else is served there, and the token still
|
|
196
|
+
applies (`?token=`). In "IP Camera Viewer for Roku", enter the Pi's IP,
|
|
197
|
+
that port, and `/api/orbit-view?token={0}` as the stream URL with the
|
|
198
|
+
token as the login: the app substitutes `{0}` itself.
|
|
199
|
+
|
|
172
200
|
Includes real HTTP range support (`/api/stream/<job_id>`) so a
|
|
173
201
|
`<video>` tag can seek a completed download instead of downloading it
|
|
174
202
|
blind.
|
|
@@ -233,6 +261,13 @@ hardcode a threshold):
|
|
|
233
261
|
Over real WAN distance (tunneled to a remote box over SSH), the gap is
|
|
234
262
|
~1700x and separates cleanly at a single sample — the hard case this
|
|
235
263
|
PoC stress-tests is two peers that are genuinely close together.
|
|
264
|
+
`node.py`'s real download path runs this after its FETCH-and-verify
|
|
265
|
+
gate: `--timing-rounds` (default 5) nonce challenges per candidate,
|
|
266
|
+
each on a chunk the host hasn't been asked to forward yet (so a relay's
|
|
267
|
+
cache is cold), each timed next to a plain `PRICE` round trip on the
|
|
268
|
+
same socket so the number is a ratio rather than milliseconds. Medians
|
|
269
|
+
break ties in the auction; `--max-timing-ratio` turns it into a hard
|
|
270
|
+
gate.
|
|
236
271
|
|
|
237
272
|
**`poc_reputation.py`** — persistent local reputation plus signed,
|
|
238
273
|
portable attestations (Ed25519, real signing/verification): a client's
|
|
@@ -321,12 +356,18 @@ downloader `CONNECT`s; the relay asks the host to dial back
|
|
|
321
356
|
sockets, no opinion on the tunneled protocol. Supports TLS at the edge
|
|
322
357
|
(`tls://` prefix, for relays like Fly that terminate TLS themselves) and
|
|
323
358
|
a periodic heartbeat so idle control connections survive proxies that
|
|
324
|
-
reset connections after a few minutes of silence.
|
|
359
|
+
reset connections after a few minutes of silence. `--tunnel` is
|
|
360
|
+
repeatable: the host registers with every relay named, the publish
|
|
361
|
+
event lists them all in order, and a downloader tries each in turn —
|
|
362
|
+
probing with a real `INFO` round trip, since a relay accepts any
|
|
363
|
+
`CONNECT` and only afterwards says whether it knows the host — so one
|
|
364
|
+
tunnel relay being down (or restarted, or having never heard of this
|
|
365
|
+
host) is a skipped entry, not a failed download.
|
|
325
366
|
|
|
326
367
|
```bash
|
|
327
368
|
python3 discovery_relay.py 9101
|
|
328
369
|
python3 tunnel_relay.py 9199
|
|
329
|
-
weed host real_archive --port 9201 --tunnel 127.0.0.1:9199 \
|
|
370
|
+
weed host real_archive --port 9201 --tunnel 127.0.0.1:9199 --tunnel tls://tunnel.example.org:9199 \
|
|
330
371
|
--relay http://127.0.0.1:9101 --advertise-host 10.255.255.1
|
|
331
372
|
weed download <content_hash> --relay http://127.0.0.1:9101 --out downloaded.mp4
|
|
332
373
|
```
|
|
@@ -379,10 +420,20 @@ just designed:
|
|
|
379
420
|
Honest edges that are still real constraints even though the core
|
|
380
421
|
mechanisms hold up:
|
|
381
422
|
|
|
382
|
-
-
|
|
383
|
-
|
|
384
|
-
-
|
|
385
|
-
|
|
423
|
+
- The timing challenge is now on the real download path (`node.
|
|
424
|
+
nonce_challenge`: five nonce-salted `CHALLENGE` rounds per candidate,
|
|
425
|
+
each timed against a bytes-free `PRICE` round trip on the same socket,
|
|
426
|
+
medians, reported as a ratio) — but the verdict is still yours. The
|
|
427
|
+
ratio breaks ties in the auction and `--max-timing-ratio` can reject
|
|
428
|
+
on it; there's no default cutoff because the honest-vs-relay
|
|
429
|
+
crossover depends on how close the two are (loopback vs LAN vs WAN).
|
|
430
|
+
Measure it live, then pick a number.
|
|
431
|
+
- Relays still never talk to each other. Every event a node signs now
|
|
432
|
+
goes to every relay it names, the web UI mirrors its own events across
|
|
433
|
+
its relays every few minutes, and `weed sync-relays` does the same on
|
|
434
|
+
demand — but that redundancy is per node, scoped to that node's own
|
|
435
|
+
events by default (`--all` mirrors everyone's). An event whose signer
|
|
436
|
+
only ever named one relay, and never syncs, still dies with it.
|
|
386
437
|
- Lightning settlement is regtest-only, and both sides still have to
|
|
387
438
|
name which of exactly two demo LND identities (`alice`/`bob`) they
|
|
388
439
|
are — the protocol pays whoever really won, but the pool of real
|
|
@@ -390,8 +441,14 @@ mechanisms hold up:
|
|
|
390
441
|
an arbitrary host's own independently-run LND node.
|
|
391
442
|
- The DHT covers host-discovery only, not the richer publish/like/
|
|
392
443
|
subscribe/attestation event system.
|
|
393
|
-
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
doesn't
|
|
397
|
-
|
|
444
|
+
- A host can register with several tunnel relays and downloaders fail
|
|
445
|
+
over between them, but each relay is still a bandwidth cost the host
|
|
446
|
+
can't avoid — every tunneled byte crosses it — and an active download
|
|
447
|
+
doesn't migrate if its relay dies mid-transfer; it restarts on the
|
|
448
|
+
next one.
|
|
449
|
+
- The web UI's auth is two shared bearer tokens (`--auth-token` for
|
|
450
|
+
everything, `--stream-token` for the guest party view), off by default
|
|
451
|
+
and local-only when off. No accounts, no rotation without a restart,
|
|
452
|
+
and votes are anonymous per browser cookie — enough to put a
|
|
453
|
+
LAN-bound UI behind something and hand guests a safe subset, not a
|
|
454
|
+
reason to face it at the internet.
|
|
@@ -84,6 +84,10 @@ weed discover --relay http://127.0.0.1:9101
|
|
|
84
84
|
weed download <content_hash_prefix> --relay http://127.0.0.1:9101 --out downloaded.mp4
|
|
85
85
|
weed like <content_hash> --relay http://127.0.0.1:9101
|
|
86
86
|
weed subscribe <target_pubkey> --relay http://127.0.0.1:9101
|
|
87
|
+
|
|
88
|
+
# --relay is repeatable everywhere: an event goes to every relay named,
|
|
89
|
+
# and this copies anything you signed that one relay has and another lacks
|
|
90
|
+
weed sync-relays --relay http://127.0.0.1:9101 --relay https://relay.example.org
|
|
87
91
|
```
|
|
88
92
|
|
|
89
93
|
`--advertise-host` matters once you're off localhost — there's no NAT
|
|
@@ -128,15 +132,39 @@ weed> download 7f2477c7ea675004ad5dbab6dc7c44327c724b880cc389807df1965b77966acc
|
|
|
128
132
|
`web_ui.py` wraps the same `node.py` functions behind a small stdlib
|
|
129
133
|
JSON API plus a static, no-build-step frontend — host/discover/download/
|
|
130
134
|
like/subscribe without memorizing CLI flags. Binds `127.0.0.1` by
|
|
131
|
-
default (
|
|
132
|
-
|
|
133
|
-
|
|
135
|
+
default (a local control surface, not something meant to face the
|
|
136
|
+
internet); `--bind 0.0.0.0` widens it and auto-detects your real LAN IP
|
|
137
|
+
for the printed/scanned QR code. Auth is optional: `--auth-token` (bare
|
|
138
|
+
for a generated token, or give one; `$WEED_UI_TOKEN` in Docker) gates
|
|
139
|
+
every API call behind a bearer token. The startup QR and printed URL
|
|
140
|
+
then carry it, so scanning is the login; the page shows an unlock
|
|
141
|
+
prompt if opened any other way; the stream URLs it hands to VLC carry
|
|
142
|
+
it as `?token=`, since a player can't send a cookie.
|
|
134
143
|
|
|
135
144
|
```bash
|
|
136
145
|
weed serve # alias for `web`, positional: serve [bind] [port]
|
|
137
146
|
weed serve 0.0.0.0 8080 # reachable from your phone; prints a scan-to-open QR
|
|
147
|
+
weed web --bind 0.0.0.0 --auth-token # same, behind a generated token (printed + in the QR)
|
|
148
|
+
weed web --bind 0.0.0.0 --tls --auth-token --stream-plain-port 8081
|
|
138
149
|
```
|
|
139
150
|
|
|
151
|
+
`--stream-token` (with `--auth-token`) adds a second, guest tier: a
|
|
152
|
+
browser opened with that token gets the **party view** and nothing
|
|
153
|
+
else — the live Orbit stream, what's playing, a vote on which
|
|
154
|
+
downloaded track plays next (one vote per person per track, toggleable),
|
|
155
|
+
and whatever links you set. The admin's **Party** tab holds the guest
|
|
156
|
+
link and its QR code, the title and links, the live tally with a ▶ per
|
|
157
|
+
track, and an "auto-play the top vote when a track ends" switch.
|
|
158
|
+
Guests can't host, download, like, subscribe, or read the library.
|
|
159
|
+
|
|
160
|
+
`--stream-plain-port` adds a plain-HTTP listener that serves *only* the
|
|
161
|
+
stream endpoints (the Orbit MJPEG stream and downloaded files), for
|
|
162
|
+
players that can't do TLS with a self-signed cert — a Roku IP-camera
|
|
163
|
+
viewer, a smart TV. Nothing else is served there, and the token still
|
|
164
|
+
applies (`?token=`). In "IP Camera Viewer for Roku", enter the Pi's IP,
|
|
165
|
+
that port, and `/api/orbit-view?token={0}` as the stream URL with the
|
|
166
|
+
token as the login: the app substitutes `{0}` itself.
|
|
167
|
+
|
|
140
168
|
Includes real HTTP range support (`/api/stream/<job_id>`) so a
|
|
141
169
|
`<video>` tag can seek a completed download instead of downloading it
|
|
142
170
|
blind.
|
|
@@ -201,6 +229,13 @@ hardcode a threshold):
|
|
|
201
229
|
Over real WAN distance (tunneled to a remote box over SSH), the gap is
|
|
202
230
|
~1700x and separates cleanly at a single sample — the hard case this
|
|
203
231
|
PoC stress-tests is two peers that are genuinely close together.
|
|
232
|
+
`node.py`'s real download path runs this after its FETCH-and-verify
|
|
233
|
+
gate: `--timing-rounds` (default 5) nonce challenges per candidate,
|
|
234
|
+
each on a chunk the host hasn't been asked to forward yet (so a relay's
|
|
235
|
+
cache is cold), each timed next to a plain `PRICE` round trip on the
|
|
236
|
+
same socket so the number is a ratio rather than milliseconds. Medians
|
|
237
|
+
break ties in the auction; `--max-timing-ratio` turns it into a hard
|
|
238
|
+
gate.
|
|
204
239
|
|
|
205
240
|
**`poc_reputation.py`** — persistent local reputation plus signed,
|
|
206
241
|
portable attestations (Ed25519, real signing/verification): a client's
|
|
@@ -289,12 +324,18 @@ downloader `CONNECT`s; the relay asks the host to dial back
|
|
|
289
324
|
sockets, no opinion on the tunneled protocol. Supports TLS at the edge
|
|
290
325
|
(`tls://` prefix, for relays like Fly that terminate TLS themselves) and
|
|
291
326
|
a periodic heartbeat so idle control connections survive proxies that
|
|
292
|
-
reset connections after a few minutes of silence.
|
|
327
|
+
reset connections after a few minutes of silence. `--tunnel` is
|
|
328
|
+
repeatable: the host registers with every relay named, the publish
|
|
329
|
+
event lists them all in order, and a downloader tries each in turn —
|
|
330
|
+
probing with a real `INFO` round trip, since a relay accepts any
|
|
331
|
+
`CONNECT` and only afterwards says whether it knows the host — so one
|
|
332
|
+
tunnel relay being down (or restarted, or having never heard of this
|
|
333
|
+
host) is a skipped entry, not a failed download.
|
|
293
334
|
|
|
294
335
|
```bash
|
|
295
336
|
python3 discovery_relay.py 9101
|
|
296
337
|
python3 tunnel_relay.py 9199
|
|
297
|
-
weed host real_archive --port 9201 --tunnel 127.0.0.1:9199 \
|
|
338
|
+
weed host real_archive --port 9201 --tunnel 127.0.0.1:9199 --tunnel tls://tunnel.example.org:9199 \
|
|
298
339
|
--relay http://127.0.0.1:9101 --advertise-host 10.255.255.1
|
|
299
340
|
weed download <content_hash> --relay http://127.0.0.1:9101 --out downloaded.mp4
|
|
300
341
|
```
|
|
@@ -347,10 +388,20 @@ just designed:
|
|
|
347
388
|
Honest edges that are still real constraints even though the core
|
|
348
389
|
mechanisms hold up:
|
|
349
390
|
|
|
350
|
-
-
|
|
351
|
-
|
|
352
|
-
-
|
|
353
|
-
|
|
391
|
+
- The timing challenge is now on the real download path (`node.
|
|
392
|
+
nonce_challenge`: five nonce-salted `CHALLENGE` rounds per candidate,
|
|
393
|
+
each timed against a bytes-free `PRICE` round trip on the same socket,
|
|
394
|
+
medians, reported as a ratio) — but the verdict is still yours. The
|
|
395
|
+
ratio breaks ties in the auction and `--max-timing-ratio` can reject
|
|
396
|
+
on it; there's no default cutoff because the honest-vs-relay
|
|
397
|
+
crossover depends on how close the two are (loopback vs LAN vs WAN).
|
|
398
|
+
Measure it live, then pick a number.
|
|
399
|
+
- Relays still never talk to each other. Every event a node signs now
|
|
400
|
+
goes to every relay it names, the web UI mirrors its own events across
|
|
401
|
+
its relays every few minutes, and `weed sync-relays` does the same on
|
|
402
|
+
demand — but that redundancy is per node, scoped to that node's own
|
|
403
|
+
events by default (`--all` mirrors everyone's). An event whose signer
|
|
404
|
+
only ever named one relay, and never syncs, still dies with it.
|
|
354
405
|
- Lightning settlement is regtest-only, and both sides still have to
|
|
355
406
|
name which of exactly two demo LND identities (`alice`/`bob`) they
|
|
356
407
|
are — the protocol pays whoever really won, but the pool of real
|
|
@@ -358,8 +409,14 @@ mechanisms hold up:
|
|
|
358
409
|
an arbitrary host's own independently-run LND node.
|
|
359
410
|
- The DHT covers host-discovery only, not the richer publish/like/
|
|
360
411
|
subscribe/attestation event system.
|
|
361
|
-
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
doesn't
|
|
365
|
-
|
|
412
|
+
- A host can register with several tunnel relays and downloaders fail
|
|
413
|
+
over between them, but each relay is still a bandwidth cost the host
|
|
414
|
+
can't avoid — every tunneled byte crosses it — and an active download
|
|
415
|
+
doesn't migrate if its relay dies mid-transfer; it restarts on the
|
|
416
|
+
next one.
|
|
417
|
+
- The web UI's auth is two shared bearer tokens (`--auth-token` for
|
|
418
|
+
everything, `--stream-token` for the guest party view), off by default
|
|
419
|
+
and local-only when off. No accounts, no rotation without a restart,
|
|
420
|
+
and votes are anonymous per browser cookie — enough to put a
|
|
421
|
+
LAN-bound UI behind something and hand guests a safe subset, not a
|
|
422
|
+
reason to face it at the internet.
|