copyparty 1.17.0__py3-none-any.whl → 1.17.2__py3-none-any.whl
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.
- copyparty/__main__.py +6 -2
- copyparty/__version__.py +2 -2
- copyparty/authsrv.py +21 -5
- copyparty/cert.py +3 -5
- copyparty/cfg.py +6 -0
- copyparty/httpcli.py +54 -46
- copyparty/sutil.py +4 -3
- copyparty/tftpd.py +2 -1
- copyparty/th_srv.py +3 -3
- copyparty/up2k.py +15 -8
- copyparty/util.py +17 -9
- copyparty/web/a/u2c.py +3 -3
- copyparty/web/browser.css.gz +0 -0
- copyparty/web/browser.js.gz +0 -0
- copyparty/web/splash.js.gz +0 -0
- copyparty/web/svcs.html +1 -0
- copyparty/web/up2k.js.gz +0 -0
- copyparty/web/util.js.gz +0 -0
- copyparty/web/w.hash.js.gz +0 -0
- {copyparty-1.17.0.dist-info → copyparty-1.17.2.dist-info}/METADATA +18 -3
- {copyparty-1.17.0.dist-info → copyparty-1.17.2.dist-info}/RECORD +25 -25
- {copyparty-1.17.0.dist-info → copyparty-1.17.2.dist-info}/WHEEL +1 -1
- {copyparty-1.17.0.dist-info → copyparty-1.17.2.dist-info}/entry_points.txt +0 -0
- {copyparty-1.17.0.dist-info → copyparty-1.17.2.dist-info}/licenses/LICENSE +0 -0
- {copyparty-1.17.0.dist-info → copyparty-1.17.2.dist-info}/top_level.txt +0 -0
copyparty/__main__.py
CHANGED
@@ -995,6 +995,9 @@ def add_upload(ap):
|
|
995
995
|
ap2 = ap.add_argument_group('upload options')
|
996
996
|
ap2.add_argument("--dotpart", action="store_true", help="dotfile incomplete uploads, hiding them from clients unless \033[33m-ed\033[0m")
|
997
997
|
ap2.add_argument("--plain-ip", action="store_true", help="when avoiding filename collisions by appending the uploader's ip to the filename: append the plaintext ip instead of salting and hashing the ip")
|
998
|
+
ap2.add_argument("--put-name", metavar="TXT", type=u, default="put-{now.6f}-{cip}.bin", help="filename for nameless uploads (when uploader doesn't provide a name); default is [\033[32mput-UNIXTIME-IP.bin\033[0m] (the \033[32m.6f\033[0m means six decimal places) (volflag=put_name)")
|
999
|
+
ap2.add_argument("--put-ck", metavar="ALG", type=u, default="sha512", help="default checksum-hasher for PUT/WebDAV uploads: no / md5 / sha1 / sha256 / sha512 / b2 / blake2 / b2s / blake2s (volflag=put_ck)")
|
1000
|
+
ap2.add_argument("--bup-ck", metavar="ALG", type=u, default="sha512", help="default checksum-hasher for bup/basic-uploader: no / md5 / sha1 / sha256 / sha512 / b2 / blake2 / b2s / blake2s (volflag=bup_ck)")
|
998
1001
|
ap2.add_argument("--unpost", metavar="SEC", type=int, default=3600*12, help="grace period where uploads can be deleted by the uploader, even without delete permissions; 0=disabled, default=12h")
|
999
1002
|
ap2.add_argument("--u2abort", metavar="NUM", type=int, default=1, help="clients can abort incomplete uploads by using the unpost tab (requires \033[33m-e2d\033[0m). [\033[32m0\033[0m] = never allowed (disable feature), [\033[32m1\033[0m] = allow if client has the same IP as the upload AND is using the same account, [\033[32m2\033[0m] = just check the IP, [\033[32m3\033[0m] = just check account-name (volflag=u2abort)")
|
1000
1003
|
ap2.add_argument("--blank-wt", metavar="SEC", type=int, default=300, help="file write grace period (any client can write to a blank file last-modified more recently than \033[33mSEC\033[0m seconds ago)")
|
@@ -1017,6 +1020,7 @@ def add_upload(ap):
|
|
1017
1020
|
ap2.add_argument("--df", metavar="GiB", type=u, default="0", help="ensure \033[33mGiB\033[0m free disk space by rejecting upload requests; assumes gigabytes unless a unit suffix is given: [\033[32m256m\033[0m], [\033[32m4\033[0m], [\033[32m2T\033[0m] (volflag=df)")
|
1018
1021
|
ap2.add_argument("--sparse", metavar="MiB", type=int, default=4, help="windows-only: minimum size of incoming uploads through up2k before they are made into sparse files")
|
1019
1022
|
ap2.add_argument("--turbo", metavar="LVL", type=int, default=0, help="configure turbo-mode in up2k client; [\033[32m-1\033[0m] = forbidden/always-off, [\033[32m0\033[0m] = default-off and warn if enabled, [\033[32m1\033[0m] = default-off, [\033[32m2\033[0m] = on, [\033[32m3\033[0m] = on and disable datecheck")
|
1023
|
+
ap2.add_argument("--nosubtle", metavar="N", type=int, default=0, help="when to use a wasm-hasher instead of the browser's builtin; faster on chrome, but buggy in older chrome versions. [\033[32m0\033[0m] = only when necessary (non-https), [\033[32m1\033[0m] = always (all browsers), [\033[32m2\033[0m] = always on chrome/firefox, [\033[32m3\033[0m] = always on chrome, [\033[32mN\033[0m] = chrome-version N and newer (recommendation: 137)")
|
1020
1024
|
ap2.add_argument("--u2j", metavar="JOBS", type=int, default=2, help="web-client: number of file chunks to upload in parallel; 1 or 2 is good when latency is low (same-country), 2~4 for android-clients, 2~6 for cross-atlantic. Max is 6 in most browsers. Big values increase network-speed but may reduce HDD-speed")
|
1021
1025
|
ap2.add_argument("--u2sz", metavar="N,N,N", type=u, default="1,64,96", help="web-client: default upload chunksize (MiB); sets \033[33mmin,default,max\033[0m in the settings gui. Each HTTP POST will aim for \033[33mdefault\033[0m, and never exceed \033[33mmax\033[0m. Cloudflare max is 96. Big values are good for cross-atlantic but may increase HDD fragmentation on some FS. Disable this optimization with [\033[32m1,1,1\033[0m]")
|
1022
1026
|
ap2.add_argument("--u2ow", metavar="NUM", type=int, default=0, help="web-client: default setting for when to replace/overwrite existing files; [\033[32m0\033[0m]=never, [\033[32m1\033[0m]=if-client-newer, [\033[32m2\033[0m]=always (volflag=u2ow)")
|
@@ -1371,8 +1375,8 @@ def add_thumbnail(ap):
|
|
1371
1375
|
ap2.add_argument("--th-r-vips", metavar="T,T", type=u, default="avif,exr,fit,fits,fts,gif,hdr,heic,jp2,jpeg,jpg,jpx,jxl,nii,pfm,pgm,png,ppm,svg,tif,tiff,webp", help="image formats to decode using pyvips")
|
1372
1376
|
ap2.add_argument("--th-r-ffi", metavar="T,T", type=u, default="apng,avif,avifs,bmp,cbz,dds,dib,fit,fits,fts,gif,hdr,heic,heics,heif,heifs,icns,ico,jp2,jpeg,jpg,jpx,jxl,pbm,pcx,pfm,pgm,png,pnm,ppm,psd,qoi,sgi,tga,tif,tiff,webp,xbm,xpm", help="image formats to decode using ffmpeg")
|
1373
1377
|
ap2.add_argument("--th-r-ffv", metavar="T,T", type=u, default="3gp,asf,av1,avc,avi,flv,h264,h265,hevc,m4v,mjpeg,mjpg,mkv,mov,mp4,mpeg,mpeg2,mpegts,mpg,mpg2,mts,nut,ogm,ogv,rm,ts,vob,webm,wmv", help="video formats to decode using ffmpeg")
|
1374
|
-
ap2.add_argument("--th-r-ffa", metavar="T,T", type=u, default="aac,ac3,aif,aiff,alac,alaw,amr,apac,ape,au,bonk,dfpwm,dts,flac,gsm,ilbc,it,itgz,itxz,itz,m4a,mdgz,mdxz,mdz,mo3,mod,mp2,mp3,mpc,mptm,mt2,mulaw,ogg,okt,opus,ra,s3m,s3gz,s3xz,s3z,tak,tta,ulaw,wav,wma,wv,xm,xmgz,xmxz,xmz,xpk", help="audio formats to decode using ffmpeg")
|
1375
|
-
ap2.add_argument("--th-spec-cnv", metavar="T
|
1378
|
+
ap2.add_argument("--th-r-ffa", metavar="T,T", type=u, default="aac,ac3,aif,aiff,alac,alaw,amr,apac,ape,au,bonk,dfpwm,dts,flac,gsm,ilbc,it,itgz,itxz,itz,m4a,mdgz,mdxz,mdz,mo3,mod,mp2,mp3,mpc,mptm,mt2,mulaw,oga,ogg,okt,opus,ra,s3m,s3gz,s3xz,s3z,tak,tta,ulaw,wav,wma,wv,xm,xmgz,xmxz,xmz,xpk", help="audio formats to decode using ffmpeg")
|
1379
|
+
ap2.add_argument("--th-spec-cnv", metavar="T", type=u, default="it,itgz,itxz,itz,mdgz,mdxz,mdz,mo3,mod,s3m,s3gz,s3xz,s3z,xm,xmgz,xmxz,xmz,xpk", help="audio formats which provoke https://trac.ffmpeg.org/ticket/10797 (huge ram usage for s3xmodit spectrograms)")
|
1376
1380
|
ap2.add_argument("--au-unpk", metavar="E=F.C", type=u, default="mdz=mod.zip, mdgz=mod.gz, mdxz=mod.xz, s3z=s3m.zip, s3gz=s3m.gz, s3xz=s3m.xz, xmz=xm.zip, xmgz=xm.gz, xmxz=xm.xz, itz=it.zip, itgz=it.gz, itxz=it.xz, cbz=jpg.cbz", help="audio/image formats to decompress before passing to ffmpeg")
|
1377
1381
|
|
1378
1382
|
|
copyparty/__version__.py
CHANGED
copyparty/authsrv.py
CHANGED
@@ -350,7 +350,6 @@ class VFS(object):
|
|
350
350
|
self.flags = flags # config options
|
351
351
|
self.root = self
|
352
352
|
self.dev = 0 # st_dev
|
353
|
-
self.badcfg1 = False
|
354
353
|
self.nodes = {} # child nodes
|
355
354
|
self.histtab = {} # all realpath->histpath
|
356
355
|
self.dbpaths = {} # all realpath->dbpath
|
@@ -870,6 +869,7 @@ class AuthSrv(object):
|
|
870
869
|
self.warn_anonwrite = warn_anonwrite
|
871
870
|
self.line_ctr = 0
|
872
871
|
self.indent = ""
|
872
|
+
self.is_lxc = args.c == ["/z/initcfg"]
|
873
873
|
|
874
874
|
# fwd-decl
|
875
875
|
self.vfs = VFS(log_func, "", "", "", AXS(), {})
|
@@ -880,6 +880,8 @@ class AuthSrv(object):
|
|
880
880
|
self.defpw = {}
|
881
881
|
self.grps = {}
|
882
882
|
self.re_pwd = None
|
883
|
+
self.cfg_files_loaded = []
|
884
|
+
self.badcfg1 = False
|
883
885
|
|
884
886
|
# all volumes observed since last restart
|
885
887
|
self.idp_vols = {} # vpath->abspath
|
@@ -1475,8 +1477,10 @@ class AuthSrv(object):
|
|
1475
1477
|
daxs = {}
|
1476
1478
|
mflags = {} # vpath:flags
|
1477
1479
|
mount = {} # dst:src (vp:(ap,vp0))
|
1480
|
+
cfg_files_loaded = []
|
1478
1481
|
|
1479
1482
|
self.idp_vols = {} # yolo
|
1483
|
+
self.badcfg1 = False
|
1480
1484
|
|
1481
1485
|
if self.args.a:
|
1482
1486
|
# list of username:password
|
@@ -1537,6 +1541,7 @@ class AuthSrv(object):
|
|
1537
1541
|
zst = [(max(0, len(x) - 2) * " ") + "└" + x[-1] for x in zstt]
|
1538
1542
|
t = "loaded {} config files:\n{}"
|
1539
1543
|
self.log(t.format(len(zst), "\n".join(zst)))
|
1544
|
+
cfg_files_loaded = zst
|
1540
1545
|
|
1541
1546
|
except:
|
1542
1547
|
lns = lns[: self.line_ctr]
|
@@ -1561,9 +1566,14 @@ class AuthSrv(object):
|
|
1561
1566
|
if not mount and not self.args.idp_h_usr:
|
1562
1567
|
# -h says our defaults are CWD at root and read/write for everyone
|
1563
1568
|
axs = AXS(["*"], ["*"], None, None)
|
1564
|
-
if
|
1565
|
-
t = "Read-access has been disabled due to failsafe: Docker detected, but
|
1566
|
-
|
1569
|
+
if self.is_lxc:
|
1570
|
+
t = "Read-access has been disabled due to failsafe: Docker detected, but %s. This failsafe is to prevent unintended access if this is due to accidental loss of config. You can override this safeguard and allow read/write to all of /w/ by adding the following arguments to the docker container: -v .::rw"
|
1571
|
+
if len(cfg_files_loaded) == 1:
|
1572
|
+
self.log(t % ("no config-file was provided",), 1)
|
1573
|
+
t = "it is strongly recommended to add a config-file instead, for example based on https://github.com/9001/copyparty/blob/hovudstraum/docs/examples/docker/basic-docker-compose/copyparty.conf"
|
1574
|
+
self.log(t, 3)
|
1575
|
+
else:
|
1576
|
+
self.log(t % ("the config does not define any volumes",), 1)
|
1567
1577
|
axs = AXS()
|
1568
1578
|
elif self.args.c:
|
1569
1579
|
t = "Read-access has been disabled due to failsafe: No volumes were defined by the config-file. This failsafe is to prevent unintended access if this is due to accidental loss of config. You can override this safeguard and allow read/write to the working-directory by adding the following arguments: -v .::rw"
|
@@ -1571,7 +1581,7 @@ class AuthSrv(object):
|
|
1571
1581
|
axs = AXS()
|
1572
1582
|
vfs = VFS(self.log_func, absreal("."), "", "", axs, {})
|
1573
1583
|
if not axs.uread:
|
1574
|
-
|
1584
|
+
self.badcfg1 = True
|
1575
1585
|
elif "" not in mount:
|
1576
1586
|
# there's volumes but no root; make root inaccessible
|
1577
1587
|
zsd = {"d2d": True, "tcolor": self.args.tcolor}
|
@@ -2067,6 +2077,10 @@ class AuthSrv(object):
|
|
2067
2077
|
if len(zs) == 3: # fc5 => ffcc55
|
2068
2078
|
vol.flags["tcolor"] = "".join([x * 2 for x in zs])
|
2069
2079
|
|
2080
|
+
# volflag syntax currently doesn't allow for ':' in value
|
2081
|
+
zs = vol.flags["put_name"]
|
2082
|
+
vol.flags["put_name2"] = zs.replace("{now.", "{now:.")
|
2083
|
+
|
2070
2084
|
if vol.flags.get("neversymlink"):
|
2071
2085
|
vol.flags["hardlinkonly"] = True # was renamed
|
2072
2086
|
if vol.flags.get("hardlinkonly"):
|
@@ -2422,6 +2436,7 @@ class AuthSrv(object):
|
|
2422
2436
|
self.defpw = defpw
|
2423
2437
|
self.grps = grps
|
2424
2438
|
self.iacct = {v: k for k, v in acct.items()}
|
2439
|
+
self.cfg_files_loaded = cfg_files_loaded
|
2425
2440
|
|
2426
2441
|
self.load_sessions()
|
2427
2442
|
|
@@ -2552,6 +2567,7 @@ class AuthSrv(object):
|
|
2552
2567
|
"idxh": int(self.args.ih),
|
2553
2568
|
"themes": self.args.themes,
|
2554
2569
|
"turbolvl": self.args.turbo,
|
2570
|
+
"nosubtle": self.args.nosubtle,
|
2555
2571
|
"u2j": self.args.u2j,
|
2556
2572
|
"u2sz": self.args.u2sz,
|
2557
2573
|
"u2ts": vf["u2ts"],
|
copyparty/cert.py
CHANGED
@@ -1,13 +1,11 @@
|
|
1
1
|
import calendar
|
2
2
|
import errno
|
3
|
-
import filecmp
|
4
3
|
import json
|
5
4
|
import os
|
6
|
-
import shutil
|
7
5
|
import time
|
8
6
|
|
9
7
|
from .__init__ import ANYWIN
|
10
|
-
from .util import Netdev, load_resource, runcmd,
|
8
|
+
from .util import Netdev, atomic_move, load_resource, runcmd, wunlink
|
11
9
|
|
12
10
|
HAVE_CFSSL = not os.environ.get("PRTY_NO_CFSSL")
|
13
11
|
|
@@ -118,7 +116,7 @@ def _gen_ca(log , args):
|
|
118
116
|
wunlink(nlog, bname + ".key", VF)
|
119
117
|
except:
|
120
118
|
pass
|
121
|
-
|
119
|
+
atomic_move(nlog, bname + "-key.pem", bname + ".key", VF)
|
122
120
|
wunlink(nlog, bname + ".csr", VF)
|
123
121
|
|
124
122
|
log("cert", "new ca OK", 2)
|
@@ -211,7 +209,7 @@ def _gen_srv(log , args, netdevs ):
|
|
211
209
|
wunlink(nlog, bname + ".key", VF)
|
212
210
|
except:
|
213
211
|
pass
|
214
|
-
|
212
|
+
atomic_move(nlog, bname + "-key.pem", bname + ".key", VF)
|
215
213
|
wunlink(nlog, bname + ".csr", VF)
|
216
214
|
|
217
215
|
with open(os.path.join(args.crt_dir, "ca.pem"), "rb") as f:
|
copyparty/cfg.py
CHANGED
@@ -75,6 +75,7 @@ def vf_vmap() :
|
|
75
75
|
"th_x3": "th3x",
|
76
76
|
}
|
77
77
|
for k in (
|
78
|
+
"bup_ck",
|
78
79
|
"dbd",
|
79
80
|
"forget_ip",
|
80
81
|
"hsortn",
|
@@ -95,6 +96,8 @@ def vf_vmap() :
|
|
95
96
|
"og_title_i",
|
96
97
|
"og_tpl",
|
97
98
|
"og_ua",
|
99
|
+
"put_ck",
|
100
|
+
"put_name",
|
98
101
|
"mv_retry",
|
99
102
|
"rm_retry",
|
100
103
|
"sort",
|
@@ -165,6 +168,9 @@ flagcats = {
|
|
165
168
|
"daw": "enable full WebDAV write support (dangerous);\nPUT-operations will now \033[1;31mOVERWRITE\033[0;35m existing files",
|
166
169
|
"nosub": "forces all uploads into the top folder of the vfs",
|
167
170
|
"magic": "enables filetype detection for nameless uploads",
|
171
|
+
"put_name": "fallback filename for nameless uploads",
|
172
|
+
"put_ck": "default checksum-hasher for PUT/WebDAV uploads",
|
173
|
+
"bup_ck": "default checksum-hasher for bup/basic uploads",
|
168
174
|
"gz": "allows server-side gzip compression of uploads with ?gz",
|
169
175
|
"xz": "allows server-side lzma compression of uploads with ?xz",
|
170
176
|
"pk": "forces server-side compression, optional arg: xz,9",
|
copyparty/httpcli.py
CHANGED
@@ -113,7 +113,6 @@ from .util import (
|
|
113
113
|
vol_san,
|
114
114
|
vroots,
|
115
115
|
vsplit,
|
116
|
-
wrename,
|
117
116
|
wunlink,
|
118
117
|
yieldfile,
|
119
118
|
)
|
@@ -185,11 +184,11 @@ class HttpCli(object):
|
|
185
184
|
self.log_src = conn.log_src # mypy404
|
186
185
|
self.gen_fk = self._gen_fk if self.args.log_fk else gen_filekey
|
187
186
|
self.tls = hasattr(self.s, "cipher")
|
187
|
+
self.is_vproxied = bool(self.args.R)
|
188
188
|
|
189
189
|
# placeholders; assigned by run()
|
190
190
|
self.keepalive = False
|
191
191
|
self.is_https = False
|
192
|
-
self.is_vproxied = False
|
193
192
|
self.in_hdr_recv = True
|
194
193
|
self.headers = {}
|
195
194
|
self.mode = " " # http verb
|
@@ -397,7 +396,6 @@ class HttpCli(object):
|
|
397
396
|
self.bad_xff = True
|
398
397
|
else:
|
399
398
|
self.ip = cli_ip
|
400
|
-
self.is_vproxied = bool(self.args.R)
|
401
399
|
self.log_src = self.conn.set_rproxy(self.ip)
|
402
400
|
self.host = self.headers.get("x-forwarded-host") or self.host
|
403
401
|
trusted_xff = True
|
@@ -530,6 +528,7 @@ class HttpCli(object):
|
|
530
528
|
else:
|
531
529
|
t = "incorrect --rp-loc or webserver config; expected vpath starting with %r but got %r"
|
532
530
|
self.log(t % (self.args.R, vpath), 1)
|
531
|
+
self.is_vproxied = False
|
533
532
|
|
534
533
|
self.ouparam = uparam.copy()
|
535
534
|
|
@@ -1229,10 +1228,19 @@ class HttpCli(object):
|
|
1229
1228
|
else:
|
1230
1229
|
return self.tx_404(True)
|
1231
1230
|
else:
|
1232
|
-
|
1233
|
-
|
1234
|
-
|
1235
|
-
|
1231
|
+
if (
|
1232
|
+
self.asrv.badcfg1
|
1233
|
+
and "h" not in self.ouparam
|
1234
|
+
and "hc" not in self.ouparam
|
1235
|
+
):
|
1236
|
+
zs1 = "copyparty refused to start due to a failsafe: invalid server config; check server log"
|
1237
|
+
zs2 = 'you may <a href="/?h">access the controlpanel</a> but nothing will work until you shutdown the copyparty container and %s config-file (or provide the configuration as command-line arguments)'
|
1238
|
+
if self.asrv.is_lxc and len(self.asrv.cfg_files_loaded) == 1:
|
1239
|
+
zs2 = zs2 % ("add a",)
|
1240
|
+
else:
|
1241
|
+
zs2 = zs2 % ("fix the",)
|
1242
|
+
|
1243
|
+
html = self.j2s("msg", h1=zs1, h2=zs2)
|
1236
1244
|
self.reply(html.encode("utf-8", "replace"), 500)
|
1237
1245
|
return True
|
1238
1246
|
|
@@ -1408,7 +1416,7 @@ class HttpCli(object):
|
|
1408
1416
|
desc = "%s - %s" % (tag_a, tag_t) if tag_t and tag_a else (tag_t or tag_a)
|
1409
1417
|
desc = html_escape(desc, True, True) if desc else title
|
1410
1418
|
mime = html_escape(guess_mime(title))
|
1411
|
-
lmod = formatdate(i["ts"])
|
1419
|
+
lmod = formatdate(max(0, i["ts"]))
|
1412
1420
|
zsa = (iurl, iurl, title, desc, lmod, iurl, mime, i["sz"])
|
1413
1421
|
zs = (
|
1414
1422
|
"""\
|
@@ -1565,7 +1573,7 @@ class HttpCli(object):
|
|
1565
1573
|
for x in fgen:
|
1566
1574
|
rp = vjoin(vtop, x["vp"])
|
1567
1575
|
st = x["st"]
|
1568
|
-
mtime = st.st_mtime
|
1576
|
+
mtime = max(0, st.st_mtime)
|
1569
1577
|
if stat.S_ISLNK(st.st_mode):
|
1570
1578
|
try:
|
1571
1579
|
st = bos.stat(os.path.join(tap, x["vp"]))
|
@@ -2091,8 +2099,7 @@ class HttpCli(object):
|
|
2091
2099
|
suffix = "-{:.6f}-{}".format(time.time(), self.dip())
|
2092
2100
|
nameless = not fn
|
2093
2101
|
if nameless:
|
2094
|
-
|
2095
|
-
fn = "put" + suffix
|
2102
|
+
fn = vfs.flags["put_name2"].format(now=time.time(), cip=self.dip())
|
2096
2103
|
|
2097
2104
|
params = {"suffix": suffix, "fdir": fdir}
|
2098
2105
|
if self.args.nw:
|
@@ -2171,28 +2178,26 @@ class HttpCli(object):
|
|
2171
2178
|
# small toctou, but better than clobbering a hardlink
|
2172
2179
|
wunlink(self.log, path, vfs.flags)
|
2173
2180
|
|
2174
|
-
halg = "sha512"
|
2175
2181
|
hasher = None
|
2176
2182
|
copier = hashcopy
|
2177
|
-
|
2178
|
-
|
2179
|
-
|
2180
|
-
|
2181
|
-
|
2182
|
-
|
2183
|
-
|
2184
|
-
|
2185
|
-
|
2186
|
-
|
2187
|
-
|
2188
|
-
|
2189
|
-
|
2190
|
-
|
2191
|
-
|
2192
|
-
|
2193
|
-
|
2194
|
-
|
2195
|
-
raise Pebkac(500, "unknown hash alg")
|
2183
|
+
halg = self.ouparam.get("ck") or self.headers.get("ck") or vfs.flags["put_ck"]
|
2184
|
+
if halg == "sha512":
|
2185
|
+
pass
|
2186
|
+
elif halg == "no":
|
2187
|
+
copier = justcopy
|
2188
|
+
halg = ""
|
2189
|
+
elif halg == "md5":
|
2190
|
+
hasher = hashlib.md5(**USED4SEC)
|
2191
|
+
elif halg == "sha1":
|
2192
|
+
hasher = hashlib.sha1(**USED4SEC)
|
2193
|
+
elif halg == "sha256":
|
2194
|
+
hasher = hashlib.sha256(**USED4SEC)
|
2195
|
+
elif halg in ("blake2", "b2"):
|
2196
|
+
hasher = hashlib.blake2b(**USED4SEC)
|
2197
|
+
elif halg in ("blake2s", "b2s"):
|
2198
|
+
hasher = hashlib.blake2s(**USED4SEC)
|
2199
|
+
else:
|
2200
|
+
raise Pebkac(500, "unknown hash alg")
|
2196
2201
|
|
2197
2202
|
f, fn = ren_open(fn, *open_a, **params)
|
2198
2203
|
try:
|
@@ -2580,10 +2585,6 @@ class HttpCli(object):
|
|
2580
2585
|
x = self.conn.hsrv.broker.ask("up2k.handle_json", body, self.u2fh.aps)
|
2581
2586
|
ret = x.get()
|
2582
2587
|
|
2583
|
-
if self.is_vproxied:
|
2584
|
-
if "purl" in ret:
|
2585
|
-
ret["purl"] = self.args.SR + ret["purl"]
|
2586
|
-
|
2587
2588
|
if self.args.shr and self.vpath.startswith(self.args.shr1):
|
2588
2589
|
# strip common suffix (uploader's folder structure)
|
2589
2590
|
vp_req, vp_vfs = vroots(self.vpath, vjoin(dbv.vpath, vrem))
|
@@ -2593,6 +2594,10 @@ class HttpCli(object):
|
|
2593
2594
|
raise Pebkac(500, t % zt)
|
2594
2595
|
ret["purl"] = vp_req + ret["purl"][len(vp_vfs) :]
|
2595
2596
|
|
2597
|
+
if self.is_vproxied:
|
2598
|
+
if "purl" in ret:
|
2599
|
+
ret["purl"] = self.args.SR + ret["purl"]
|
2600
|
+
|
2596
2601
|
ret = json.dumps(ret)
|
2597
2602
|
self.log(ret)
|
2598
2603
|
self.reply(ret.encode("utf-8"), mime="application/json")
|
@@ -2917,7 +2922,8 @@ class HttpCli(object):
|
|
2917
2922
|
self.parser.drop()
|
2918
2923
|
|
2919
2924
|
self.log("logout " + self.uname)
|
2920
|
-
self.
|
2925
|
+
if not self.uname.startswith("s_"):
|
2926
|
+
self.asrv.forget_session(self.conn.hsrv.broker, self.uname)
|
2921
2927
|
self.get_pwd_cookie("x")
|
2922
2928
|
|
2923
2929
|
dst = self.args.SRS + "?h"
|
@@ -3068,15 +3074,18 @@ class HttpCli(object):
|
|
3068
3074
|
vfs, rem = self.asrv.vfs.get(self.vpath, self.uname, False, True)
|
3069
3075
|
self._assert_safe_rem(rem)
|
3070
3076
|
|
3071
|
-
halg = "sha512"
|
3072
3077
|
hasher = None
|
3073
|
-
copier = hashcopy
|
3074
3078
|
if nohash:
|
3075
3079
|
halg = ""
|
3076
3080
|
copier = justcopy
|
3077
|
-
|
3078
|
-
|
3079
|
-
|
3081
|
+
else:
|
3082
|
+
copier = hashcopy
|
3083
|
+
halg = (
|
3084
|
+
self.ouparam.get("ck") or self.headers.get("ck") or vfs.flags["bup_ck"]
|
3085
|
+
)
|
3086
|
+
if halg == "sha512":
|
3087
|
+
pass
|
3088
|
+
elif halg == "no":
|
3080
3089
|
copier = justcopy
|
3081
3090
|
halg = ""
|
3082
3091
|
elif halg == "md5":
|
@@ -3089,8 +3098,6 @@ class HttpCli(object):
|
|
3089
3098
|
hasher = hashlib.blake2b(**USED4SEC)
|
3090
3099
|
elif halg in ("blake2s", "b2s"):
|
3091
3100
|
hasher = hashlib.blake2s(**USED4SEC)
|
3092
|
-
elif halg == "sha512":
|
3093
|
-
pass
|
3094
3101
|
else:
|
3095
3102
|
raise Pebkac(500, "unknown hash alg")
|
3096
3103
|
|
@@ -3552,7 +3559,7 @@ class HttpCli(object):
|
|
3552
3559
|
except:
|
3553
3560
|
pass
|
3554
3561
|
if dp:
|
3555
|
-
|
3562
|
+
atomic_move(self.log, fp, os.path.join(dp, mfile2), vfs.flags)
|
3556
3563
|
|
3557
3564
|
p_field, _, p_data = next(self.parser.gen)
|
3558
3565
|
if p_field != "body":
|
@@ -3961,7 +3968,7 @@ class HttpCli(object):
|
|
3961
3968
|
for ext in ("", ".gz"):
|
3962
3969
|
if ptop is not None:
|
3963
3970
|
sz = job["size"]
|
3964
|
-
file_ts = job["lmod"]
|
3971
|
+
file_ts = max(0, job["lmod"])
|
3965
3972
|
editions["plain"] = (ap_data, sz)
|
3966
3973
|
break
|
3967
3974
|
|
@@ -5482,6 +5489,7 @@ class HttpCli(object):
|
|
5482
5489
|
raise Pebkac(400, "selected file not found on disk: [%s]" % (fn,))
|
5483
5490
|
|
5484
5491
|
pw = req.get("pw") or ""
|
5492
|
+
pw = self.asrv.ah.hash(pw)
|
5485
5493
|
now = int(time.time())
|
5486
5494
|
sexp = req["exp"]
|
5487
5495
|
exp = int(sexp) if sexp else 0
|
@@ -6099,7 +6107,7 @@ class HttpCli(object):
|
|
6099
6107
|
margin = "-"
|
6100
6108
|
|
6101
6109
|
sz = inf.st_size
|
6102
|
-
zd = datetime.fromtimestamp(linf.st_mtime, UTC)
|
6110
|
+
zd = datetime.fromtimestamp(max(0, linf.st_mtime), UTC)
|
6103
6111
|
dt = "%04d-%02d-%02d %02d:%02d:%02d" % (
|
6104
6112
|
zd.year,
|
6105
6113
|
zd.month,
|
copyparty/sutil.py
CHANGED
@@ -11,6 +11,9 @@ from .bos import bos
|
|
11
11
|
from .th_cli import ThumbCli
|
12
12
|
from .util import UTC, vjoin, vol_san
|
13
13
|
|
14
|
+
TAR_NO_OPUS = set("aac|m4a|mp3|oga|ogg|opus|wma".split("|"))
|
15
|
+
|
16
|
+
|
14
17
|
class StreamArc(object):
|
15
18
|
def __init__(
|
16
19
|
self,
|
@@ -76,9 +79,7 @@ def enthumb(
|
|
76
79
|
) :
|
77
80
|
rem = f["vp"]
|
78
81
|
ext = rem.rsplit(".", 1)[-1].lower()
|
79
|
-
if (fmt == "mp3" and ext == "mp3") or (
|
80
|
-
fmt == "opus" and ext in "aac|m4a|mp3|ogg|opus|wma".split("|")
|
81
|
-
):
|
82
|
+
if (fmt == "mp3" and ext == "mp3") or (fmt == "opus" and ext in TAR_NO_OPUS):
|
82
83
|
raise Exception()
|
83
84
|
|
84
85
|
vp = vjoin(vtop, rem.split("/", 1)[1])
|
copyparty/tftpd.py
CHANGED
@@ -281,6 +281,7 @@ class Tftpd(object):
|
|
281
281
|
if not ptn or not ptn.match(fn.lower()):
|
282
282
|
return None
|
283
283
|
|
284
|
+
tsdt = datetime.fromtimestamp
|
284
285
|
vn, rem = self.asrv.vfs.get(vpath, "*", True, False)
|
285
286
|
fsroot, vfs_ls, vfs_virt = vn.ls(
|
286
287
|
rem,
|
@@ -293,7 +294,7 @@ class Tftpd(object):
|
|
293
294
|
dirs1 = [(v.st_mtime, v.st_size, k + "/") for k, v in vfs_ls if k in dnames]
|
294
295
|
fils1 = [(v.st_mtime, v.st_size, k) for k, v in vfs_ls if k not in dnames]
|
295
296
|
real1 = dirs1 + fils1
|
296
|
-
realt = [(
|
297
|
+
realt = [(tsdt(max(0, mt), UTC), sz, fn) for mt, sz, fn in real1]
|
297
298
|
reals = [
|
298
299
|
(
|
299
300
|
"%04d-%02d-%02d %02d:%02d:%02d"
|
copyparty/th_srv.py
CHANGED
@@ -24,13 +24,13 @@ from .util import (
|
|
24
24
|
Cooldown,
|
25
25
|
Daemon,
|
26
26
|
afsenc,
|
27
|
+
atomic_move,
|
27
28
|
fsenc,
|
28
29
|
min_ex,
|
29
30
|
runcmd,
|
30
31
|
statdir,
|
31
32
|
ub64enc,
|
32
33
|
vsplit,
|
33
|
-
wrename,
|
34
34
|
wunlink,
|
35
35
|
)
|
36
36
|
|
@@ -409,7 +409,7 @@ class ThumbSrv(object):
|
|
409
409
|
wunlink(self.log, ap_unpk, vn.flags)
|
410
410
|
|
411
411
|
try:
|
412
|
-
|
412
|
+
atomic_move(self.log, ttpath, tpath, vn.flags)
|
413
413
|
except Exception as ex:
|
414
414
|
if not os.path.exists(tpath):
|
415
415
|
t = "failed to move [%s] to [%s]: %r"
|
@@ -673,7 +673,7 @@ class ThumbSrv(object):
|
|
673
673
|
except:
|
674
674
|
pass
|
675
675
|
else:
|
676
|
-
|
676
|
+
atomic_move(self.log, wtpath, tpath, vn.flags)
|
677
677
|
|
678
678
|
def conv_spec(self, abspath , tpath , fmt , vn ) :
|
679
679
|
ret, _ = ffprobe(abspath, int(vn.flags["convt"] / 2))
|
copyparty/up2k.py
CHANGED
@@ -1112,7 +1112,7 @@ class Up2k(object):
|
|
1112
1112
|
ft = "\033[0;32m{}{:.0}"
|
1113
1113
|
ff = "\033[0;35m{}{:.0}"
|
1114
1114
|
fv = "\033[0;36m{}:\033[90m{}"
|
1115
|
-
zs = "ext_th_d html_head mv_re_r mv_re_t rm_re_r rm_re_t srch_re_dots srch_re_nodot zipmax zipmaxn_v zipmaxs_v"
|
1115
|
+
zs = "ext_th_d html_head put_name2 mv_re_r mv_re_t rm_re_r rm_re_t srch_re_dots srch_re_nodot zipmax zipmaxn_v zipmaxs_v"
|
1116
1116
|
fx = set(zs.split())
|
1117
1117
|
fd = vf_bmap()
|
1118
1118
|
fd.update(vf_cmap())
|
@@ -2110,11 +2110,12 @@ class Up2k(object):
|
|
2110
2110
|
return -1
|
2111
2111
|
|
2112
2112
|
w = bw[:-1].decode("ascii")
|
2113
|
+
w16 = w[:16]
|
2113
2114
|
|
2114
2115
|
with self.mutex:
|
2115
2116
|
try:
|
2116
2117
|
q = "select rd, fn, ip, at from up where substr(w,1,16)=? and +w=?"
|
2117
|
-
rd, fn, ip, at = cur.execute(q, (
|
2118
|
+
rd, fn, ip, at = cur.execute(q, (w16, w)).fetchone()
|
2118
2119
|
except:
|
2119
2120
|
# file modified/deleted since spooling
|
2120
2121
|
continue
|
@@ -2123,8 +2124,12 @@ class Up2k(object):
|
|
2123
2124
|
rd, fn = s3dec(rd, fn)
|
2124
2125
|
|
2125
2126
|
if "mtp" in flags:
|
2127
|
+
q = "select 1 from mt where w=? and +k='t:mtp' limit 1"
|
2128
|
+
if cur.execute(q, (w16,)).fetchone():
|
2129
|
+
continue
|
2130
|
+
|
2126
2131
|
q = "insert into mt values (?,'t:mtp','a')"
|
2127
|
-
cur.execute(q, (
|
2132
|
+
cur.execute(q, (w16,))
|
2128
2133
|
|
2129
2134
|
abspath = djoin(ptop, rd, fn)
|
2130
2135
|
self.pp.msg = "c%d %s" % (nq, abspath)
|
@@ -2180,7 +2185,7 @@ class Up2k(object):
|
|
2180
2185
|
return tf, -1
|
2181
2186
|
|
2182
2187
|
if flt == 1:
|
2183
|
-
q = "select
|
2188
|
+
q = "select 1 from mt where w=? and +k != 't:mtp'"
|
2184
2189
|
if c2.execute(q, (row[0][:16],)).fetchone():
|
2185
2190
|
continue
|
2186
2191
|
|
@@ -3215,7 +3220,7 @@ class Up2k(object):
|
|
3215
3220
|
if hr.get("reloc"):
|
3216
3221
|
x = pathmod(self.vfs, dst, vp, hr["reloc"])
|
3217
3222
|
if x:
|
3218
|
-
|
3223
|
+
ud1 = (vfs.vpath, job["prel"], job["name"])
|
3219
3224
|
pdir, _, job["name"], (vfs, rem) = x
|
3220
3225
|
dst = os.path.join(pdir, job["name"])
|
3221
3226
|
job["vcfg"] = vfs.flags
|
@@ -3223,7 +3228,8 @@ class Up2k(object):
|
|
3223
3228
|
job["vtop"] = vfs.vpath
|
3224
3229
|
job["prel"] = rem
|
3225
3230
|
job["name"] = sanitize_fn(job["name"], "")
|
3226
|
-
|
3231
|
+
ud2 = (vfs.vpath, job["prel"], job["name"])
|
3232
|
+
if ud1 != ud2:
|
3227
3233
|
# print(json.dumps(job, sort_keys=True, indent=4))
|
3228
3234
|
job["hash"] = cj["hash"]
|
3229
3235
|
self.log("xbu reloc1:%d..." % (depth,), 6)
|
@@ -4970,14 +4976,15 @@ class Up2k(object):
|
|
4970
4976
|
if hr.get("reloc"):
|
4971
4977
|
x = pathmod(self.vfs, ap_chk, vp_chk, hr["reloc"])
|
4972
4978
|
if x:
|
4973
|
-
|
4979
|
+
ud1 = (vfs.vpath, job["prel"], job["name"])
|
4974
4980
|
pdir, _, job["name"], (vfs, rem) = x
|
4975
4981
|
job["vcfg"] = vf = vfs.flags
|
4976
4982
|
job["ptop"] = vfs.realpath
|
4977
4983
|
job["vtop"] = vfs.vpath
|
4978
4984
|
job["prel"] = rem
|
4979
4985
|
job["name"] = sanitize_fn(job["name"], "")
|
4980
|
-
|
4986
|
+
ud2 = (vfs.vpath, job["prel"], job["name"])
|
4987
|
+
if ud1 != ud2:
|
4981
4988
|
self.log("xbu reloc2:%d..." % (depth,), 6)
|
4982
4989
|
return self._handle_json(job, depth + 1)
|
4983
4990
|
|
copyparty/util.py
CHANGED
@@ -2497,6 +2497,11 @@ def _fs_mvrm(
|
|
2497
2497
|
now = time.time()
|
2498
2498
|
if ex.errno == errno.ENOENT:
|
2499
2499
|
return False
|
2500
|
+
if not attempt and ex.errno == errno.EXDEV:
|
2501
|
+
t = "using copy+delete (%s)\n %s\n %s"
|
2502
|
+
log(t % (ex.strerror, src, dst))
|
2503
|
+
osfun = shutil.move
|
2504
|
+
continue
|
2500
2505
|
if now - t0 > maxtime or attempt == 90209:
|
2501
2506
|
raise
|
2502
2507
|
if not attempt:
|
@@ -2521,15 +2526,18 @@ def atomic_move(log , src , dst , flags ) :
|
|
2521
2526
|
elif flags.get("mv_re_t"):
|
2522
2527
|
_fs_mvrm(log, src, dst, True, flags)
|
2523
2528
|
else:
|
2524
|
-
|
2525
|
-
|
2526
|
-
|
2527
|
-
|
2528
|
-
|
2529
|
-
|
2530
|
-
|
2531
|
-
|
2532
|
-
|
2529
|
+
try:
|
2530
|
+
os.replace(bsrc, bdst)
|
2531
|
+
except OSError as ex:
|
2532
|
+
if ex.errno != errno.EXDEV:
|
2533
|
+
raise
|
2534
|
+
t = "using copy+delete (%s);\n %s\n %s"
|
2535
|
+
log(t % (ex.strerror, src, dst))
|
2536
|
+
try:
|
2537
|
+
os.unlink(bdst)
|
2538
|
+
except:
|
2539
|
+
pass
|
2540
|
+
shutil.move(bsrc, bdst)
|
2533
2541
|
|
2534
2542
|
|
2535
2543
|
def wunlink(log , abspath , flags ) :
|
copyparty/web/a/u2c.py
CHANGED
@@ -1,8 +1,8 @@
|
|
1
1
|
#!/usr/bin/env python3
|
2
2
|
from __future__ import print_function, unicode_literals
|
3
3
|
|
4
|
-
S_VERSION = "2.
|
5
|
-
S_BUILD_DT = "2025-
|
4
|
+
S_VERSION = "2.11"
|
5
|
+
S_BUILD_DT = "2025-05-18"
|
6
6
|
|
7
7
|
"""
|
8
8
|
u2c.py: upload to copyparty
|
@@ -1287,7 +1287,7 @@ class Ctl(object):
|
|
1287
1287
|
if self.ar.jw:
|
1288
1288
|
print("%s %s" % (wark, vp))
|
1289
1289
|
else:
|
1290
|
-
zd = datetime.datetime.fromtimestamp(file.lmod, UTC)
|
1290
|
+
zd = datetime.datetime.fromtimestamp(max(0, file.lmod), UTC)
|
1291
1291
|
dt = "%04d-%02d-%02d %02d:%02d:%02d" % (
|
1292
1292
|
zd.year,
|
1293
1293
|
zd.month,
|
copyparty/web/browser.css.gz
CHANGED
Binary file
|
copyparty/web/browser.js.gz
CHANGED
Binary file
|
copyparty/web/splash.js.gz
CHANGED
Binary file
|
copyparty/web/svcs.html
CHANGED
copyparty/web/up2k.js.gz
CHANGED
Binary file
|
copyparty/web/util.js.gz
CHANGED
Binary file
|
copyparty/web/w.hash.js.gz
CHANGED
Binary file
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.4
|
2
2
|
Name: copyparty
|
3
|
-
Version: 1.17.
|
3
|
+
Version: 1.17.2
|
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
|
@@ -72,6 +72,8 @@ turn almost any device into a file server with resumable uploads/downloads using
|
|
72
72
|
|
73
73
|
🎬 **videos:** [upload](https://a.ocv.me/pub/demo/pics-vids/up2k.webm) // [cli-upload](https://a.ocv.me/pub/demo/pics-vids/u2cli.webm) // [race-the-beam](https://a.ocv.me/pub/g/nerd-stuff/cpp/2024-0418-race-the-beam.webm)
|
74
74
|
|
75
|
+
made in Norway 🇳🇴
|
76
|
+
|
75
77
|
|
76
78
|
## readme toc
|
77
79
|
|
@@ -162,7 +164,7 @@ turn almost any device into a file server with resumable uploads/downloads using
|
|
162
164
|
* [feature chickenbits](#feature-chickenbits) - buggy feature? rip it out
|
163
165
|
* [feature beefybits](#feature-beefybits) - force-enable features with known issues on your OS/env
|
164
166
|
* [packages](#packages) - the party might be closer than you think
|
165
|
-
* [arch package](#arch-package) -
|
167
|
+
* [arch package](#arch-package) - `pacman -S copyparty` (in [arch linux extra](https://archlinux.org/packages/extra/any/copyparty/))
|
166
168
|
* [fedora package](#fedora-package) - does not exist yet
|
167
169
|
* [nix package](#nix-package) - `nix profile install github:9001/copyparty`
|
168
170
|
* [nixos module](#nixos-module)
|
@@ -475,6 +477,9 @@ upgrade notes
|
|
475
477
|
|
476
478
|
"frequently" asked questions
|
477
479
|
|
480
|
+
* CopyParty?
|
481
|
+
* nope! the name is either copyparty (all-lowercase) or Copyparty -- it's [one word](https://en.wiktionary.org/wiki/copyparty) after all :>
|
482
|
+
|
478
483
|
* can I change the 🌲 spinning pine-tree loading animation?
|
479
484
|
* [yeah...](https://github.com/9001/copyparty/tree/hovudstraum/docs/rice#boring-loader-spinner) :-(
|
480
485
|
|
@@ -973,6 +978,7 @@ semi-intentional limitations:
|
|
973
978
|
|
974
979
|
* cleanup of expired shares only works when global option `e2d` is set, and/or at least one volume on the server has volflag `e2d`
|
975
980
|
* only folders from the same volume are shared; if you are sharing a folder which contains other volumes, then the contents of those volumes will not be available
|
981
|
+
* if you change [password hashing](#password-hashing) settings after creating a password-protected share, then that share will stop working
|
976
982
|
* related to [IdP volumes being forgotten on shutdown](https://github.com/9001/copyparty/blob/hovudstraum/docs/idp.md#idp-volumes-are-forgotten-on-shutdown), any shares pointing into a user's IdP volume will be unavailable until that user makes their first request after a restart
|
977
983
|
* no option to "delete after first access" because tricky
|
978
984
|
* when linking something to discord (for example) it'll get accessed by their scraper and that would count as a hit
|
@@ -2261,10 +2267,14 @@ if your distro/OS is not mentioned below, there might be some hints in the [«on
|
|
2261
2267
|
|
2262
2268
|
## arch package
|
2263
2269
|
|
2264
|
-
|
2270
|
+
`pacman -S copyparty` (in [arch linux extra](https://archlinux.org/packages/extra/any/copyparty/))
|
2265
2271
|
|
2266
2272
|
it comes with a [systemd service](./contrib/package/arch/copyparty.service) and expects to find one or more [config files](./docs/example.conf) in `/etc/copyparty.d/`
|
2267
2273
|
|
2274
|
+
after installing it, you may want to `cp /usr/lib/systemd/system/copyparty.service /etc/systemd/system/` and then `vim /etc/systemd/system/copyparty.service` to change what user/group it is running as (you only need to do this once)
|
2275
|
+
|
2276
|
+
NOTE: there used to be an aur package; this evaporated when copyparty was adopted by the official archlinux repos. If you're still using the aur package, please move
|
2277
|
+
|
2268
2278
|
|
2269
2279
|
## fedora package
|
2270
2280
|
|
@@ -2568,6 +2578,11 @@ below are some tweaks roughly ordered by usefulness:
|
|
2568
2578
|
|
2569
2579
|
when uploading files,
|
2570
2580
|
|
2581
|
+
* when uploading from very fast storage (NVMe SSD) with chrome/firefox, enable `[wasm]` in the `[⚙️] settings` tab to more effectively use all CPU-cores for hashing
|
2582
|
+
* don't do this on Safari (runs faster without)
|
2583
|
+
* don't do this on older browsers; likely to provoke browser-bugs (browser eats all RAM and crashes)
|
2584
|
+
* can be made default-enabled serverside with `--nosubtle 137` (chrome v137+) or `--nosubtle 2` (chrome+firefox)
|
2585
|
+
|
2571
2586
|
* chrome is recommended (unfortunately), at least compared to firefox:
|
2572
2587
|
* up to 90% faster when hashing, especially on SSDs
|
2573
2588
|
* up to 40% faster when uploading over extremely fast internets
|
@@ -1,17 +1,17 @@
|
|
1
1
|
copyparty/__init__.py,sha256=TnFSStmHlwlRIClWW8jSHxZpt3dl_kN6_pEnqBqh3mE,2638
|
2
|
-
copyparty/__main__.py,sha256=
|
3
|
-
copyparty/__version__.py,sha256=
|
4
|
-
copyparty/authsrv.py,sha256=
|
2
|
+
copyparty/__main__.py,sha256=WRhqmrVEBU1_ejCNxEsn_5rhfrztjA-V04kZnUL_IIs,121255
|
3
|
+
copyparty/__version__.py,sha256=3LDY1k8_pNQJ6jOZqNHZXY9IYsLJzzrl1fDwi-GXsDw,253
|
4
|
+
copyparty/authsrv.py,sha256=aDPAs4XwchHA2CBor3K6CakXxljQ6AWOY1wTv5Jt2Iw,114130
|
5
5
|
copyparty/broker_mp.py,sha256=QdOXXvV2Xn6J0CysEqyY3GZbqxQMyWnTpnba-a5lMc0,4987
|
6
6
|
copyparty/broker_mpw.py,sha256=PpSS4SK3pItlpfD8OwVr3QmJEPKlUgaf2nuMOozixgU,3347
|
7
7
|
copyparty/broker_thr.py,sha256=fjoYtpSscUA7-nMl4r1n2R7UK3J9lrvLS3rUZ-iJzKQ,1721
|
8
8
|
copyparty/broker_util.py,sha256=76mfnFOpX1gUUvtjm8UQI7jpTIaVINX10QonM-B7ggc,1680
|
9
|
-
copyparty/cert.py,sha256=
|
10
|
-
copyparty/cfg.py,sha256=
|
9
|
+
copyparty/cert.py,sha256=pSSeVYticrDsnsrdRtfpUQN-8WRObsqrYtSRroXmgxo,7992
|
10
|
+
copyparty/cfg.py,sha256=H2p2bHRWk2e4rOx5NZWUVHUcoETy3dtzDkeC8TdosRY,14522
|
11
11
|
copyparty/dxml.py,sha256=vu5uZQtwvwoqnFHbULs2Zh_y2DETu0T-ENpMZ1i2CV4,2505
|
12
12
|
copyparty/fsutil.py,sha256=NC_CJC4TDag399vVDH9_uQfdfpTMwRFLNxERSWhlVvs,4594
|
13
13
|
copyparty/ftpd.py,sha256=G7PApVIFeSzRo4-D-9uRb8NxYgz6nFwTEbrOk1ErYCU,17969
|
14
|
-
copyparty/httpcli.py,sha256=
|
14
|
+
copyparty/httpcli.py,sha256=ze5Sl51itREFGiYM3p4at32Zol7RSJDHiDKNJel0MFk,222513
|
15
15
|
copyparty/httpconn.py,sha256=mQSgljh0Q-jyWjF4tQLrHbRKRe9WKl19kGqsGMsJpWo,6880
|
16
16
|
copyparty/httpsrv.py,sha256=pxH_Eh8ElBLvOEDejgpP9Bvk65HNEou-03aYIcgXhrs,18090
|
17
17
|
copyparty/ico.py,sha256=-7QjF_jIxnPo4Vr0oUPksQ_U_Ef0HRsSPm3s71idOz8,3879
|
@@ -23,16 +23,16 @@ copyparty/pwhash.py,sha256=zHoz9FHGkFBxoRvSfG1XyjN3ibww_h5GE6_m5yS-fws,4246
|
|
23
23
|
copyparty/smbd.py,sha256=dixFl2wlWymq_Cycc8a4cVB4gY8RSg2e3tE7Xr-aDa0,14614
|
24
24
|
copyparty/ssdp.py,sha256=R1Z61GZOxBMF2Sk4RTxKWMOemogmcjEWG-CvLihd45k,7023
|
25
25
|
copyparty/star.py,sha256=tV5BbX6AiQ7N4UU8DYtSTckNYeoeey4DBqq4LjfymbY,3818
|
26
|
-
copyparty/sutil.py,sha256=
|
26
|
+
copyparty/sutil.py,sha256=E65jAaOzHlJYnqsOKDMPVT8kALPUVexpkSStWBdItkY,3231
|
27
27
|
copyparty/svchub.py,sha256=leERN449te_yBbyChcOenjY_nuNPoFJpncLHfDMvDYE,46618
|
28
28
|
copyparty/szip.py,sha256=9srQzjsTBrBadf6QMh4YRAL70rkZLevAOHqXWK5jvr8,8846
|
29
29
|
copyparty/tcpsrv.py,sha256=F5K4Qr4eBLfhdLT_39yDf6ftrhWuGTrd6DSqqp_6e-Q,20480
|
30
|
-
copyparty/tftpd.py,sha256=
|
30
|
+
copyparty/tftpd.py,sha256=tbnxUsilwyusrAUCVVjJUZnR9TIHDkE-99WLsUxAIGA,14029
|
31
31
|
copyparty/th_cli.py,sha256=IEX5tCb0gw9Z2aRIDL9bwdvJ6g5jhWZ8OEAAz16_xN4,5426
|
32
|
-
copyparty/th_srv.py,sha256=
|
32
|
+
copyparty/th_srv.py,sha256=2omGprnKGWim6U7fjJAXI41UCZBSxRwZfS0rCDsUDps,32556
|
33
33
|
copyparty/u2idx.py,sha256=4Y5OOPyVkc-pS0z6e3p4StXAMnjHobSOMmMsvNUTD34,13674
|
34
|
-
copyparty/up2k.py,sha256=
|
35
|
-
copyparty/util.py,sha256=
|
34
|
+
copyparty/up2k.py,sha256=nnR_ZKaopSNBuAjSN3Q5G_UVe6GmYD1NkxJt5QQf02o,178079
|
35
|
+
copyparty/util.py,sha256=Keb-mlTq4rtWjv3utaGsKqwujHYPZLkaBZOeivnGxKc,103485
|
36
36
|
copyparty/bos/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
37
37
|
copyparty/bos/bos.py,sha256=Wb7eWsXJgR5AFlBR9ZOyKrLTwy-Kct9RrGiOu4Jo37Y,1622
|
38
38
|
copyparty/bos/path.py,sha256=yEjCq2ki9CvxA5sCT8pS0keEXwugs0ZeUyUhdBziOCI,777
|
@@ -55,9 +55,9 @@ copyparty/stolen/ifaddr/_posix.py,sha256=-67NdfGrCktfQPakT2fLbjl2U00QMvyBGkSvrUu
|
|
55
55
|
copyparty/stolen/ifaddr/_shared.py,sha256=uNC4SdEIgdSLKvuUzsf1aM-H1Xrc_9mpLoOT43YukGs,6206
|
56
56
|
copyparty/stolen/ifaddr/_win32.py,sha256=EE-QyoBgeB7lYQ6z62VjXNaRozaYfCkaJBHGNA8QtZM,4026
|
57
57
|
copyparty/web/baguettebox.js.gz,sha256=r2c_hOZV_RTyl4CqWWX14FDWP8nnDVwGkDl4Sfk0rU4,8239
|
58
|
-
copyparty/web/browser.css.gz,sha256
|
58
|
+
copyparty/web/browser.css.gz,sha256=-w-OUbKy0UdL9vYKAC95ayl4MesDAFjqrq60uAxPj4U,11728
|
59
59
|
copyparty/web/browser.html,sha256=auvhLVE_t0aIN0q-nk0zOWFqITgDhroMAAviBNLoFfc,4788
|
60
|
-
copyparty/web/browser.js.gz,sha256=
|
60
|
+
copyparty/web/browser.js.gz,sha256=GEQR3qsVSFWoJun_cj-3ljE5ccL6pApSPwzNj36XToc,94957
|
61
61
|
copyparty/web/browser2.html,sha256=NRUZ08GH-e2YcGXcoz0UjYg6JIVF42u4IMX4HHwWTmg,1587
|
62
62
|
copyparty/web/cf.html,sha256=lJThtNFNAQT1ClCHHlivAkDGE0LutedwopXD62Z8Nys,589
|
63
63
|
copyparty/web/dbg-audio.js.gz,sha256=Ma-KZtK8LnmiwNvNKFKXMPYl_Nn_3U7GsJ6-DRWC2HE,688
|
@@ -79,16 +79,16 @@ copyparty/web/shares.html,sha256=YctvUrKuBYu42kxVylyW2_DEHm7Ik6uHqzfzVZ4N0ac,254
|
|
79
79
|
copyparty/web/shares.js.gz,sha256=emeY2-wjkh8x1JgaW6ny5fcC7XpZzZzfE1f-sEyntQ4,940
|
80
80
|
copyparty/web/splash.css.gz,sha256=S8_A7JJl71xACRBYGzafeaD82OacW6Fa7oKPiNyrhAs,1087
|
81
81
|
copyparty/web/splash.html,sha256=ouFB1P9g0K-S3LZQtOLfNz3GLXIRjyETkxo9aJZhiYk,6249
|
82
|
-
copyparty/web/splash.js.gz,sha256=
|
83
|
-
copyparty/web/svcs.html,sha256=
|
82
|
+
copyparty/web/splash.js.gz,sha256=Qh0KoPWKoJ77cyzOwnhUaCTI5XUoPVV3YJURKklqpBg,2739
|
83
|
+
copyparty/web/svcs.html,sha256=cxgrhX9wD0Z_kvidry3aS9ubuGXYDj2f4ehq1X8T1EA,14227
|
84
84
|
copyparty/web/svcs.js.gz,sha256=lMXEP9W-VlXyANlva4q0ASSxvvHYlE2CrmxGgZXZop0,713
|
85
85
|
copyparty/web/ui.css.gz,sha256=iDjrmq32aDN6l2S5AjCQdKjD6bxmzP6ji2WjM1FjKiU,2819
|
86
|
-
copyparty/web/up2k.js.gz,sha256=
|
87
|
-
copyparty/web/util.js.gz,sha256=
|
88
|
-
copyparty/web/w.hash.js.gz,sha256=
|
86
|
+
copyparty/web/up2k.js.gz,sha256=vf9Kth2JQ4F-XmWhjcGXqy6gA4eOkg0-EfVjAGQsW5o,24794
|
87
|
+
copyparty/web/util.js.gz,sha256=VYXSNNvydhFx-LdPMNjSovMEi-9euYzH4tntPTH8wcg,15255
|
88
|
+
copyparty/web/w.hash.js.gz,sha256=cFH6Xo4YRgH9Wr7RmHMSEfpuTmmIvEmzmSvv4RLmyPU,1193
|
89
89
|
copyparty/web/a/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
90
90
|
copyparty/web/a/partyfuse.py,sha256=9p5Hpg_IBiSimv7j9kmPhCGpy-FLXSRUOYnLjJ5JifU,28049
|
91
|
-
copyparty/web/a/u2c.py,sha256=
|
91
|
+
copyparty/web/a/u2c.py,sha256=auXzLj04dt_lw4H70PhNUK0GjrQEThrybo2-77SLsUg,53165
|
92
92
|
copyparty/web/a/webdav-cfg.bat,sha256=Y4NoGZlksAIg4cBMb7KdJrpKC6Nx97onaTl6yMjaimk,1449
|
93
93
|
copyparty/web/dd/2.png,sha256=gJ14XFPzaw95L6z92fSq9eMPikSQyu-03P1lgiGe0_I,258
|
94
94
|
copyparty/web/dd/3.png,sha256=4lho8Koz5tV7jJ4ODo6GMTScZfkqsT05yp48EDFIlyg,252
|
@@ -109,9 +109,9 @@ copyparty/web/deps/prismd.css.gz,sha256=ObUlksQVr-OuYlTz-I4B23TeBg2QDVVGRnWBz8cV
|
|
109
109
|
copyparty/web/deps/scp.woff2,sha256=w99BDU5i8MukkMEL-iW0YO9H4vFFZSPWxbkH70ytaAg,8612
|
110
110
|
copyparty/web/deps/sha512.ac.js.gz,sha256=lFZaCLumgWxrvEuDr4bqdKHsqjX82AbVAb7_F45Yk88,7033
|
111
111
|
copyparty/web/deps/sha512.hw.js.gz,sha256=UAed2_ocklZCnIzcSYz2h4P1ycztlCLj-ewsRTud2lU,7939
|
112
|
-
copyparty-1.17.
|
113
|
-
copyparty-1.17.
|
114
|
-
copyparty-1.17.
|
115
|
-
copyparty-1.17.
|
116
|
-
copyparty-1.17.
|
117
|
-
copyparty-1.17.
|
112
|
+
copyparty-1.17.2.dist-info/licenses/LICENSE,sha256=gOr4h33pCsBEg9uIy9AYmb7qlocL4V9t2uPJS5wllr0,1072
|
113
|
+
copyparty-1.17.2.dist-info/METADATA,sha256=kCbbfcG7Nl-bV-Opp56naw3fdqw3PYchKl5bXlamDXk,163776
|
114
|
+
copyparty-1.17.2.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
115
|
+
copyparty-1.17.2.dist-info/entry_points.txt,sha256=4zw6a3rqASywQomiYLObjjlxybaI65LYYOTJwgKz7b0,128
|
116
|
+
copyparty-1.17.2.dist-info/top_level.txt,sha256=LnYUPsDyk-8kFgM6YJLG4h820DQekn81cObKSu9g-sI,10
|
117
|
+
copyparty-1.17.2.dist-info/RECORD,,
|
File without changes
|
File without changes
|
File without changes
|