copyparty 1.12.0__py3-none-any.whl → 1.12.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 CHANGED
@@ -852,6 +852,7 @@ def add_fs(ap):
852
852
  ap2 = ap.add_argument_group("filesystem options")
853
853
  rm_re_def = "5/0.1" if ANYWIN else "0/0"
854
854
  ap2.add_argument("--rm-retry", metavar="T/R", type=u, default=rm_re_def, help="if a file cannot be deleted because it is busy, continue trying for \033[33mT\033[0m seconds, retry every \033[33mR\033[0m seconds; disable with 0/0 (volflag=rm_retry)")
855
+ ap2.add_argument("--mv-retry", metavar="T/R", type=u, default=rm_re_def, help="if a file cannot be renamed because it is busy, continue trying for \033[33mT\033[0m seconds, retry every \033[33mR\033[0m seconds; disable with 0/0 (volflag=mv_retry)")
855
856
  ap2.add_argument("--iobuf", metavar="BYTES", type=int, default=256*1024, help="file I/O buffer-size; if your volumes are on a network drive, try increasing to \033[32m524288\033[0m or even \033[32m4194304\033[0m (and let me know if that improves your performance)")
856
857
 
857
858
 
@@ -943,6 +944,8 @@ def add_auth(ap):
943
944
  ap2.add_argument("--idp-h-grp", metavar="HN", type=u, default="", help="assume the request-header \033[33mHN\033[0m contains the groupname of the requesting user; can be referenced in config files for group-based access control")
944
945
  ap2.add_argument("--idp-h-key", metavar="HN", type=u, default="", help="optional but recommended safeguard; your reverse-proxy will insert a secret header named \033[33mHN\033[0m into all requests, and the other IdP headers will be ignored if this header is not present")
945
946
  ap2.add_argument("--idp-gsep", metavar="RE", type=u, default="|:;+,", help="if there are multiple groups in \033[33m--idp-h-grp\033[0m, they are separated by one of the characters in \033[33mRE\033[0m")
947
+ ap2.add_argument("--no-bauth", action="store_true", help="disable basic-authentication support; do not accept passwords from the 'Authenticate' header at all. NOTE: This breaks support for the android app")
948
+ ap2.add_argument("--bauth-last", action="store_true", help="keeps basic-authentication enabled, but only as a last-resort; if a cookie is also provided then the cookie wins")
946
949
 
947
950
 
948
951
  def add_zeroconf(ap):
copyparty/__version__.py CHANGED
@@ -1,8 +1,8 @@
1
1
  # coding: utf-8
2
2
 
3
- VERSION = (1, 12, 0)
3
+ VERSION = (1, 12, 2)
4
4
  CODENAME = "locksmith"
5
- BUILD_DT = (2024, 4, 6)
5
+ BUILD_DT = (2024, 4, 12)
6
6
 
7
7
  S_VERSION = ".".join(map(str, VERSION))
8
8
  S_BUILD_DT = "{0:04d}-{1:02d}-{2:02d}".format(*BUILD_DT)
copyparty/authsrv.py CHANGED
@@ -1757,13 +1757,14 @@ class AuthSrv(object):
1757
1757
  if k in vol.flags:
1758
1758
  vol.flags[k] = float(vol.flags[k])
1759
1759
 
1760
- try:
1761
- zs1, zs2 = vol.flags["rm_retry"].split("/")
1762
- vol.flags["rm_re_t"] = float(zs1)
1763
- vol.flags["rm_re_r"] = float(zs2)
1764
- except:
1765
- t = 'volume "/%s" has invalid rm_retry [%s]'
1766
- raise Exception(t % (vol.vpath, vol.flags.get("rm_retry")))
1760
+ for k in ("mv_re", "rm_re"):
1761
+ try:
1762
+ zs1, zs2 = vol.flags[k + "try"].split("/")
1763
+ vol.flags[k + "_t"] = float(zs1)
1764
+ vol.flags[k + "_r"] = float(zs2)
1765
+ except:
1766
+ t = 'volume "/%s" has invalid %stry [%s]'
1767
+ raise Exception(t % (vol.vpath, k, vol.flags.get(k + "try")))
1767
1768
 
1768
1769
  for k1, k2 in IMPLICATIONS:
1769
1770
  if k1 in vol.flags:
copyparty/cert.py CHANGED
@@ -6,10 +6,17 @@ import os
6
6
  import shutil
7
7
  import time
8
8
 
9
- from .util import Netdev, runcmd
9
+ from .__init__ import ANYWIN
10
+ from .util import Netdev, runcmd, wrename, wunlink
10
11
 
11
12
  HAVE_CFSSL = True
12
13
 
14
+ if ANYWIN:
15
+ VF = {"mv_re_t": 5, "rm_re_t": 5, "mv_re_r": 0.1, "rm_re_r": 0.1}
16
+ else:
17
+ VF = {"mv_re_t": 0, "rm_re_t": 0}
18
+
19
+
13
20
  def ensure_cert(log , args) :
14
21
  """
15
22
  the default cert (and the entire TLS support) is only here to enable the
@@ -101,8 +108,12 @@ def _gen_ca(log , args):
101
108
  raise Exception("failed to translate ca-cert: {}, {}".format(rc, se), 3)
102
109
 
103
110
  bname = os.path.join(args.crt_dir, "ca")
104
- os.rename(bname + "-key.pem", bname + ".key")
105
- os.unlink(bname + ".csr")
111
+ try:
112
+ wunlink(log, bname + ".key", VF)
113
+ except:
114
+ pass
115
+ wrename(log, bname + "-key.pem", bname + ".key", VF)
116
+ wunlink(log, bname + ".csr", VF)
106
117
 
107
118
  log("cert", "new ca OK", 2)
108
119
 
@@ -181,11 +192,11 @@ def _gen_srv(log , args, netdevs ):
181
192
 
182
193
  bname = os.path.join(args.crt_dir, "srv")
183
194
  try:
184
- os.unlink(bname + ".key")
195
+ wunlink(log, bname + ".key", VF)
185
196
  except:
186
197
  pass
187
- os.rename(bname + "-key.pem", bname + ".key")
188
- os.unlink(bname + ".csr")
198
+ wrename(log, bname + "-key.pem", bname + ".key", VF)
199
+ wunlink(log, bname + ".csr", VF)
189
200
 
190
201
  with open(os.path.join(args.crt_dir, "ca.pem"), "rb") as f:
191
202
  ca = f.read()
copyparty/cfg.py CHANGED
@@ -63,6 +63,7 @@ def vf_vmap() :
63
63
  "lg_sbf",
64
64
  "md_sbf",
65
65
  "nrand",
66
+ "mv_retry",
66
67
  "rm_retry",
67
68
  "sort",
68
69
  "unlist",
@@ -214,6 +215,7 @@ flagcats = {
214
215
  "dots": "allow all users with read-access to\nenable the option to show dotfiles in listings",
215
216
  "fk=8": 'generates per-file accesskeys,\nwhich are then required at the "g" permission;\nkeys are invalidated if filesize or inode changes',
216
217
  "fka=8": 'generates slightly weaker per-file accesskeys,\nwhich are then required at the "g" permission;\nnot affected by filesize or inode numbers',
218
+ "mv_retry": "ms-windows: timeout for renaming busy files",
217
219
  "rm_retry": "ms-windows: timeout for deleting busy files",
218
220
  "davauth": "ask webdav clients to login for all folders",
219
221
  "davrt": "show lastmod time of symlink destination, not the link itself\n(note: this option is always enabled for recursive listings)",
copyparty/httpcli.py CHANGED
@@ -89,6 +89,7 @@ from .util import (
89
89
  vjoin,
90
90
  vol_san,
91
91
  vsplit,
92
+ wrename,
92
93
  wunlink,
93
94
  yieldfile,
94
95
  )
@@ -439,7 +440,11 @@ class HttpCli(object):
439
440
 
440
441
  zso = self.headers.get("authorization")
441
442
  bauth = ""
442
- if zso:
443
+ if (
444
+ zso
445
+ and not self.args.no_bauth
446
+ and (not cookie_pw or not self.args.bauth_last)
447
+ ):
443
448
  try:
444
449
  zb = zso.split(" ")[1].encode("ascii")
445
450
  zs = base64.b64decode(zb).decode("utf-8")
@@ -1796,7 +1801,7 @@ class HttpCli(object):
1796
1801
  f, fn = zfw["orz"]
1797
1802
 
1798
1803
  path2 = os.path.join(fdir, fn2)
1799
- atomic_move(path, path2)
1804
+ atomic_move(self.log, path, path2, vfs.flags)
1800
1805
  fn = fn2
1801
1806
  path = path2
1802
1807
 
@@ -1877,7 +1882,9 @@ class HttpCli(object):
1877
1882
  self.reply(t.encode("utf-8"), 201, headers=h)
1878
1883
  return True
1879
1884
 
1880
- def bakflip(self, f , ofs , sz , sha ) :
1885
+ def bakflip(
1886
+ self, f , ofs , sz , sha , flags
1887
+ ) :
1881
1888
  if not self.args.bak_flips or self.args.nw:
1882
1889
  return
1883
1890
 
@@ -1905,7 +1912,7 @@ class HttpCli(object):
1905
1912
 
1906
1913
  if nrem:
1907
1914
  self.log("bakflip truncated; {} remains".format(nrem), 1)
1908
- atomic_move(fp, fp + ".trunc")
1915
+ atomic_move(self.log, fp, fp + ".trunc", flags)
1909
1916
  else:
1910
1917
  self.log("bakflip ok", 2)
1911
1918
 
@@ -2171,7 +2178,7 @@ class HttpCli(object):
2171
2178
 
2172
2179
  if sha_b64 != chash:
2173
2180
  try:
2174
- self.bakflip(f, cstart[0], post_sz, sha_b64)
2181
+ self.bakflip(f, cstart[0], post_sz, sha_b64, vfs.flags)
2175
2182
  except:
2176
2183
  self.log("bakflip failed: " + min_ex())
2177
2184
 
@@ -2523,7 +2530,7 @@ class HttpCli(object):
2523
2530
  raise
2524
2531
 
2525
2532
  if not nullwrite:
2526
- atomic_move(tabspath, abspath)
2533
+ atomic_move(self.log, tabspath, abspath, vfs.flags)
2527
2534
 
2528
2535
  tabspath = ""
2529
2536
 
@@ -2763,7 +2770,7 @@ class HttpCli(object):
2763
2770
  hidedir(dp)
2764
2771
  except:
2765
2772
  pass
2766
- bos.rename(fp, os.path.join(mdir, ".hist", mfile2))
2773
+ wrename(self.log, fp, os.path.join(mdir, ".hist", mfile2), vfs.flags)
2767
2774
 
2768
2775
  assert self.parser.gen
2769
2776
  p_field, _, p_data = next(self.parser.gen)
copyparty/multicast.py CHANGED
@@ -203,6 +203,7 @@ class MCast(object):
203
203
  except:
204
204
  t = "announce failed on {} [{}]:\n{}"
205
205
  self.log(t.format(netdev, ip, min_ex()), 3)
206
+ sck.close()
206
207
 
207
208
  if self.args.zm_msub:
208
209
  for s1 in self.srv.values():
copyparty/svchub.py CHANGED
@@ -418,6 +418,12 @@ class SvcHub(object):
418
418
  t = "WARNING: found config files in [%s]: %s\n config files are not expected here, and will NOT be loaded (unless your setup is intentionally hella funky)"
419
419
  self.log("root", t % (E.cfg, ", ".join(hits)), 3)
420
420
 
421
+ if self.args.no_bauth:
422
+ t = "WARNING: --no-bauth disables support for the Android app; you may want to use --bauth-last instead"
423
+ self.log("root", t, 3)
424
+ if self.args.bauth_last:
425
+ self.log("root", "WARNING: ignoring --bauth-last due to --no-bauth", 3)
426
+
421
427
  def _process_config(self) :
422
428
  al = self.args
423
429
 
@@ -538,6 +544,13 @@ class SvcHub(object):
538
544
  except:
539
545
  raise Exception("invalid --rm-retry [%s]" % (self.args.rm_retry,))
540
546
 
547
+ try:
548
+ zf1, zf2 = self.args.mv_retry.split("/")
549
+ self.args.mv_re_t = float(zf1)
550
+ self.args.mv_re_r = float(zf2)
551
+ except:
552
+ raise Exception("invalid --mv-retry [%s]" % (self.args.mv_retry,))
553
+
541
554
  return True
542
555
 
543
556
  def _ipa2re(self, txt) :
copyparty/th_srv.py CHANGED
@@ -28,6 +28,7 @@ from .util import (
28
28
  runcmd,
29
29
  statdir,
30
30
  vsplit,
31
+ wrename,
31
32
  wunlink,
32
33
  )
33
34
 
@@ -343,7 +344,7 @@ class ThumbSrv(object):
343
344
  pass
344
345
 
345
346
  try:
346
- bos.rename(ttpath, tpath)
347
+ wrename(self.log, ttpath, tpath, vn.flags)
347
348
  except:
348
349
  pass
349
350
 
copyparty/up2k.py CHANGED
@@ -88,6 +88,9 @@ CV_EXTS = set(zsg.split(","))
88
88
  HINT_HISTPATH = "you could try moving the database to another location (preferably an SSD or NVME drive) using either the --hist argument (global option for all volumes), or the hist volflag (just for this volume)"
89
89
 
90
90
 
91
+ VF_CAREFUL = {"mv_re_t": 5, "rm_re_t": 5, "mv_re_r": 0.1, "rm_re_r": 0.1}
92
+
93
+
91
94
  class Dbw(object):
92
95
  def __init__(self, c , n , t ) :
93
96
  self.c = c
@@ -866,7 +869,7 @@ class Up2k(object):
866
869
  ft = "\033[0;32m{}{:.0}"
867
870
  ff = "\033[0;35m{}{:.0}"
868
871
  fv = "\033[0;36m{}:\033[90m{}"
869
- fx = set(("html_head", "rm_re_t", "rm_re_r"))
872
+ fx = set(("html_head", "rm_re_t", "rm_re_r", "mv_re_t", "mv_re_r"))
870
873
  fd = vf_bmap()
871
874
  fd.update(vf_cmap())
872
875
  fd.update(vf_vmap())
@@ -3041,12 +3044,11 @@ class Up2k(object):
3041
3044
  t = "finish_upload {} with remaining chunks {}"
3042
3045
  raise Pebkac(500, t.format(wark, job["need"]))
3043
3046
 
3044
- # self.log("--- " + wark + " " + dst + " finish_upload atomic " + dst, 4)
3045
- atomic_move(src, dst)
3046
-
3047
3047
  upt = job.get("at") or time.time()
3048
3048
  vflags = self.flags[ptop]
3049
3049
 
3050
+ atomic_move(self.log, src, dst, vflags)
3051
+
3050
3052
  times = (int(time.time()), int(job["lmod"]))
3051
3053
  self.log(
3052
3054
  "no more chunks, setting times {} ({}) on {}".format(
@@ -3650,7 +3652,7 @@ class Up2k(object):
3650
3652
  self._symlink(dlink, dabs, dvn.flags, lmod=ftime)
3651
3653
  wunlink(self.log, sabs, svn.flags)
3652
3654
  else:
3653
- atomic_move(sabs, dabs)
3655
+ atomic_move(self.log, sabs, dabs, svn.flags)
3654
3656
 
3655
3657
  except OSError as ex:
3656
3658
  if ex.errno != errno.EXDEV:
@@ -3827,8 +3829,7 @@ class Up2k(object):
3827
3829
  self.log("linkswap [{}] and [{}]".format(sabs, slabs))
3828
3830
  mt = bos.path.getmtime(slabs, False)
3829
3831
  flags = self.flags.get(ptop) or {}
3830
- wunlink(self.log, slabs, flags)
3831
- bos.rename(sabs, slabs)
3832
+ atomic_move(self.log, sabs, slabs, flags)
3832
3833
  bos.utime(slabs, (int(time.time()), int(mt)), False)
3833
3834
  self._symlink(slabs, sabs, flags, False)
3834
3835
  full[slabs] = (ptop, rem)
@@ -4139,7 +4140,7 @@ class Up2k(object):
4139
4140
  with gzip.GzipFile(path2, "wb") as f:
4140
4141
  f.write(j)
4141
4142
 
4142
- atomic_move(path2, path)
4143
+ atomic_move(self.log, path2, path, VF_CAREFUL)
4143
4144
 
4144
4145
  self.log("snap: {} |{}|".format(path, len(reg.keys())))
4145
4146
  self.snap_prev[ptop] = etag
copyparty/util.py CHANGED
@@ -2104,26 +2104,29 @@ def lsof(log , abspath ) :
2104
2104
  log("lsof failed; " + min_ex(), 3)
2105
2105
 
2106
2106
 
2107
- def atomic_move(usrc , udst ) :
2108
- src = fsenc(usrc)
2109
- dst = fsenc(udst)
2110
- if not PY2:
2111
- os.replace(src, dst)
2107
+ def _fs_mvrm(
2108
+ log , src , dst , atomic , flags
2109
+ ) :
2110
+ bsrc = fsenc(src)
2111
+ bdst = fsenc(dst)
2112
+ if atomic:
2113
+ k = "mv_re_"
2114
+ act = "atomic-rename"
2115
+ osfun = os.replace
2116
+ args = [bsrc, bdst]
2117
+ elif dst:
2118
+ k = "mv_re_"
2119
+ act = "rename"
2120
+ osfun = os.rename
2121
+ args = [bsrc, bdst]
2112
2122
  else:
2113
- if os.path.exists(dst):
2114
- os.unlink(dst)
2115
-
2116
- os.rename(src, dst)
2117
-
2118
-
2119
- def wunlink(log , abspath , flags ) :
2120
- maxtime = flags.get("rm_re_t", 0.0)
2121
- bpath = fsenc(abspath)
2122
- if not maxtime:
2123
- os.unlink(bpath)
2124
- return True
2123
+ k = "rm_re_"
2124
+ act = "delete"
2125
+ osfun = os.unlink
2126
+ args = [bsrc]
2125
2127
 
2126
- chill = flags.get("rm_re_r", 0.0)
2128
+ maxtime = flags.get(k + "t", 0.0)
2129
+ chill = flags.get(k + "r", 0.0)
2127
2130
  if chill < 0.001:
2128
2131
  chill = 0.1
2129
2132
 
@@ -2131,14 +2134,19 @@ def wunlink(log , abspath , flags ) :
2131
2134
  t0 = now = time.time()
2132
2135
  for attempt in range(90210):
2133
2136
  try:
2134
- if ino and os.stat(bpath).st_ino != ino:
2135
- log("inode changed; aborting delete")
2137
+ if ino and os.stat(bsrc).st_ino != ino:
2138
+ t = "src inode changed; aborting %s %s"
2139
+ log(t % (act, src), 1)
2136
2140
  return False
2137
- os.unlink(bpath)
2141
+ if (dst and not atomic) and os.path.exists(bdst):
2142
+ t = "something appeared at dst; aborting rename [%s] ==> [%s]"
2143
+ log(t % (src, dst), 1)
2144
+ return False
2145
+ osfun(*args)
2138
2146
  if attempt:
2139
2147
  now = time.time()
2140
- t = "deleted in %.2f sec, attempt %d"
2141
- log(t % (now - t0, attempt + 1))
2148
+ t = "%sd in %.2f sec, attempt %d: %s"
2149
+ log(t % (act, now - t0, attempt + 1, src))
2142
2150
  return True
2143
2151
  except OSError as ex:
2144
2152
  now = time.time()
@@ -2148,15 +2156,45 @@ def wunlink(log , abspath , flags ) :
2148
2156
  raise
2149
2157
  if not attempt:
2150
2158
  if not PY2:
2151
- ino = os.stat(bpath).st_ino
2152
- t = "delete failed (err.%d); retrying for %d sec: %s"
2153
- log(t % (ex.errno, maxtime + 0.99, abspath))
2159
+ ino = os.stat(bsrc).st_ino
2160
+ t = "%s failed (err.%d); retrying for %d sec: [%s]"
2161
+ log(t % (act, ex.errno, maxtime + 0.99, src))
2154
2162
 
2155
2163
  time.sleep(chill)
2156
2164
 
2157
2165
  return False # makes pylance happy
2158
2166
 
2159
2167
 
2168
+ def atomic_move(log , src , dst , flags ) :
2169
+ bsrc = fsenc(src)
2170
+ bdst = fsenc(dst)
2171
+ if PY2:
2172
+ if os.path.exists(bdst):
2173
+ _fs_mvrm(log, dst, "", False, flags) # unlink
2174
+
2175
+ _fs_mvrm(log, src, dst, False, flags) # rename
2176
+ elif flags.get("mv_re_t"):
2177
+ _fs_mvrm(log, src, dst, True, flags)
2178
+ else:
2179
+ os.replace(bsrc, bdst)
2180
+
2181
+
2182
+ def wrename(log , src , dst , flags ) :
2183
+ if not flags.get("mv_re_t"):
2184
+ os.rename(fsenc(src), fsenc(dst))
2185
+ return True
2186
+
2187
+ return _fs_mvrm(log, src, dst, False, flags)
2188
+
2189
+
2190
+ def wunlink(log , abspath , flags ) :
2191
+ if not flags.get("rm_re_t"):
2192
+ os.unlink(fsenc(abspath))
2193
+ return True
2194
+
2195
+ return _fs_mvrm(log, abspath, "", False, flags)
2196
+
2197
+
2160
2198
  def get_df(abspath ) :
2161
2199
  try:
2162
2200
  # some fuses misbehave
Binary file
Binary file
Binary file
Binary file
copyparty/web/splash.html CHANGED
@@ -94,7 +94,7 @@
94
94
  <div>
95
95
  <form method="post" enctype="multipart/form-data" action="{{ r }}/{{ qvpath }}">
96
96
  <input type="hidden" name="act" value="login" />
97
- <input type="password" name="cppwd" />
97
+ <input type="password" name="cppwd" placeholder=" password" />
98
98
  <input type="submit" value="Login" />
99
99
  {% if ahttps %}
100
100
  <a id="w" href="{{ ahttps }}">switch to https</a>
copyparty/web/util.js.gz CHANGED
Binary file
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: copyparty
3
- Version: 1.12.0
3
+ Version: 1.12.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
@@ -69,6 +69,7 @@ turn almost any device into a file server with resumable uploads/downloads using
69
69
 
70
70
  * top
71
71
  * [quickstart](#quickstart) - just run **[copyparty-sfx.py](https://github.com/9001/copyparty/releases/latest/download/copyparty-sfx.py)** -- that's it! 🎉
72
+ * [at home](#at-home) - make it accessible over the internet
72
73
  * [on servers](#on-servers) - you may also want these, especially on servers
73
74
  * [features](#features)
74
75
  * [testimonials](#testimonials) - small collection of user feedback
@@ -201,6 +202,17 @@ some recommended options:
201
202
  * see [accounts and volumes](#accounts-and-volumes) (or `--help-accounts`) for the syntax and other permissions
202
203
 
203
204
 
205
+ ### at home
206
+
207
+ make it accessible over the internet by starting a [cloudflare quicktunnel](https://developers.cloudflare.com/cloudflare-one/connections/connect-networks/do-more-with-tunnels/trycloudflare/) like so:
208
+
209
+ first download [cloudflared](https://developers.cloudflare.com/cloudflare-one/connections/connect-networks/downloads/) and then start the tunnel with `cloudflared tunnel --url http://127.0.0.1:3923`
210
+
211
+ as the tunnel starts, it will show a URL which you can share to let anyone browse your stash or upload files to you
212
+
213
+ since people will be connecting through cloudflare, run copyparty with `--xff-hdr cf-connecting-ip` to detect client IPs correctly
214
+
215
+
204
216
  ### on servers
205
217
 
206
218
  you may also want these, especially on servers:
@@ -1096,6 +1108,8 @@ tweaking the ui
1096
1108
  * to sort in music order (album, track, artist, title) with filename as fallback, you could `--sort tags/Cirle,tags/.tn,tags/Artist,tags/Title,href`
1097
1109
  * to sort by upload date, first enable showing the upload date in the listing with `-e2d -mte +.up_at` and then `--sort tags/.up_at`
1098
1110
 
1111
+ see [./docs/rice](./docs/rice) for more
1112
+
1099
1113
 
1100
1114
  ## file indexing
1101
1115
 
@@ -1,38 +1,38 @@
1
1
  copyparty/__init__.py,sha256=fUINM1abqDGzCCH_JcXdOnLdKOV-SrTI2Xo2QgQW2P4,1703
2
- copyparty/__main__.py,sha256=e9hqYxGdNJDzebB6wcUoc0J_MJ7QjDFOd8U0lHMg6so,94463
3
- copyparty/__version__.py,sha256=jARmXj1ooaOsD7tTXj7PQut35A5JlMrdGV1wNuozsHs,250
4
- copyparty/authsrv.py,sha256=qHC_sSExXnd4LLKdSKQM5RA_Xrvl2zdNT_TZRJhA454,84436
2
+ copyparty/__main__.py,sha256=S4Q3vX1OcxDX4jdiaUmJ6ISxI4zmWEqmuNmgycEuFng,95106
3
+ copyparty/__version__.py,sha256=M_tUfeuxrcHAVaa7MIyCrvu8zP98hSnRNS-1cY7Bqxw,251
4
+ copyparty/authsrv.py,sha256=-MZQnSsrEGD8cTtR90qT5-xoc9xD8PP8cjvBL75HMKo,84501
5
5
  copyparty/broker_mp.py,sha256=4mEZC5tiHUazJMgYuwInNo2dxS7jrbzrGb1qs2UBt9k,3948
6
6
  copyparty/broker_mpw.py,sha256=4ZI7bJYOwUibeAJVv9_FPGNmHrr9eOtkj_Kz0JEppTU,3197
7
7
  copyparty/broker_thr.py,sha256=eKr--HJGig5zqvNGwH9UoBG9Nvi9mT2axrRmJwknd0s,1759
8
8
  copyparty/broker_util.py,sha256=CnX_LAhQQqouONcDLtVkVlcBX3Z6pWuKDQDmmbHGEg4,1489
9
- copyparty/cert.py,sha256=bt1n-629-Gtez1C_CroXq53gXEmUsVjkTbkQ6Gu2Zfc,7323
10
- copyparty/cfg.py,sha256=CQKSyixyhxeM2narwbOfjUsjn0DZ_VYXbdMSa_tv4gw,9189
9
+ copyparty/cert.py,sha256=nCeDdzcCpvjPPUcxT4Oh7wvL_8zvddu4oXtbA-zOb8g,7607
10
+ copyparty/cfg.py,sha256=6r2-UQ7ule18evBOAxa4wMVyIag2ce32JwMh6TcibXU,9276
11
11
  copyparty/dxml.py,sha256=lZpg-kn-kQsXRtNY1n6fRaS-b7uXzMCyv8ovKnhZcZc,1548
12
12
  copyparty/fsutil.py,sha256=c4fTvmclKbVABNsjU4rGddsjCgRwi9YExAyo-06ATc8,3932
13
13
  copyparty/ftpd.py,sha256=OIExjfqOEw-Y_ygez6cIZUQec4SFOmoxEH_WOVvw-aE,15961
14
- copyparty/httpcli.py,sha256=oxMEY8rzE-f6LN2JlzvqY-dc7v85swecpFffvHjEqck,148735
14
+ copyparty/httpcli.py,sha256=q4yGtOJ_2v7KjRbk6grn0nqhI75hojZvqS3VrWGwT0M,148982
15
15
  copyparty/httpconn.py,sha256=gLOURB2Nb1w6n2ihGBspEnzEfUND9Osa4klzYuAbgzI,6829
16
16
  copyparty/httpsrv.py,sha256=af6LdApfj-Q4mWC5mVQjhnyrFzNy8_bXK3VUe0xKkeY,16368
17
17
  copyparty/ico.py,sha256=AYHdK6NlYBfBgafVYXia3jHQ9XHZdUL1D8WftLMAzIU,3545
18
18
  copyparty/mdns.py,sha256=CcraggbDxTT1ntYzD8Ebgqmw5Q4HkyZcfh5ymtCV_ak,17469
19
19
  copyparty/metrics.py,sha256=OqXFkAuoVhayGAGd_Sv-OQ9SVmdXYV8M7CxitkzE3lo,8854
20
20
  copyparty/mtag.py,sha256=wiXd26ZSYgOu4lkRDn4KLaqo6H2V7cpqUMepTHTCfKE,16851
21
- copyparty/multicast.py,sha256=4N_NQVIrGSF5ZNWYdpAfYHoZefkSowN3w1GfWAxhTL0,12291
21
+ copyparty/multicast.py,sha256=Ha27l2oATEa-Qo2WOzkeRgjAm6G_YDCfbVJWR-ao2UE,12319
22
22
  copyparty/pwhash.py,sha256=D82y8emnwpHDQq7Cr8lNuppHshbNA9ptcR2XsGOOk6E,3937
23
23
  copyparty/smbd.py,sha256=iACj5pbiKsX7bVu20BK3ebPQLB_qA7WS2l-ytrSfT3Y,14054
24
24
  copyparty/ssdp.py,sha256=H6ZftXttydcnBxcg2-Prm4P-XiybgT3xiJRUXU1pbrE,6343
25
25
  copyparty/star.py,sha256=K4NuzyfT4956uoW6GJSQ2II-JsSV57apQZwRZ4mjFoo,3790
26
26
  copyparty/sutil.py,sha256=_G4TM0YFa1vXzhRypHJ88QBdZWtYgDbom4CZjGvGIwc,3074
27
- copyparty/svchub.py,sha256=mf101Y51z4H86DYjJ0YD1LOWzygTKdHWevUNaQUOGR8,31701
27
+ copyparty/svchub.py,sha256=FiX6B70K5XVhCDuQDty8ZXhujThfkFcH3brp1rsEr-A,32258
28
28
  copyparty/szip.py,sha256=631TsEwGKV22yAnusJtvE-9fGFWr61HPGBinu-jk1QA,8591
29
29
  copyparty/tcpsrv.py,sha256=2LGUqOBAIrsmL-1pwrbsPXR71gutHccqRp-hjzt91Us,17289
30
30
  copyparty/tftpd.py,sha256=7EHAZ9LnjAXupwRNIENJ2eA8Q0lFynnwwbziV3fyzns,13157
31
31
  copyparty/th_cli.py,sha256=eSW7sBiaZAsh_XffXFzb035CTSbS3J3Q0G-BMzQGuSY,4385
32
- copyparty/th_srv.py,sha256=X_nQB7YlwPuj5_4v2jVGh7H2UtNgf_lDAD8aBjcmJag,27161
32
+ copyparty/th_srv.py,sha256=C2ZBE6ddINCuYDympRQQmhj0ULdlD6HOM6qNK-UB4so,27191
33
33
  copyparty/u2idx.py,sha256=JBEqKX1ZM8GIvQrDYb5VQ_5QiFNFsjWF6H9drHlPVEY,12709
34
- copyparty/up2k.py,sha256=834EGhamt6oXmdHdHS9BxG2LiHm4Q2Ax3NpUv8DbMr4,140723
35
- copyparty/util.py,sha256=sClrlGCL-sGVSYAuMAFR-SNXIIj5T2Tl12y6XLR_ikE,81016
34
+ copyparty/up2k.py,sha256=SnLU_60EZymqESqo13ayVGYewyf0BgZaCoPlpAOGZlQ,140773
35
+ copyparty/util.py,sha256=br6SQFXLu2Ol6gSpVX498G_ig3M2ZtKP9USMxuWE0qk,82089
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
@@ -54,10 +54,10 @@ copyparty/stolen/ifaddr/__init__.py,sha256=_BUN7eM5oD2Jgib6B22tEFSb20fD9urNPPaAl
54
54
  copyparty/stolen/ifaddr/_posix.py,sha256=-67NdfGrCktfQPakT2fLbjl2U00QMvyBGkSvrUuTOrU,2626
55
55
  copyparty/stolen/ifaddr/_shared.py,sha256=cJACl8cOxQ-HSYphZTzKMAjAx_TAFyJwUPjfD102Xqw,6111
56
56
  copyparty/stolen/ifaddr/_win32.py,sha256=EE-QyoBgeB7lYQ6z62VjXNaRozaYfCkaJBHGNA8QtZM,4026
57
- copyparty/web/baguettebox.js.gz,sha256=zf2x1n512edRty2zjP6L3-N_jpb2pMWDOjuLFynNyM8,7669
58
- copyparty/web/browser.css.gz,sha256=dvCrWbY4MswsS5tmDR50eaWk1rhsAecos3x8iKd3v6w,11434
57
+ copyparty/web/baguettebox.js.gz,sha256=Qcx5ZJWWCU4S1J0ULVXuVKWnm_SuCiEknMlt_uwIkJ8,7830
58
+ copyparty/web/browser.css.gz,sha256=ufB8EMVUJPnHl-NJN-GI3-HFJElJisgB6p0nexNtzrU,11431
59
59
  copyparty/web/browser.html,sha256=uAejLJd11rV_tQx3h2nHnJ1XY6zn1JV-meIAv74Lc8o,4873
60
- copyparty/web/browser.js.gz,sha256=hzmgXRCwVPg7rxWnOCGcSsAmOYFjVpgztWU0Yo4639g,67267
60
+ copyparty/web/browser.js.gz,sha256=k7COxnPofd9GOMRkk72sdQAJJVRZ1sJfgXXwE247Nkk,67298
61
61
  copyparty/web/browser2.html,sha256=ciQlgr9GWuIapdsRBFNRvRFvN5T_5n920LqDMbsj5-g,1605
62
62
  copyparty/web/cf.html,sha256=lJThtNFNAQT1ClCHHlivAkDGE0LutedwopXD62Z8Nys,589
63
63
  copyparty/web/dbg-audio.js.gz,sha256=Ma-KZtK8LnmiwNvNKFKXMPYl_Nn_3U7GsJ6-DRWC2HE,688
@@ -71,14 +71,14 @@ copyparty/web/mde.html,sha256=FMMq4ySXoOrQV5E836KmQCry3COOhMu0DSstAdJZL_g,1678
71
71
  copyparty/web/mde.js.gz,sha256=kN2eUSvr4mFuksfK4-4LimJmWdwsao39Sea2lWtu8L0,2224
72
72
  copyparty/web/msg.css.gz,sha256=u90fXYAVrMD-jqwf5XFVC1ptSpSHZUe8Mez6PX101P8,300
73
73
  copyparty/web/msg.html,sha256=XDg51WLO7RruZnoFnKpeJ33k47-tBHP3bR7l55Jwre4,896
74
- copyparty/web/splash.css.gz,sha256=1IV-0cAs-RNCnvHu-wbSVzKMCkHIblManOLB8d3xcqk,949
75
- copyparty/web/splash.html,sha256=KFAvTnofyVURBQyTnrYwuDdEKN_iGtvdjicn5b33tL8,3822
74
+ copyparty/web/splash.css.gz,sha256=zgDs-SY3VrInsXeARRPcGHziVOUs-1hUtSObzybwD1g,1006
75
+ copyparty/web/splash.html,sha256=mPhMBTO3BMaie5lGJGloS6b8HhoujUzDZYAosfDX8fg,3846
76
76
  copyparty/web/splash.js.gz,sha256=2R8UYlAN8WpIABg8clgWckWqgD8nKtz3eGZFu2y1g88,1420
77
77
  copyparty/web/svcs.html,sha256=s7vUSrCrELC3iTemksodRBhQpssO7s4xW1vA-CX6vU8,11702
78
78
  copyparty/web/svcs.js.gz,sha256=k81ZvZ3I-f4fMHKrNGGOgOlvXnCBz0mVjD-8mieoWCA,520
79
79
  copyparty/web/ui.css.gz,sha256=skuzZHqTU0ag5hButpQmKI9wM7ro-UJ2PnpTodTWYF4,2616
80
80
  copyparty/web/up2k.js.gz,sha256=ZuxLQW8mJSvLu_Aa8fDT3F9rptuAzNDmaOLd0MeMrd8,22114
81
- copyparty/web/util.js.gz,sha256=Ag3zWWzbHoWYQtRnn8frhl3PcUzTIjSOUQiSxQWp1M8,14330
81
+ copyparty/web/util.js.gz,sha256=3Ys57MotfGguhuCdDhj3afyX8wlz3ZgG5ZrnY4_Zqcw,14377
82
82
  copyparty/web/w.hash.js.gz,sha256=__hBMd5oZWfTrb8ZCJNT21isoSqyrxKE6qdaKGQVAhc,1060
83
83
  copyparty/web/a/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
84
84
  copyparty/web/a/partyfuse.py,sha256=MuRkaSuYsdfWfBFMOkbPwDXqSvNTw3sd7QhhlKCDZ8I,32311
@@ -102,9 +102,9 @@ copyparty/web/deps/prismd.css.gz,sha256=ObUlksQVr-OuYlTz-I4B23TeBg2QDVVGRnWBz8cV
102
102
  copyparty/web/deps/scp.woff2,sha256=w99BDU5i8MukkMEL-iW0YO9H4vFFZSPWxbkH70ytaAg,8612
103
103
  copyparty/web/deps/sha512.ac.js.gz,sha256=lFZaCLumgWxrvEuDr4bqdKHsqjX82AbVAb7_F45Yk88,7033
104
104
  copyparty/web/deps/sha512.hw.js.gz,sha256=vqoXeracj-99Z5MfY3jK2N4WiSzYQdfjy0RnUlQDhSU,8110
105
- copyparty-1.12.0.dist-info/LICENSE,sha256=gOr4h33pCsBEg9uIy9AYmb7qlocL4V9t2uPJS5wllr0,1072
106
- copyparty-1.12.0.dist-info/METADATA,sha256=aJEMFtvG-b_ofuoUiX9c9oD8ilOhsZyafcf7eeGpfAU,117598
107
- copyparty-1.12.0.dist-info/WHEEL,sha256=GJ7t_kWBFywbagK5eo9IoUwLW6oyOeTKmQ-9iHFVNxQ,92
108
- copyparty-1.12.0.dist-info/entry_points.txt,sha256=4zw6a3rqASywQomiYLObjjlxybaI65LYYOTJwgKz7b0,128
109
- copyparty-1.12.0.dist-info/top_level.txt,sha256=LnYUPsDyk-8kFgM6YJLG4h820DQekn81cObKSu9g-sI,10
110
- copyparty-1.12.0.dist-info/RECORD,,
105
+ copyparty-1.12.2.dist-info/LICENSE,sha256=gOr4h33pCsBEg9uIy9AYmb7qlocL4V9t2uPJS5wllr0,1072
106
+ copyparty-1.12.2.dist-info/METADATA,sha256=CXx9dAVjA9andahLVjyqMzqKeOVzLch9fj3D5GfyQP0,118373
107
+ copyparty-1.12.2.dist-info/WHEEL,sha256=GJ7t_kWBFywbagK5eo9IoUwLW6oyOeTKmQ-9iHFVNxQ,92
108
+ copyparty-1.12.2.dist-info/entry_points.txt,sha256=4zw6a3rqASywQomiYLObjjlxybaI65LYYOTJwgKz7b0,128
109
+ copyparty-1.12.2.dist-info/top_level.txt,sha256=LnYUPsDyk-8kFgM6YJLG4h820DQekn81cObKSu9g-sI,10
110
+ copyparty-1.12.2.dist-info/RECORD,,