copyparty 1.16.8__tar.gz → 1.16.10__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.
Files changed (128) hide show
  1. {copyparty-1.16.8/copyparty.egg-info → copyparty-1.16.10}/PKG-INFO +51 -10
  2. copyparty-1.16.8/PKG-INFO → copyparty-1.16.10/README.md +48 -64
  3. {copyparty-1.16.8 → copyparty-1.16.10}/copyparty/__main__.py +34 -13
  4. {copyparty-1.16.8 → copyparty-1.16.10}/copyparty/__version__.py +2 -2
  5. {copyparty-1.16.8 → copyparty-1.16.10}/copyparty/authsrv.py +8 -1
  6. {copyparty-1.16.8 → copyparty-1.16.10}/copyparty/cfg.py +6 -0
  7. {copyparty-1.16.8 → copyparty-1.16.10}/copyparty/dxml.py +48 -3
  8. {copyparty-1.16.8 → copyparty-1.16.10}/copyparty/httpcli.py +40 -9
  9. {copyparty-1.16.8 → copyparty-1.16.10}/copyparty/svchub.py +13 -0
  10. {copyparty-1.16.8 → copyparty-1.16.10}/copyparty/th_cli.py +6 -2
  11. {copyparty-1.16.8 → copyparty-1.16.10}/copyparty/th_srv.py +100 -41
  12. {copyparty-1.16.8 → copyparty-1.16.10}/copyparty/up2k.py +11 -5
  13. {copyparty-1.16.8 → copyparty-1.16.10}/copyparty/util.py +163 -8
  14. {copyparty-1.16.8 → copyparty-1.16.10}/copyparty/web/a/u2c.py +3 -3
  15. {copyparty-1.16.8 → copyparty-1.16.10}/copyparty/web/browser.css.gz +0 -0
  16. copyparty-1.16.10/copyparty/web/browser.js.gz +0 -0
  17. copyparty-1.16.10/copyparty/web/md.js.gz +0 -0
  18. copyparty-1.16.10/copyparty/web/md2.js.gz +0 -0
  19. {copyparty-1.16.8 → copyparty-1.16.10}/copyparty/web/svcs.html +1 -1
  20. copyparty-1.16.10/copyparty/web/svcs.js.gz +0 -0
  21. copyparty-1.16.10/copyparty/web/up2k.js.gz +0 -0
  22. copyparty-1.16.10/copyparty/web/util.js.gz +0 -0
  23. copyparty-1.16.8/README.md → copyparty-1.16.10/copyparty.egg-info/PKG-INFO +105 -9
  24. {copyparty-1.16.8 → copyparty-1.16.10}/copyparty.egg-info/requires.txt +3 -0
  25. {copyparty-1.16.8 → copyparty-1.16.10}/pyproject.toml +1 -0
  26. copyparty-1.16.8/copyparty/web/browser.js.gz +0 -0
  27. copyparty-1.16.8/copyparty/web/md.js.gz +0 -0
  28. copyparty-1.16.8/copyparty/web/md2.js.gz +0 -0
  29. copyparty-1.16.8/copyparty/web/svcs.js.gz +0 -0
  30. copyparty-1.16.8/copyparty/web/up2k.js.gz +0 -0
  31. copyparty-1.16.8/copyparty/web/util.js.gz +0 -0
  32. {copyparty-1.16.8 → copyparty-1.16.10}/LICENSE +0 -0
  33. {copyparty-1.16.8 → copyparty-1.16.10}/copyparty/__init__.py +0 -0
  34. {copyparty-1.16.8 → copyparty-1.16.10}/copyparty/bos/__init__.py +0 -0
  35. {copyparty-1.16.8 → copyparty-1.16.10}/copyparty/bos/bos.py +0 -0
  36. {copyparty-1.16.8 → copyparty-1.16.10}/copyparty/bos/path.py +0 -0
  37. {copyparty-1.16.8 → copyparty-1.16.10}/copyparty/broker_mp.py +0 -0
  38. {copyparty-1.16.8 → copyparty-1.16.10}/copyparty/broker_mpw.py +0 -0
  39. {copyparty-1.16.8 → copyparty-1.16.10}/copyparty/broker_thr.py +0 -0
  40. {copyparty-1.16.8 → copyparty-1.16.10}/copyparty/broker_util.py +0 -0
  41. {copyparty-1.16.8 → copyparty-1.16.10}/copyparty/cert.py +0 -0
  42. {copyparty-1.16.8 → copyparty-1.16.10}/copyparty/fsutil.py +0 -0
  43. {copyparty-1.16.8 → copyparty-1.16.10}/copyparty/ftpd.py +0 -0
  44. {copyparty-1.16.8 → copyparty-1.16.10}/copyparty/httpconn.py +0 -0
  45. {copyparty-1.16.8 → copyparty-1.16.10}/copyparty/httpsrv.py +0 -0
  46. {copyparty-1.16.8 → copyparty-1.16.10}/copyparty/ico.py +0 -0
  47. {copyparty-1.16.8 → copyparty-1.16.10}/copyparty/mdns.py +0 -0
  48. {copyparty-1.16.8 → copyparty-1.16.10}/copyparty/metrics.py +0 -0
  49. {copyparty-1.16.8 → copyparty-1.16.10}/copyparty/mtag.py +0 -0
  50. {copyparty-1.16.8 → copyparty-1.16.10}/copyparty/multicast.py +0 -0
  51. {copyparty-1.16.8 → copyparty-1.16.10}/copyparty/pwhash.py +0 -0
  52. {copyparty-1.16.8 → copyparty-1.16.10}/copyparty/res/COPYING.txt +0 -0
  53. {copyparty-1.16.8 → copyparty-1.16.10}/copyparty/res/__init__.py +0 -0
  54. {copyparty-1.16.8 → copyparty-1.16.10}/copyparty/res/insecure.pem +0 -0
  55. {copyparty-1.16.8 → copyparty-1.16.10}/copyparty/smbd.py +0 -0
  56. {copyparty-1.16.8 → copyparty-1.16.10}/copyparty/ssdp.py +0 -0
  57. {copyparty-1.16.8 → copyparty-1.16.10}/copyparty/star.py +0 -0
  58. {copyparty-1.16.8 → copyparty-1.16.10}/copyparty/stolen/__init__.py +0 -0
  59. {copyparty-1.16.8 → copyparty-1.16.10}/copyparty/stolen/dnslib/__init__.py +0 -0
  60. {copyparty-1.16.8 → copyparty-1.16.10}/copyparty/stolen/dnslib/bimap.py +0 -0
  61. {copyparty-1.16.8 → copyparty-1.16.10}/copyparty/stolen/dnslib/bit.py +0 -0
  62. {copyparty-1.16.8 → copyparty-1.16.10}/copyparty/stolen/dnslib/buffer.py +0 -0
  63. {copyparty-1.16.8 → copyparty-1.16.10}/copyparty/stolen/dnslib/dns.py +0 -0
  64. {copyparty-1.16.8 → copyparty-1.16.10}/copyparty/stolen/dnslib/label.py +0 -0
  65. {copyparty-1.16.8 → copyparty-1.16.10}/copyparty/stolen/dnslib/lex.py +0 -0
  66. {copyparty-1.16.8 → copyparty-1.16.10}/copyparty/stolen/dnslib/ranges.py +0 -0
  67. {copyparty-1.16.8 → copyparty-1.16.10}/copyparty/stolen/ifaddr/__init__.py +0 -0
  68. {copyparty-1.16.8 → copyparty-1.16.10}/copyparty/stolen/ifaddr/_posix.py +0 -0
  69. {copyparty-1.16.8 → copyparty-1.16.10}/copyparty/stolen/ifaddr/_shared.py +0 -0
  70. {copyparty-1.16.8 → copyparty-1.16.10}/copyparty/stolen/ifaddr/_win32.py +0 -0
  71. {copyparty-1.16.8 → copyparty-1.16.10}/copyparty/stolen/qrcodegen.py +0 -0
  72. {copyparty-1.16.8 → copyparty-1.16.10}/copyparty/stolen/surrogateescape.py +0 -0
  73. {copyparty-1.16.8 → copyparty-1.16.10}/copyparty/sutil.py +0 -0
  74. {copyparty-1.16.8 → copyparty-1.16.10}/copyparty/szip.py +0 -0
  75. {copyparty-1.16.8 → copyparty-1.16.10}/copyparty/tcpsrv.py +0 -0
  76. {copyparty-1.16.8 → copyparty-1.16.10}/copyparty/tftpd.py +0 -0
  77. {copyparty-1.16.8 → copyparty-1.16.10}/copyparty/u2idx.py +0 -0
  78. {copyparty-1.16.8 → copyparty-1.16.10}/copyparty/web/a/__init__.py +0 -0
  79. {copyparty-1.16.8 → copyparty-1.16.10}/copyparty/web/a/partyfuse.py +0 -0
  80. {copyparty-1.16.8 → copyparty-1.16.10}/copyparty/web/a/webdav-cfg.bat +0 -0
  81. {copyparty-1.16.8 → copyparty-1.16.10}/copyparty/web/baguettebox.js.gz +0 -0
  82. {copyparty-1.16.8 → copyparty-1.16.10}/copyparty/web/browser.html +0 -0
  83. {copyparty-1.16.8 → copyparty-1.16.10}/copyparty/web/browser2.html +0 -0
  84. {copyparty-1.16.8 → copyparty-1.16.10}/copyparty/web/cf.html +0 -0
  85. {copyparty-1.16.8 → copyparty-1.16.10}/copyparty/web/dbg-audio.js.gz +0 -0
  86. {copyparty-1.16.8 → copyparty-1.16.10}/copyparty/web/dd/2.png +0 -0
  87. {copyparty-1.16.8 → copyparty-1.16.10}/copyparty/web/dd/3.png +0 -0
  88. {copyparty-1.16.8 → copyparty-1.16.10}/copyparty/web/dd/4.png +0 -0
  89. {copyparty-1.16.8 → copyparty-1.16.10}/copyparty/web/dd/5.png +0 -0
  90. {copyparty-1.16.8 → copyparty-1.16.10}/copyparty/web/dd/__init__.py +0 -0
  91. {copyparty-1.16.8 → copyparty-1.16.10}/copyparty/web/deps/__init__.py +0 -0
  92. {copyparty-1.16.8 → copyparty-1.16.10}/copyparty/web/deps/busy.mp3.gz +0 -0
  93. {copyparty-1.16.8 → copyparty-1.16.10}/copyparty/web/deps/easymde.css.gz +0 -0
  94. {copyparty-1.16.8 → copyparty-1.16.10}/copyparty/web/deps/easymde.js.gz +0 -0
  95. {copyparty-1.16.8 → copyparty-1.16.10}/copyparty/web/deps/fuse.py +0 -0
  96. {copyparty-1.16.8 → copyparty-1.16.10}/copyparty/web/deps/marked.js.gz +0 -0
  97. {copyparty-1.16.8 → copyparty-1.16.10}/copyparty/web/deps/mini-fa.css.gz +0 -0
  98. {copyparty-1.16.8 → copyparty-1.16.10}/copyparty/web/deps/mini-fa.woff +0 -0
  99. {copyparty-1.16.8 → copyparty-1.16.10}/copyparty/web/deps/prism.css.gz +0 -0
  100. {copyparty-1.16.8 → copyparty-1.16.10}/copyparty/web/deps/prism.js.gz +0 -0
  101. {copyparty-1.16.8 → copyparty-1.16.10}/copyparty/web/deps/prismd.css.gz +0 -0
  102. {copyparty-1.16.8 → copyparty-1.16.10}/copyparty/web/deps/scp.woff2 +0 -0
  103. {copyparty-1.16.8 → copyparty-1.16.10}/copyparty/web/deps/sha512.ac.js.gz +0 -0
  104. {copyparty-1.16.8 → copyparty-1.16.10}/copyparty/web/deps/sha512.hw.js.gz +0 -0
  105. {copyparty-1.16.8 → copyparty-1.16.10}/copyparty/web/md.css.gz +0 -0
  106. {copyparty-1.16.8 → copyparty-1.16.10}/copyparty/web/md.html +0 -0
  107. {copyparty-1.16.8 → copyparty-1.16.10}/copyparty/web/md2.css.gz +0 -0
  108. {copyparty-1.16.8 → copyparty-1.16.10}/copyparty/web/mde.css.gz +0 -0
  109. {copyparty-1.16.8 → copyparty-1.16.10}/copyparty/web/mde.html +0 -0
  110. {copyparty-1.16.8 → copyparty-1.16.10}/copyparty/web/mde.js.gz +0 -0
  111. {copyparty-1.16.8 → copyparty-1.16.10}/copyparty/web/msg.css.gz +0 -0
  112. {copyparty-1.16.8 → copyparty-1.16.10}/copyparty/web/msg.html +0 -0
  113. {copyparty-1.16.8 → copyparty-1.16.10}/copyparty/web/rups.css.gz +0 -0
  114. {copyparty-1.16.8 → copyparty-1.16.10}/copyparty/web/rups.html +0 -0
  115. {copyparty-1.16.8 → copyparty-1.16.10}/copyparty/web/rups.js.gz +0 -0
  116. {copyparty-1.16.8 → copyparty-1.16.10}/copyparty/web/shares.css.gz +0 -0
  117. {copyparty-1.16.8 → copyparty-1.16.10}/copyparty/web/shares.html +0 -0
  118. {copyparty-1.16.8 → copyparty-1.16.10}/copyparty/web/shares.js.gz +0 -0
  119. {copyparty-1.16.8 → copyparty-1.16.10}/copyparty/web/splash.css.gz +0 -0
  120. {copyparty-1.16.8 → copyparty-1.16.10}/copyparty/web/splash.html +0 -0
  121. {copyparty-1.16.8 → copyparty-1.16.10}/copyparty/web/splash.js.gz +0 -0
  122. {copyparty-1.16.8 → copyparty-1.16.10}/copyparty/web/ui.css.gz +0 -0
  123. {copyparty-1.16.8 → copyparty-1.16.10}/copyparty/web/w.hash.js.gz +0 -0
  124. {copyparty-1.16.8 → copyparty-1.16.10}/copyparty.egg-info/SOURCES.txt +0 -0
  125. {copyparty-1.16.8 → copyparty-1.16.10}/copyparty.egg-info/dependency_links.txt +0 -0
  126. {copyparty-1.16.8 → copyparty-1.16.10}/copyparty.egg-info/entry_points.txt +0 -0
  127. {copyparty-1.16.8 → copyparty-1.16.10}/copyparty.egg-info/top_level.txt +0 -0
  128. {copyparty-1.16.8 → copyparty-1.16.10}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.2
2
2
  Name: copyparty
3
- Version: 1.16.8
3
+ Version: 1.16.10
4
4
  Summary: Portable file server with accelerated resumable uploads, deduplication, WebDAV, FTP, zeroconf, media indexer, video thumbnails, audio transcoding, and write-only folders
5
5
  Author-email: ed <copyparty@ocv.me>
6
6
  License: MIT
@@ -52,6 +52,8 @@ Provides-Extra: tftpd
52
52
  Requires-Dist: partftpy>=0.4.0; extra == "tftpd"
53
53
  Provides-Extra: pwhash
54
54
  Requires-Dist: argon2-cffi; extra == "pwhash"
55
+ Provides-Extra: zeromq
56
+ Requires-Dist: pyzmq; extra == "zeromq"
55
57
 
56
58
  <img src="https://github.com/9001/copyparty/raw/hovudstraum/docs/logo.svg" width="250" align="right"/>
57
59
 
@@ -135,6 +137,7 @@ turn almost any device into a file server with resumable uploads/downloads using
135
137
  * [metadata from audio files](#metadata-from-audio-files) - set `-e2t` to index tags on upload
136
138
  * [file parser plugins](#file-parser-plugins) - provide custom parsers to index additional tags
137
139
  * [event hooks](#event-hooks) - trigger a program on uploads, renames etc ([examples](./bin/hooks/))
140
+ * [zeromq](#zeromq) - event-hooks can send zeromq messages
138
141
  * [upload events](#upload-events) - the older, more powerful approach ([examples](./bin/mtag/))
139
142
  * [handlers](#handlers) - redefine behavior with plugins ([examples](./bin/handlers/))
140
143
  * [ip auth](#ip-auth) - autologin based on IP range (CIDR)
@@ -407,10 +410,19 @@ same order here too
407
410
  * iPhones: the volume control doesn't work because [apple doesn't want it to](https://developer.apple.com/library/archive/documentation/AudioVideo/Conceptual/Using_HTML5_Audio_Video/Device-SpecificConsiderations/Device-SpecificConsiderations.html#//apple_ref/doc/uid/TP40009523-CH5-SW11)
408
411
  * `AudioContext` will probably never be a viable workaround as apple introduces new issues faster than they fix current ones
409
412
 
413
+ * iPhones: music volume goes on a rollercoaster during song changes
414
+ * nothing I can do about it because `AudioContext` is still broken in safari
415
+
410
416
  * iPhones: the preload feature (in the media-player-options tab) can cause a tiny audio glitch 20sec before the end of each song, but disabling it may cause worse iOS bugs to appear instead
411
417
  * just a hunch, but disabling preloading may cause playback to stop entirely, or possibly mess with bluetooth speakers
412
418
  * tried to add a tooltip regarding this but looks like apple broke my tooltips
413
419
 
420
+ * iPhones: preloaded awo files make safari log MEDIA_ERR_NETWORK errors as playback starts, but the song plays just fine so eh whatever
421
+ * awo, opus-weba, is apple's new take on opus support, replacing opus-caf which was technically limited to cbr opus
422
+
423
+ * iPhones: preloading another awo file may cause playback to stop
424
+ * can be somewhat mitigated with `mp.au.play()` in `mp.onpreload` but that can hit a race condition in safari that starts playing the same audio object twice in parallel...
425
+
414
426
  * Windows: folders cannot be accessed if the name ends with `.`
415
427
  * python or windows bug
416
428
 
@@ -670,8 +682,8 @@ select which type of archive you want in the `[⚙️] config` tab:
670
682
  | `pax` | `?tar=pax` | pax-format tar, futureproof, not as fast |
671
683
  | `tgz` | `?tar=gz` | gzip compressed gnu-tar (slow), for `curl \| tar -xvz` |
672
684
  | `txz` | `?tar=xz` | gnu-tar with xz / lzma compression (v.slow) |
673
- | `zip` | `?zip=utf8` | works everywhere, glitchy filenames on win7 and older |
674
- | `zip_dos` | `?zip` | traditional cp437 (no unicode) to fix glitchy filenames |
685
+ | `zip` | `?zip` | works everywhere, glitchy filenames on win7 and older |
686
+ | `zip_dos` | `?zip=dos` | traditional cp437 (no unicode) to fix glitchy filenames |
675
687
  | `zip_crc` | `?zip=crc` | cp437 with crc32 computed early for truly ancient software |
676
688
 
677
689
  * gzip default level is `3` (0=fast, 9=best), change with `?tar=gz:9`
@@ -679,7 +691,7 @@ select which type of archive you want in the `[⚙️] config` tab:
679
691
  * bz2 default level is `2` (1=fast, 9=best), change with `?tar=bz2:9`
680
692
  * hidden files ([dotfiles](#dotfiles)) are excluded unless account is allowed to list them
681
693
  * `up2k.db` and `dir.txt` is always excluded
682
- * bsdtar supports streaming unzipping: `curl foo?zip=utf8 | bsdtar -xv`
694
+ * bsdtar supports streaming unzipping: `curl foo?zip | bsdtar -xv`
683
695
  * good, because copyparty's zip is faster than tar on small files
684
696
  * `zip_crc` will take longer to download since the server has to read each file twice
685
697
  * this is only to support MS-DOS PKZIP v2.04g (october 1993) and older
@@ -942,6 +954,8 @@ will show uploader IP and upload-time if the visitor has the admin permission
942
954
 
943
955
  * global-option `--ups-when` makes upload-time visible to all users, and not just admins
944
956
 
957
+ * global-option `--ups-who` (volflag `ups_who`) specifies who gets access (0=nobody, 1=admins, 2=everyone), default=2
958
+
945
959
  note that the [🧯 unpost](#unpost) feature is better suited for viewing *your own* recent uploads, as it includes the option to undo/delete them
946
960
 
947
961
 
@@ -981,6 +995,11 @@ open the `[🎺]` media-player-settings tab to configure it,
981
995
  * `[aac]` converts `aac` and `m4a` files into opus (if supported by browser) or mp3
982
996
  * `[oth]` converts all other known formats into opus (if supported by browser) or mp3
983
997
  * `aac|ac3|aif|aiff|alac|alaw|amr|ape|au|dfpwm|dts|flac|gsm|it|m4a|mo3|mod|mp2|mp3|mpc|mptm|mt2|mulaw|ogg|okt|opus|ra|s3m|tak|tta|ulaw|wav|wma|wv|xm|xpk`
998
+ * "transcode to":
999
+ * `[opus]` produces an `opus` whenever transcoding is necessary (the best choice on Android and PCs)
1000
+ * `[awo]` is `opus` in a `weba` file, good for iPhones (iOS 17.5 and newer) but Apple is still fixing some state-confusion bugs as of iOS 18.2.1
1001
+ * `[caf]` is `opus` in a `caf` file, good for iPhones (iOS 11 through 17), technically unsupported by Apple but works for the mos tpart
1002
+ * `[mp3]` -- the myth, the legend, the undying master of mediocre sound quality that definitely works everywhere
984
1003
  * "tint" reduces the contrast of the playback bar
985
1004
 
986
1005
 
@@ -1513,6 +1532,23 @@ there's a bunch of flags and stuff, see `--help-hooks`
1513
1532
  if you want to write your own hooks, see [devnotes](./docs/devnotes.md#event-hooks)
1514
1533
 
1515
1534
 
1535
+ ### zeromq
1536
+
1537
+ event-hooks can send zeromq messages instead of running programs
1538
+
1539
+ to send a 0mq message every time a file is uploaded,
1540
+
1541
+ * `--xau zmq:pub:tcp://*:5556` sends a PUB to any/all connected SUB clients
1542
+ * `--xau t3,zmq:push:tcp://*:5557` sends a PUSH to exactly one connected PULL client
1543
+ * `--xau t3,j,zmq:req:tcp://localhost:5555` sends a REQ to the connected REP client
1544
+
1545
+ the PUSH and REQ examples have `t3` (timeout after 3 seconds) because they block if there's no clients to talk to
1546
+
1547
+ * the REQ example does `t3,j` to send extended upload-info as json instead of just the filesystem-path
1548
+
1549
+ see [zmq-recv.py](https://github.com/9001/copyparty/blob/hovudstraum/bin/zmq-recv.py) if you need something to receive the messages with
1550
+
1551
+
1516
1552
  ### upload events
1517
1553
 
1518
1554
  the older, more powerful approach ([examples](./bin/mtag/)):
@@ -1600,12 +1636,16 @@ connecting to an aws s3 bucket and similar
1600
1636
 
1601
1637
  there is no built-in support for this, but you can use FUSE-software such as [rclone](https://rclone.org/) / [geesefs](https://github.com/yandex-cloud/geesefs) / [JuiceFS](https://juicefs.com/en/) to first mount your cloud storage as a local disk, and then let copyparty use (a folder in) that disk as a volume
1602
1638
 
1603
- you may experience poor upload performance this way, but that can sometimes be fixed by specifying the volflag `sparse` to force the use of sparse files; this has improved the upload speeds from `1.5 MiB/s` to over `80 MiB/s` in one case, but note that you are also more likely to discover funny bugs in your FUSE software this way, so buckle up
1639
+ you will probably get decent speeds with the default config, however most likely restricted to using one TCP connection per file, so the upload-client won't be able to send multiple chunks in parallel
1640
+
1641
+ > before [v1.13.5](https://github.com/9001/copyparty/releases/tag/v1.13.5) it was recommended to use the volflag `sparse` to force-allow multiple chunks in parallel; this would improve the upload-speed from `1.5 MiB/s` to over `80 MiB/s` at the risk of provoking latent bugs in S3 or JuiceFS. But v1.13.5 added chunk-stitching, so this is now probably much less important. On the contrary, `nosparse` *may* now increase performance in some cases. Please try all three options (default, `sparse`, `nosparse`) as the optimal choice depends on your network conditions and software stack (both the FUSE-driver and cloud-server)
1604
1642
 
1605
1643
  someone has also tested geesefs in combination with [gocryptfs](https://nuetzlich.net/gocryptfs/) with surprisingly good results, getting 60 MiB/s upload speeds on a gbit line, but JuiceFS won with 80 MiB/s using its built-in encryption
1606
1644
 
1607
1645
  you may improve performance by specifying larger values for `--iobuf` / `--s-rd-sz` / `--s-wr-sz`
1608
1646
 
1647
+ > if you've experimented with this and made interesting observations, please share your findings so we can add a section with specific recommendations :-)
1648
+
1609
1649
 
1610
1650
  ## hiding from google
1611
1651
 
@@ -2359,13 +2399,13 @@ mandatory deps:
2359
2399
 
2360
2400
  install these to enable bonus features
2361
2401
 
2362
- enable hashed passwords in config: `argon2-cffi`
2402
+ enable [hashed passwords](#password-hashing) in config: `argon2-cffi`
2363
2403
 
2364
- enable ftp-server:
2404
+ enable [ftp-server](#ftp-server):
2365
2405
  * for just plaintext FTP, `pyftpdlib` (is built into the SFX)
2366
2406
  * with TLS encryption, `pyftpdlib pyopenssl`
2367
2407
 
2368
- enable music tags:
2408
+ enable [music tags](#metadata-from-audio-files):
2369
2409
  * either `mutagen` (fast, pure-python, skips a few tags, makes copyparty GPL? idk)
2370
2410
  * or `ffprobe` (20x slower, more accurate, possibly dangerous depending on your distro and users)
2371
2411
 
@@ -2376,8 +2416,9 @@ enable [thumbnails](#thumbnails) of...
2376
2416
  * **AVIF pictures:** `pyvips` or `ffmpeg` or `pillow-avif-plugin`
2377
2417
  * **JPEG XL pictures:** `pyvips` or `ffmpeg`
2378
2418
 
2379
- enable [smb](#smb-server) support (**not** recommended):
2380
- * `impacket==0.12.0`
2419
+ enable sending [zeromq messages](#zeromq) from event-hooks: `pyzmq`
2420
+
2421
+ enable [smb](#smb-server) support (**not** recommended): `impacket==0.12.0`
2381
2422
 
2382
2423
  `pyvips` gives higher quality thumbnails than `Pillow` and is 320% faster, using 270% more ram: `sudo apt install libvips42 && python3 -m pip install --user -U pyvips`
2383
2424
 
@@ -1,58 +1,3 @@
1
- Metadata-Version: 2.2
2
- Name: copyparty
3
- Version: 1.16.8
4
- Summary: Portable file server with accelerated resumable uploads, deduplication, WebDAV, FTP, zeroconf, media indexer, video thumbnails, audio transcoding, and write-only folders
5
- Author-email: ed <copyparty@ocv.me>
6
- License: MIT
7
- Project-URL: Source Code, https://github.com/9001/copyparty
8
- Project-URL: Bug Tracker, https://github.com/9001/copyparty/issues
9
- Project-URL: Demo Server, https://a.ocv.me/pub/demo/
10
- Classifier: Development Status :: 5 - Production/Stable
11
- Classifier: License :: OSI Approved :: MIT License
12
- Classifier: Programming Language :: Python
13
- Classifier: Programming Language :: Python :: 3
14
- Classifier: Programming Language :: Python :: 3.3
15
- Classifier: Programming Language :: Python :: 3.4
16
- Classifier: Programming Language :: Python :: 3.5
17
- Classifier: Programming Language :: Python :: 3.6
18
- Classifier: Programming Language :: Python :: 3.7
19
- Classifier: Programming Language :: Python :: 3.8
20
- Classifier: Programming Language :: Python :: 3.9
21
- Classifier: Programming Language :: Python :: 3.10
22
- Classifier: Programming Language :: Python :: 3.11
23
- Classifier: Programming Language :: Python :: 3.12
24
- Classifier: Programming Language :: Python :: 3.13
25
- Classifier: Programming Language :: Python :: Implementation :: CPython
26
- Classifier: Programming Language :: Python :: Implementation :: Jython
27
- Classifier: Programming Language :: Python :: Implementation :: PyPy
28
- Classifier: Operating System :: OS Independent
29
- Classifier: Environment :: Console
30
- Classifier: Environment :: No Input/Output (Daemon)
31
- Classifier: Intended Audience :: End Users/Desktop
32
- Classifier: Intended Audience :: System Administrators
33
- Classifier: Topic :: Communications :: File Sharing
34
- Classifier: Topic :: Internet :: File Transfer Protocol (FTP)
35
- Classifier: Topic :: Internet :: WWW/HTTP :: HTTP Servers
36
- Requires-Python: >=3.3
37
- Description-Content-Type: text/markdown
38
- License-File: LICENSE
39
- Requires-Dist: Jinja2
40
- Provides-Extra: thumbnails
41
- Requires-Dist: Pillow; extra == "thumbnails"
42
- Provides-Extra: thumbnails2
43
- Requires-Dist: pyvips; extra == "thumbnails2"
44
- Provides-Extra: audiotags
45
- Requires-Dist: mutagen; extra == "audiotags"
46
- Provides-Extra: ftpd
47
- Requires-Dist: pyftpdlib; extra == "ftpd"
48
- Provides-Extra: ftps
49
- Requires-Dist: pyftpdlib; extra == "ftps"
50
- Requires-Dist: pyopenssl; extra == "ftps"
51
- Provides-Extra: tftpd
52
- Requires-Dist: partftpy>=0.4.0; extra == "tftpd"
53
- Provides-Extra: pwhash
54
- Requires-Dist: argon2-cffi; extra == "pwhash"
55
-
56
1
  <img src="https://github.com/9001/copyparty/raw/hovudstraum/docs/logo.svg" width="250" align="right"/>
57
2
 
58
3
  ### 💾🎉 copyparty
@@ -135,6 +80,7 @@ turn almost any device into a file server with resumable uploads/downloads using
135
80
  * [metadata from audio files](#metadata-from-audio-files) - set `-e2t` to index tags on upload
136
81
  * [file parser plugins](#file-parser-plugins) - provide custom parsers to index additional tags
137
82
  * [event hooks](#event-hooks) - trigger a program on uploads, renames etc ([examples](./bin/hooks/))
83
+ * [zeromq](#zeromq) - event-hooks can send zeromq messages
138
84
  * [upload events](#upload-events) - the older, more powerful approach ([examples](./bin/mtag/))
139
85
  * [handlers](#handlers) - redefine behavior with plugins ([examples](./bin/handlers/))
140
86
  * [ip auth](#ip-auth) - autologin based on IP range (CIDR)
@@ -407,10 +353,19 @@ same order here too
407
353
  * iPhones: the volume control doesn't work because [apple doesn't want it to](https://developer.apple.com/library/archive/documentation/AudioVideo/Conceptual/Using_HTML5_Audio_Video/Device-SpecificConsiderations/Device-SpecificConsiderations.html#//apple_ref/doc/uid/TP40009523-CH5-SW11)
408
354
  * `AudioContext` will probably never be a viable workaround as apple introduces new issues faster than they fix current ones
409
355
 
356
+ * iPhones: music volume goes on a rollercoaster during song changes
357
+ * nothing I can do about it because `AudioContext` is still broken in safari
358
+
410
359
  * iPhones: the preload feature (in the media-player-options tab) can cause a tiny audio glitch 20sec before the end of each song, but disabling it may cause worse iOS bugs to appear instead
411
360
  * just a hunch, but disabling preloading may cause playback to stop entirely, or possibly mess with bluetooth speakers
412
361
  * tried to add a tooltip regarding this but looks like apple broke my tooltips
413
362
 
363
+ * iPhones: preloaded awo files make safari log MEDIA_ERR_NETWORK errors as playback starts, but the song plays just fine so eh whatever
364
+ * awo, opus-weba, is apple's new take on opus support, replacing opus-caf which was technically limited to cbr opus
365
+
366
+ * iPhones: preloading another awo file may cause playback to stop
367
+ * can be somewhat mitigated with `mp.au.play()` in `mp.onpreload` but that can hit a race condition in safari that starts playing the same audio object twice in parallel...
368
+
414
369
  * Windows: folders cannot be accessed if the name ends with `.`
415
370
  * python or windows bug
416
371
 
@@ -670,8 +625,8 @@ select which type of archive you want in the `[⚙️] config` tab:
670
625
  | `pax` | `?tar=pax` | pax-format tar, futureproof, not as fast |
671
626
  | `tgz` | `?tar=gz` | gzip compressed gnu-tar (slow), for `curl \| tar -xvz` |
672
627
  | `txz` | `?tar=xz` | gnu-tar with xz / lzma compression (v.slow) |
673
- | `zip` | `?zip=utf8` | works everywhere, glitchy filenames on win7 and older |
674
- | `zip_dos` | `?zip` | traditional cp437 (no unicode) to fix glitchy filenames |
628
+ | `zip` | `?zip` | works everywhere, glitchy filenames on win7 and older |
629
+ | `zip_dos` | `?zip=dos` | traditional cp437 (no unicode) to fix glitchy filenames |
675
630
  | `zip_crc` | `?zip=crc` | cp437 with crc32 computed early for truly ancient software |
676
631
 
677
632
  * gzip default level is `3` (0=fast, 9=best), change with `?tar=gz:9`
@@ -679,7 +634,7 @@ select which type of archive you want in the `[⚙️] config` tab:
679
634
  * bz2 default level is `2` (1=fast, 9=best), change with `?tar=bz2:9`
680
635
  * hidden files ([dotfiles](#dotfiles)) are excluded unless account is allowed to list them
681
636
  * `up2k.db` and `dir.txt` is always excluded
682
- * bsdtar supports streaming unzipping: `curl foo?zip=utf8 | bsdtar -xv`
637
+ * bsdtar supports streaming unzipping: `curl foo?zip | bsdtar -xv`
683
638
  * good, because copyparty's zip is faster than tar on small files
684
639
  * `zip_crc` will take longer to download since the server has to read each file twice
685
640
  * this is only to support MS-DOS PKZIP v2.04g (october 1993) and older
@@ -942,6 +897,8 @@ will show uploader IP and upload-time if the visitor has the admin permission
942
897
 
943
898
  * global-option `--ups-when` makes upload-time visible to all users, and not just admins
944
899
 
900
+ * global-option `--ups-who` (volflag `ups_who`) specifies who gets access (0=nobody, 1=admins, 2=everyone), default=2
901
+
945
902
  note that the [🧯 unpost](#unpost) feature is better suited for viewing *your own* recent uploads, as it includes the option to undo/delete them
946
903
 
947
904
 
@@ -981,6 +938,11 @@ open the `[🎺]` media-player-settings tab to configure it,
981
938
  * `[aac]` converts `aac` and `m4a` files into opus (if supported by browser) or mp3
982
939
  * `[oth]` converts all other known formats into opus (if supported by browser) or mp3
983
940
  * `aac|ac3|aif|aiff|alac|alaw|amr|ape|au|dfpwm|dts|flac|gsm|it|m4a|mo3|mod|mp2|mp3|mpc|mptm|mt2|mulaw|ogg|okt|opus|ra|s3m|tak|tta|ulaw|wav|wma|wv|xm|xpk`
941
+ * "transcode to":
942
+ * `[opus]` produces an `opus` whenever transcoding is necessary (the best choice on Android and PCs)
943
+ * `[awo]` is `opus` in a `weba` file, good for iPhones (iOS 17.5 and newer) but Apple is still fixing some state-confusion bugs as of iOS 18.2.1
944
+ * `[caf]` is `opus` in a `caf` file, good for iPhones (iOS 11 through 17), technically unsupported by Apple but works for the mos tpart
945
+ * `[mp3]` -- the myth, the legend, the undying master of mediocre sound quality that definitely works everywhere
984
946
  * "tint" reduces the contrast of the playback bar
985
947
 
986
948
 
@@ -1513,6 +1475,23 @@ there's a bunch of flags and stuff, see `--help-hooks`
1513
1475
  if you want to write your own hooks, see [devnotes](./docs/devnotes.md#event-hooks)
1514
1476
 
1515
1477
 
1478
+ ### zeromq
1479
+
1480
+ event-hooks can send zeromq messages instead of running programs
1481
+
1482
+ to send a 0mq message every time a file is uploaded,
1483
+
1484
+ * `--xau zmq:pub:tcp://*:5556` sends a PUB to any/all connected SUB clients
1485
+ * `--xau t3,zmq:push:tcp://*:5557` sends a PUSH to exactly one connected PULL client
1486
+ * `--xau t3,j,zmq:req:tcp://localhost:5555` sends a REQ to the connected REP client
1487
+
1488
+ the PUSH and REQ examples have `t3` (timeout after 3 seconds) because they block if there's no clients to talk to
1489
+
1490
+ * the REQ example does `t3,j` to send extended upload-info as json instead of just the filesystem-path
1491
+
1492
+ see [zmq-recv.py](https://github.com/9001/copyparty/blob/hovudstraum/bin/zmq-recv.py) if you need something to receive the messages with
1493
+
1494
+
1516
1495
  ### upload events
1517
1496
 
1518
1497
  the older, more powerful approach ([examples](./bin/mtag/)):
@@ -1600,12 +1579,16 @@ connecting to an aws s3 bucket and similar
1600
1579
 
1601
1580
  there is no built-in support for this, but you can use FUSE-software such as [rclone](https://rclone.org/) / [geesefs](https://github.com/yandex-cloud/geesefs) / [JuiceFS](https://juicefs.com/en/) to first mount your cloud storage as a local disk, and then let copyparty use (a folder in) that disk as a volume
1602
1581
 
1603
- you may experience poor upload performance this way, but that can sometimes be fixed by specifying the volflag `sparse` to force the use of sparse files; this has improved the upload speeds from `1.5 MiB/s` to over `80 MiB/s` in one case, but note that you are also more likely to discover funny bugs in your FUSE software this way, so buckle up
1582
+ you will probably get decent speeds with the default config, however most likely restricted to using one TCP connection per file, so the upload-client won't be able to send multiple chunks in parallel
1583
+
1584
+ > before [v1.13.5](https://github.com/9001/copyparty/releases/tag/v1.13.5) it was recommended to use the volflag `sparse` to force-allow multiple chunks in parallel; this would improve the upload-speed from `1.5 MiB/s` to over `80 MiB/s` at the risk of provoking latent bugs in S3 or JuiceFS. But v1.13.5 added chunk-stitching, so this is now probably much less important. On the contrary, `nosparse` *may* now increase performance in some cases. Please try all three options (default, `sparse`, `nosparse`) as the optimal choice depends on your network conditions and software stack (both the FUSE-driver and cloud-server)
1604
1585
 
1605
1586
  someone has also tested geesefs in combination with [gocryptfs](https://nuetzlich.net/gocryptfs/) with surprisingly good results, getting 60 MiB/s upload speeds on a gbit line, but JuiceFS won with 80 MiB/s using its built-in encryption
1606
1587
 
1607
1588
  you may improve performance by specifying larger values for `--iobuf` / `--s-rd-sz` / `--s-wr-sz`
1608
1589
 
1590
+ > if you've experimented with this and made interesting observations, please share your findings so we can add a section with specific recommendations :-)
1591
+
1609
1592
 
1610
1593
  ## hiding from google
1611
1594
 
@@ -2359,13 +2342,13 @@ mandatory deps:
2359
2342
 
2360
2343
  install these to enable bonus features
2361
2344
 
2362
- enable hashed passwords in config: `argon2-cffi`
2345
+ enable [hashed passwords](#password-hashing) in config: `argon2-cffi`
2363
2346
 
2364
- enable ftp-server:
2347
+ enable [ftp-server](#ftp-server):
2365
2348
  * for just plaintext FTP, `pyftpdlib` (is built into the SFX)
2366
2349
  * with TLS encryption, `pyftpdlib pyopenssl`
2367
2350
 
2368
- enable music tags:
2351
+ enable [music tags](#metadata-from-audio-files):
2369
2352
  * either `mutagen` (fast, pure-python, skips a few tags, makes copyparty GPL? idk)
2370
2353
  * or `ffprobe` (20x slower, more accurate, possibly dangerous depending on your distro and users)
2371
2354
 
@@ -2376,8 +2359,9 @@ enable [thumbnails](#thumbnails) of...
2376
2359
  * **AVIF pictures:** `pyvips` or `ffmpeg` or `pillow-avif-plugin`
2377
2360
  * **JPEG XL pictures:** `pyvips` or `ffmpeg`
2378
2361
 
2379
- enable [smb](#smb-server) support (**not** recommended):
2380
- * `impacket==0.12.0`
2362
+ enable sending [zeromq messages](#zeromq) from event-hooks: `pyzmq`
2363
+
2364
+ enable [smb](#smb-server) support (**not** recommended): `impacket==0.12.0`
2381
2365
 
2382
2366
  `pyvips` gives higher quality thumbnails than `Pillow` and is 320% faster, using 270% more ram: `sudo apt install libvips42 && python3 -m pip install --user -U pyvips`
2383
2367
 
@@ -54,6 +54,8 @@ from .util import (
54
54
  RAM_TOTAL,
55
55
  SQLITE_VER,
56
56
  UNPLICATIONS,
57
+ URL_BUG,
58
+ URL_PRJ,
57
59
  Daemon,
58
60
  align_tab,
59
61
  ansi_re,
@@ -326,17 +328,16 @@ def ensure_webdeps() :
326
328
  if has_resource(E, "web/deps/mini-fa.woff"):
327
329
  return
328
330
 
329
- warn(
330
- """could not find webdeps;
331
+ t = """could not find webdeps;
331
332
  if you are running the sfx, or exe, or pypi package, or docker image,
332
333
  then this is a bug! Please let me know so I can fix it, thanks :-)
333
- https://github.com/9001/copyparty/issues/new?labels=bug&template=bug_report.md
334
+ %s
334
335
 
335
336
  however, if you are a dev, or running copyparty from source, and you want
336
337
  full client functionality, you will need to build or obtain the webdeps:
337
- https://github.com/9001/copyparty/blob/hovudstraum/docs/devnotes.md#building
338
+ %s/blob/hovudstraum/docs/devnotes.md#building
338
339
  """
339
- )
340
+ warn(t % (URL_BUG, URL_PRJ))
340
341
 
341
342
 
342
343
  def configure_ssl_ver(al ) :
@@ -731,6 +732,10 @@ def get_sects():
731
732
  the \033[33m,,\033[35m stops copyparty from reading the rest as flags and
732
733
  the \033[33m--\033[35m stops notify-send from reading the message as args
733
734
  and the alert will be "hey" followed by the messagetext
735
+
736
+ \033[36m--xau zmq:pub:tcp://*:5556\033[35m announces uploads on zeromq;
737
+ \033[36m--xau t3,zmq:push:tcp://*:5557\033[35m also works, and you can
738
+ \033[36m--xau t3,j,zmq:req:tcp://localhost:5555\033[35m too for example
734
739
  \033[0m
735
740
  each hook is executed once for each event, except for \033[36mxiu\033[0m
736
741
  which builds up a backlog of uploads, running the hook just once
@@ -762,11 +767,22 @@ def get_sects():
762
767
  values for --urlform:
763
768
  \033[36mstash\033[35m dumps the data to file and returns length + checksum
764
769
  \033[36msave,get\033[35m dumps to file and returns the page like a GET
765
- \033[36mprint,get\033[35m prints the data in the log and returns GET
766
- (leave out the ",get" to return an error instead)\033[0m
770
+ \033[36mprint \033[35m prints the data to log and returns an error
771
+ \033[36mprint,xm \033[35m prints the data to log and returns --xm output
772
+ \033[36mprint,get\033[35m prints the data to log and returns GET\033[0m
773
+
774
+ note that the \033[35m--xm\033[0m hook will only run if \033[35m--urlform\033[0m is
775
+ either \033[36mprint\033[0m or \033[36mprint,get\033[0m or the default \033[36mprint,xm\033[0m
776
+
777
+ if an \033[35m--xm\033[0m hook returns text, then
778
+ the response code will be HTTP 202;
779
+ http/get responses will be HTTP 200
780
+
781
+ if there are multiple \033[35m--xm\033[0m hooks defined, then
782
+ the first hook that produced output is returned
767
783
 
768
- note that the \033[35m--xm\033[0m hook will only run if \033[35m--urlform\033[0m
769
- is either \033[36mprint\033[0m or the default \033[36mprint,get\033[0m
784
+ if there are no \033[35m--xm\033[0m hooks defined, then the default
785
+ \033[36mprint,xm\033[0m behaves like \033[36mprint,get\033[0m (returning html)
770
786
  """
771
787
  ),
772
788
  ],
@@ -947,7 +963,7 @@ def add_general(ap, nc, srvname):
947
963
  ap2.add_argument("-v", metavar="VOL", type=u, action="append", help="add volume, \033[33mSRC\033[0m:\033[33mDST\033[0m:\033[33mFLAG\033[0m; examples [\033[32m.::r\033[0m], [\033[32m/mnt/nas/music:/music:r:aed\033[0m], see --help-accounts")
948
964
  ap2.add_argument("--grp", metavar="G:N,N", type=u, action="append", help="add group, \033[33mNAME\033[0m:\033[33mUSER1\033[0m,\033[33mUSER2\033[0m,\033[33m...\033[0m; example [\033[32madmins:ed,foo,bar\033[0m]")
949
965
  ap2.add_argument("-ed", action="store_true", help="enable the ?dots url parameter / client option which allows clients to see dotfiles / hidden files (volflag=dots)")
950
- ap2.add_argument("--urlform", metavar="MODE", type=u, default="print,get", help="how to handle url-form POSTs; see \033[33m--help-urlform\033[0m")
966
+ ap2.add_argument("--urlform", metavar="MODE", type=u, default="print,xm", help="how to handle url-form POSTs; see \033[33m--help-urlform\033[0m")
951
967
  ap2.add_argument("--wintitle", metavar="TXT", type=u, default="cpp @ $pub", help="server terminal title, for example [\033[32m$ip-10.1.2.\033[0m] or [\033[32m$ip-]")
952
968
  ap2.add_argument("--name", metavar="TXT", type=u, default=srvname, help="server name (displayed topleft in browser and in mDNS)")
953
969
  ap2.add_argument("--mime", metavar="EXT=MIME", type=u, action="append", help="map file \033[33mEXT\033[0mension to \033[33mMIME\033[0mtype, for example [\033[32mjpg=image/jpeg\033[0m]")
@@ -1320,6 +1336,7 @@ def add_admin(ap):
1320
1336
  ap2.add_argument("--no-ups-page", action="store_true", help="disable ?ru (list of recent uploads)")
1321
1337
  ap2.add_argument("--no-up-list", action="store_true", help="don't show list of incoming files in controlpanel")
1322
1338
  ap2.add_argument("--dl-list", metavar="LVL", type=int, default=2, help="who can see active downloads in the controlpanel? [\033[32m0\033[0m]=nobody, [\033[32m1\033[0m]=admins, [\033[32m2\033[0m]=everyone")
1339
+ ap2.add_argument("--ups-who", metavar="LVL", type=int, default=2, help="who can see recent uploads on the ?ru page? [\033[32m0\033[0m]=nobody, [\033[32m1\033[0m]=admins, [\033[32m2\033[0m]=everyone (volflag=ups_who)")
1323
1340
  ap2.add_argument("--ups-when", action="store_true", help="let everyone see upload timestamps on the ?ru page, not just admins")
1324
1341
 
1325
1342
 
@@ -1360,6 +1377,8 @@ def add_transcoding(ap):
1360
1377
  ap2 = ap.add_argument_group('transcoding options')
1361
1378
  ap2.add_argument("--q-opus", metavar="KBPS", type=int, default=128, help="target bitrate for transcoding to opus; set 0 to disable")
1362
1379
  ap2.add_argument("--q-mp3", metavar="QUALITY", type=u, default="q2", help="target quality for transcoding to mp3, for example [\033[32m192k\033[0m] (CBR) or [\033[32mq0\033[0m] (CQ/CRF, q0=maxquality, q9=smallest); set 0 to disable")
1380
+ ap2.add_argument("--no-caf", action="store_true", help="disable transcoding to caf-opus (affects iOS v12~v17), will use mp3 instead")
1381
+ ap2.add_argument("--no-owa", action="store_true", help="disable transcoding to webm-opus (iOS v18 and later), will use mp3 instead")
1363
1382
  ap2.add_argument("--no-acode", action="store_true", help="disable audio transcoding")
1364
1383
  ap2.add_argument("--no-bacode", action="store_true", help="disable batch audio transcoding by folder download (zip/tar)")
1365
1384
  ap2.add_argument("--ac-maxage", metavar="SEC", type=int, default=86400, help="delete cached transcode output after \033[33mSEC\033[0m seconds")
@@ -1468,12 +1487,14 @@ def add_ui(ap, retry):
1468
1487
  ap2.add_argument("--txt-max", metavar="KiB", type=int, default=64, help="max size of embedded textfiles on ?doc= (anything bigger will be lazy-loaded by JS)")
1469
1488
  ap2.add_argument("--doctitle", metavar="TXT", type=u, default="copyparty @ --name", help="title / service-name to show in html documents")
1470
1489
  ap2.add_argument("--bname", metavar="TXT", type=u, default="--name", help="server name (displayed in filebrowser document title)")
1471
- ap2.add_argument("--pb-url", metavar="URL", type=u, default="https://github.com/9001/copyparty", help="powered-by link; disable with \033[33m-np\033[0m")
1490
+ ap2.add_argument("--pb-url", metavar="URL", type=u, default=URL_PRJ, help="powered-by link; disable with \033[33m-np\033[0m")
1472
1491
  ap2.add_argument("--ver", action="store_true", help="show version on the control panel (incompatible with \033[33m-nb\033[0m)")
1473
1492
  ap2.add_argument("--k304", metavar="NUM", type=int, default=0, help="configure the option to enable/disable k304 on the controlpanel (workaround for buggy reverse-proxies); [\033[32m0\033[0m] = hidden and default-off, [\033[32m1\033[0m] = visible and default-off, [\033[32m2\033[0m] = visible and default-on")
1474
1493
  ap2.add_argument("--no304", metavar="NUM", type=int, default=0, help="configure the option to enable/disable no304 on the controlpanel (workaround for buggy caching in browsers); [\033[32m0\033[0m] = hidden and default-off, [\033[32m1\033[0m] = visible and default-off, [\033[32m2\033[0m] = visible and default-on")
1475
- ap2.add_argument("--md-sbf", metavar="FLAGS", type=u, default="downloads forms popups scripts top-navigation-by-user-activation", help="list of capabilities to ALLOW for README.md docs (volflag=md_sbf); see https://developer.mozilla.org/en-US/docs/Web/HTML/Element/iframe#attr-sandbox")
1476
- ap2.add_argument("--lg-sbf", metavar="FLAGS", type=u, default="downloads forms popups scripts top-navigation-by-user-activation", help="list of capabilities to ALLOW for prologue/epilogue docs (volflag=lg_sbf)")
1494
+ ap2.add_argument("--md-sbf", metavar="FLAGS", type=u, default="downloads forms popups scripts top-navigation-by-user-activation", help="list of capabilities to allow in the iframe 'sandbox' attribute for README.md docs (volflag=md_sbf); see https://developer.mozilla.org/en-US/docs/Web/HTML/Element/iframe#sandbox")
1495
+ ap2.add_argument("--lg-sbf", metavar="FLAGS", type=u, default="downloads forms popups scripts top-navigation-by-user-activation", help="list of capabilities to allow in the iframe 'sandbox' attribute for prologue/epilogue docs (volflag=lg_sbf)")
1496
+ ap2.add_argument("--md-sba", metavar="TXT", type=u, default="", help="the value of the iframe 'allow' attribute for README.md docs, for example [\033[32mfullscreen\033[0m] (volflag=md_sba)")
1497
+ ap2.add_argument("--lg-sba", metavar="TXT", type=u, default="", help="the value of the iframe 'allow' attribute for prologue/epilogue docs (volflag=lg_sba); see https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Permissions-Policy#iframes")
1477
1498
  ap2.add_argument("--no-sb-md", action="store_true", help="don't sandbox README/PREADME.md documents (volflags: no_sb_md | sb_md)")
1478
1499
  ap2.add_argument("--no-sb-lg", action="store_true", help="don't sandbox prologue/epilogue docs (volflags: no_sb_lg | sb_lg); enables non-js support")
1479
1500
 
@@ -1,8 +1,8 @@
1
1
  # coding: utf-8
2
2
 
3
- VERSION = (1, 16, 8)
3
+ VERSION = (1, 16, 10)
4
4
  CODENAME = "COPYparty"
5
- BUILD_DT = (2025, 1, 11)
5
+ BUILD_DT = (2025, 1, 25)
6
6
 
7
7
  S_VERSION = ".".join(map(str, VERSION))
8
8
  S_BUILD_DT = "{0:04d}-{1:02d}-{2:02d}".format(*BUILD_DT)
@@ -1825,7 +1825,11 @@ class AuthSrv(object):
1825
1825
  if fka and not fk:
1826
1826
  fk = fka
1827
1827
  if fk:
1828
- vol.flags["fk"] = int(fk) if fk is not True else 8
1828
+ fk = 8 if fk is True else int(fk)
1829
+ if fk > 72:
1830
+ t = "max filekey-length is 72; volume /%s specified %d (anything higher than 16 is pointless btw)"
1831
+ raise Exception(t % (vol.vpath, fk))
1832
+ vol.flags["fk"] = fk
1829
1833
  have_fk = True
1830
1834
 
1831
1835
  dk = vol.flags.get("dk")
@@ -2332,6 +2336,7 @@ class AuthSrv(object):
2332
2336
  "frand": bool(vf.get("rand")),
2333
2337
  "lifetime": vf.get("lifetime") or 0,
2334
2338
  "unlist": vf.get("unlist") or "",
2339
+ "sb_lg": "" if "no_sb_lg" in vf else (vf.get("lg_sbf") or "y"),
2335
2340
  }
2336
2341
  js_htm = {
2337
2342
  "s_name": self.args.bname,
@@ -2344,6 +2349,8 @@ class AuthSrv(object):
2344
2349
  "have_unpost": int(self.args.unpost),
2345
2350
  "have_emp": self.args.emp,
2346
2351
  "sb_md": "" if "no_sb_md" in vf else (vf.get("md_sbf") or "y"),
2352
+ "sba_md": vf.get("md_sba") or "",
2353
+ "sba_lg": vf.get("lg_sba") or "",
2347
2354
  "txt_ext": self.args.textfiles.replace(",", " "),
2348
2355
  "def_hcols": list(vf.get("mth") or []),
2349
2356
  "unlist0": vf.get("unlist") or "",
@@ -74,6 +74,8 @@ def vf_vmap() :
74
74
  "html_head",
75
75
  "lg_sbf",
76
76
  "md_sbf",
77
+ "lg_sba",
78
+ "md_sba",
77
79
  "nrand",
78
80
  "og_desc",
79
81
  "og_site",
@@ -91,6 +93,7 @@ def vf_vmap() :
91
93
  "unlist",
92
94
  "u2abort",
93
95
  "u2ts",
96
+ "ups_who",
94
97
  ):
95
98
  ret[k] = k
96
99
  return ret
@@ -144,6 +147,7 @@ flagcats = {
144
147
  "noclone": "take dupe data from clients, even if available on HDD",
145
148
  "nodupe": "rejects existing files (instead of linking/cloning them)",
146
149
  "sparse": "force use of sparse files, mainly for s3-backed storage",
150
+ "nosparse": "deny use of sparse files, mainly for slow storage",
147
151
  "daw": "enable full WebDAV write support (dangerous);\nPUT-operations will now \033[1;31mOVERWRITE\033[0;35m existing files",
148
152
  "nosub": "forces all uploads into the top folder of the vfs",
149
153
  "magic": "enables filetype detection for nameless uploads",
@@ -240,6 +244,8 @@ flagcats = {
240
244
  "sb_lg": "enable js sandbox for prologue/epilogue (default)",
241
245
  "md_sbf": "list of markdown-sandbox safeguards to disable",
242
246
  "lg_sbf": "list of *logue-sandbox safeguards to disable",
247
+ "md_sba": "value of iframe allow-prop for markdown-sandbox",
248
+ "lg_sba": "value of iframe allow-prop for *logue-sandbox",
243
249
  "nohtml": "return html and markdown as text/html",
244
250
  },
245
251
  "others": {
@@ -1,9 +1,16 @@
1
+ # coding: utf-8
2
+ from __future__ import print_function, unicode_literals
3
+
1
4
  import importlib
2
5
  import sys
3
6
  import xml.etree.ElementTree as ET
4
7
 
5
8
  from .__init__ import PY2
6
9
 
10
+ class BadXML(Exception):
11
+ pass
12
+
13
+
7
14
  def get_ET() :
8
15
  pn = "xml.etree.ElementTree"
9
16
  cn = "_elementtree"
@@ -30,7 +37,7 @@ def get_ET() :
30
37
  XMLParser = get_ET()
31
38
 
32
39
 
33
- class DXMLParser(XMLParser): # type: ignore
40
+ class _DXMLParser(XMLParser): # type: ignore
34
41
  def __init__(self) :
35
42
  tb = ET.TreeBuilder()
36
43
  super(DXMLParser, self).__init__(target=tb)
@@ -45,8 +52,12 @@ class DXMLParser(XMLParser): # type: ignore
45
52
  raise BadXML("{}, {}".format(a, ka))
46
53
 
47
54
 
48
- class BadXML(Exception):
49
- pass
55
+ class _NG(XMLParser): # type: ignore
56
+ def __int__(self) :
57
+ raise BadXML("dxml selftest failed")
58
+
59
+
60
+ DXMLParser = _DXMLParser
50
61
 
51
62
 
52
63
  def parse_xml(txt ) :
@@ -55,6 +66,40 @@ def parse_xml(txt ) :
55
66
  return parser.close() # type: ignore
56
67
 
57
68
 
69
+ def selftest() :
70
+ qbe = r"""<!DOCTYPE d [
71
+ <!ENTITY a "nice_bakuretsu">
72
+ ]>
73
+ <root>&a;&a;&a;</root>"""
74
+
75
+ emb = r"""<!DOCTYPE d [
76
+ <!ENTITY a SYSTEM "file:///etc/hostname">
77
+ ]>
78
+ <root>&a;</root>"""
79
+
80
+ # future-proofing; there's never been any known vulns
81
+ # regarding DTDs and ET.XMLParser, but might as well
82
+ # block them since webdav-clients don't use them
83
+ dtd = r"""<!DOCTYPE d SYSTEM "a.dtd">
84
+ <root>a</root>"""
85
+
86
+ for txt in (qbe, emb, dtd):
87
+ try:
88
+ parse_xml(txt)
89
+ t = "WARNING: dxml selftest failed:\n%s\n"
90
+ print(t % (txt,), file=sys.stderr)
91
+ return False
92
+ except BadXML:
93
+ pass
94
+
95
+ return True
96
+
97
+
98
+ DXML_OK = selftest()
99
+ if not DXML_OK:
100
+ DXMLParser = _NG
101
+
102
+
58
103
  def mktnod(name , text ) :
59
104
  el = ET.Element(name)
60
105
  el.text = text