copyparty 1.13.8__py3-none-any.whl → 1.14.0__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/up2k.py CHANGED
@@ -451,11 +451,16 @@ class Up2k(object):
451
451
  cooldown = now + 3
452
452
  # self.log("SR", 5)
453
453
 
454
- if self.args.no_lifetime:
454
+ if self.args.no_lifetime and not self.args.shr:
455
455
  timeout = now + 9001
456
456
  else:
457
457
  # important; not deferred by db_act
458
458
  timeout = self._check_lifetimes()
459
+ try:
460
+ timeout = min(self._check_shares(), timeout)
461
+ except Exception as ex:
462
+ t = "could not check for expiring shares: %r"
463
+ self.log(t % (ex,), 1)
459
464
 
460
465
  try:
461
466
  timeout = min(timeout, now + self._check_xiu())
@@ -558,6 +563,34 @@ class Up2k(object):
558
563
 
559
564
  return timeout
560
565
 
566
+ def _check_shares(self) :
567
+ assert sqlite3 # type: ignore
568
+
569
+ now = time.time()
570
+ timeout = now + 9001
571
+
572
+ db = sqlite3.connect(self.args.shr_db, timeout=2)
573
+ cur = db.cursor()
574
+
575
+ q = "select k from sh where t1 and t1 <= ?"
576
+ rm = [x[0] for x in cur.execute(q, (now,))]
577
+ if rm:
578
+ self.log("forgetting expired shares %s" % (rm,))
579
+ q = "delete from sh where k=?"
580
+ cur.executemany(q, [(x,) for x in rm])
581
+ db.commit()
582
+ Daemon(self.hub._reload_blocking, "sharedrop", (False, False))
583
+
584
+ q = "select min(t1) from sh where t1 > 1"
585
+ (earliest,) = cur.execute(q).fetchone()
586
+ if earliest:
587
+ timeout = earliest - now
588
+
589
+ cur.close()
590
+ db.close()
591
+
592
+ return timeout
593
+
561
594
  def _check_xiu(self) :
562
595
  if self.xiu_busy:
563
596
  return 2
@@ -2532,6 +2565,10 @@ class Up2k(object):
2532
2565
 
2533
2566
  cur.connection.commit()
2534
2567
 
2568
+ def wake_rescanner(self):
2569
+ with self.rescan_cond:
2570
+ self.rescan_cond.notify_all()
2571
+
2535
2572
  def handle_json(
2536
2573
  self, cj , busy_aps
2537
2574
  ) :
@@ -2561,7 +2598,10 @@ class Up2k(object):
2561
2598
 
2562
2599
  return ret
2563
2600
 
2564
- def _handle_json(self, cj ) :
2601
+ def _handle_json(self, cj , depth = 1) :
2602
+ if depth > 16:
2603
+ raise Pebkac(500, "too many xbu relocs, giving up")
2604
+
2565
2605
  ptop = cj["ptop"]
2566
2606
  if not self.register_vpath(ptop, cj["vcfg"]):
2567
2607
  if ptop not in self.registry:
@@ -2754,7 +2794,8 @@ class Up2k(object):
2754
2794
  job = deepcopy(job)
2755
2795
  job["wark"] = wark
2756
2796
  job["at"] = cj.get("at") or time.time()
2757
- for k in "lmod ptop vtop prel name host user addr".split():
2797
+ zs = "lmod ptop vtop prel name host user addr poke"
2798
+ for k in zs.split():
2758
2799
  job[k] = cj.get(k) or ""
2759
2800
 
2760
2801
  pdir = djoin(cj["ptop"], cj["prel"])
@@ -2791,12 +2832,18 @@ class Up2k(object):
2791
2832
  if hr.get("reloc"):
2792
2833
  x = pathmod(self.asrv.vfs, dst, vp, hr["reloc"])
2793
2834
  if x:
2835
+ zvfs = vfs
2794
2836
  pdir, _, job["name"], (vfs, rem) = x
2795
2837
  dst = os.path.join(pdir, job["name"])
2838
+ job["vcfg"] = vfs.flags
2796
2839
  job["ptop"] = vfs.realpath
2797
2840
  job["vtop"] = vfs.vpath
2798
2841
  job["prel"] = rem
2799
- bos.makedirs(pdir)
2842
+ if zvfs.vpath != vfs.vpath:
2843
+ # print(json.dumps(job, sort_keys=True, indent=4))
2844
+ job["hash"] = cj["hash"]
2845
+ self.log("xbu reloc1:%d..." % (depth,), 6)
2846
+ return self._handle_json(job, depth + 1)
2800
2847
 
2801
2848
  job["name"] = self._untaken(pdir, job, now)
2802
2849
 
@@ -2877,7 +2924,9 @@ class Up2k(object):
2877
2924
  lut.add(k)
2878
2925
 
2879
2926
  try:
2880
- self._new_upload(job)
2927
+ ret = self._new_upload(job, vfs, depth)
2928
+ if ret:
2929
+ return ret # xbu recursed
2881
2930
  except:
2882
2931
  self.registry[job["ptop"]].pop(job["wark"], None)
2883
2932
  raise
@@ -4173,22 +4222,17 @@ class Up2k(object):
4173
4222
 
4174
4223
  return ret
4175
4224
 
4176
- def _new_upload(self, job ) :
4225
+ def _new_upload(self, job , vfs , depth ) :
4177
4226
  pdir = djoin(job["ptop"], job["prel"])
4178
4227
  if not job["size"]:
4179
4228
  try:
4180
4229
  inf = bos.stat(djoin(pdir, job["name"]))
4181
4230
  if stat.S_ISREG(inf.st_mode):
4182
4231
  job["lmod"] = inf.st_size
4183
- return
4232
+ return {}
4184
4233
  except:
4185
4234
  pass
4186
4235
 
4187
- self.registry[job["ptop"]][job["wark"]] = job
4188
- job["name"] = self._untaken(pdir, job, job["t0"])
4189
- # if len(job["name"].split(".")) > 8:
4190
- # raise Exception("aaa")
4191
-
4192
4236
  xbu = self.flags[job["ptop"]].get("xbu")
4193
4237
  ap_chk = djoin(pdir, job["name"])
4194
4238
  vp_chk = djoin(job["vtop"], job["prel"], job["name"])
@@ -4217,10 +4261,18 @@ class Up2k(object):
4217
4261
  if hr.get("reloc"):
4218
4262
  x = pathmod(self.asrv.vfs, ap_chk, vp_chk, hr["reloc"])
4219
4263
  if x:
4264
+ zvfs = vfs
4220
4265
  pdir, _, job["name"], (vfs, rem) = x
4266
+ job["vcfg"] = vfs.flags
4221
4267
  job["ptop"] = vfs.realpath
4222
4268
  job["vtop"] = vfs.vpath
4223
4269
  job["prel"] = rem
4270
+ if zvfs.vpath != vfs.vpath:
4271
+ self.log("xbu reloc2:%d..." % (depth,), 6)
4272
+ return self._handle_json(job, depth + 1)
4273
+
4274
+ job["name"] = self._untaken(pdir, job, job["t0"])
4275
+ self.registry[job["ptop"]][job["wark"]] = job
4224
4276
 
4225
4277
  tnam = job["name"] + ".PARTIAL"
4226
4278
  if self.args.dotpart:
@@ -4230,7 +4282,7 @@ class Up2k(object):
4230
4282
  job["tnam"] = tnam
4231
4283
  if not job["hash"]:
4232
4284
  del self.registry[job["ptop"]][job["wark"]]
4233
- return
4285
+ return {}
4234
4286
 
4235
4287
  if self.args.plain_ip:
4236
4288
  dip = job["addr"].replace(":", ".")
@@ -4290,6 +4342,8 @@ class Up2k(object):
4290
4342
  if not job["hash"]:
4291
4343
  self._finish_upload(job["ptop"], job["wark"])
4292
4344
 
4345
+ return {}
4346
+
4293
4347
  def _snapshot(self) :
4294
4348
  slp = self.args.snap_wri
4295
4349
  if not slp or self.args.no_snap:
copyparty/util.py CHANGED
@@ -1739,7 +1739,7 @@ def read_header(sr , t_idle , t_tot ) :
1739
1739
 
1740
1740
  ofs = ret.find(b"\r\n\r\n")
1741
1741
  if ofs < 0:
1742
- if len(ret) > 1024 * 64:
1742
+ if len(ret) > 1024 * 32:
1743
1743
  raise Pebkac(400, "header 2big")
1744
1744
  else:
1745
1745
  continue
Binary file
@@ -67,14 +67,14 @@
67
67
  <div id="op_up2k" class="opview"></div>
68
68
 
69
69
  <div id="op_cfg" class="opview opbox opwide"></div>
70
-
70
+
71
71
  <h1 id="path">
72
72
  <a href="#" id="entree">🌲</a>
73
73
  {%- for n in vpnodes %}
74
74
  <a href="{{ r }}/{{ n[0] }}">{{ n[1] }}</a>
75
75
  {%- endfor %}
76
76
  </h1>
77
-
77
+
78
78
  <div id="tree"></div>
79
79
 
80
80
  <div id="wrap">
@@ -118,11 +118,11 @@
118
118
 
119
119
  </tbody>
120
120
  </table>
121
-
121
+
122
122
  <div id="epi" class="logue">{{ "" if sb_lg else logues[1] }}</div>
123
123
 
124
124
  <h2 id="wfp"><a href="{{ r }}/?h" id="goh">control-panel</a></h2>
125
-
125
+
126
126
  <a href="#" id="repl">π</a>
127
127
 
128
128
  </div>
Binary file
@@ -51,11 +51,11 @@
51
51
 
52
52
  </tbody>
53
53
  </table>
54
-
54
+
55
55
  {%- if logues[1] %}
56
56
  <div>{{ logues[1] }}</div><br />
57
57
  {%- endif %}
58
-
58
+
59
59
  <h2><a href="{{ r }}/{{ url_suf }}{{ url_suf and '&amp;' or '?' }}h">control-panel</a></h2>
60
60
 
61
61
  </body>
copyparty/web/md.html CHANGED
@@ -49,7 +49,7 @@
49
49
  <div id="mp" class="mdo"></div>
50
50
  </div>
51
51
  <a href="#" id="repl">π</a>
52
-
52
+
53
53
  {%- if edit %}
54
54
  <div id="helpbox">
55
55
  <textarea autocomplete="off">
@@ -125,7 +125,7 @@ write markdown (most html is 🙆 too)
125
125
  </textarea>
126
126
  </div>
127
127
  {%- endif %}
128
-
128
+
129
129
  <script>
130
130
 
131
131
  var SR = {{ r|tojson }},
Binary file
@@ -0,0 +1,74 @@
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+
4
+ <head>
5
+ <meta charset="utf-8">
6
+ <title>{{ s_doctitle }}</title>
7
+ <meta http-equiv="X-UA-Compatible" content="IE=edge">
8
+ <meta name="viewport" content="width=device-width, initial-scale=0.8">
9
+ <meta name="theme-color" content="#{{ tcolor }}">
10
+ <link rel="stylesheet" media="screen" href="{{ r }}/.cpr/shares.css?_={{ ts }}">
11
+ <link rel="stylesheet" media="screen" href="{{ r }}/.cpr/ui.css?_={{ ts }}">
12
+ {{ html_head }}
13
+ </head>
14
+
15
+ <body>
16
+ <div id="wrap">
17
+ <a id="a" href="{{ r }}/?shares" class="af">refresh</a>
18
+ <a id="a" href="{{ r }}/?h" class="af">controlpanel</a>
19
+
20
+ <span>axs = perms (read,write,move,delet)</span>
21
+ <span>st 1=file 2=dir</span>
22
+ <span>min/hrs = time left</span>
23
+
24
+ <table><tr>
25
+ <th>delete</th>
26
+ <th>sharekey</th>
27
+ <th>pw</th>
28
+ <th>source</th>
29
+ <th>axs</th>
30
+ <th>st</th>
31
+ <th>user</th>
32
+ <th>created</th>
33
+ <th>expires</th>
34
+ <th>min</th>
35
+ <th>hrs</th>
36
+ </tr>
37
+ {% for k, pw, vp, pr, st, un, t0, t1 in rows %}
38
+ <tr>
39
+ <td><a href="#" k="{{ k }}">delete</a></td>
40
+ <td><a href="{{ r }}{{ shr }}{{ k }}">{{ k }}</a></td>
41
+ <td>{{ pw }}</td>
42
+ <td><a href="{{ r }}/{{ vp|e }}">{{ vp|e }}</a></td>
43
+ <td>{{ pr }}</td>
44
+ <td>{{ st }}</td>
45
+ <td>{{ un|e }}</td>
46
+ <td>{{ t0 }}</td>
47
+ <td>{{ t1 }}</td>
48
+ <td>{{ (t1 - now) // 60 if t1 else "never" }}</td>
49
+ <td>{{ (t1 - now) // 3600 if t1 else "never" }}</td>
50
+ </tr>
51
+ {% endfor %}
52
+ </table>
53
+ {% if not rows %}
54
+ (you don't have any active shares btw)
55
+ {% endif %}
56
+ <script>
57
+
58
+ var SR = {{ r|tojson }},
59
+ shr="{{ shr }}",
60
+ lang="{{ lang }}",
61
+ dfavico="{{ favico }}";
62
+
63
+ var STG = window.localStorage;
64
+ document.documentElement.className = (STG && STG.cpp_thm) || "{{ this.args.theme }}";
65
+
66
+ </script>
67
+ <script src="{{ r }}/.cpr/util.js?_={{ ts }}"></script>
68
+ <script src="{{ r }}/.cpr/shares.js?_={{ ts }}"></script>
69
+ {%- if js %}
70
+ <script src="{{ js }}_={{ ts }}"></script>
71
+ {%- endif %}
72
+ </body>
73
+ </html>
74
+
Binary file
Binary file
copyparty/web/splash.html CHANGED
@@ -21,7 +21,7 @@
21
21
  <p id="b">howdy stranger &nbsp; <small>(you're not logged in)</small></p>
22
22
  {%- else %}
23
23
  <a id="c" href="{{ r }}/?pw=x" class="logout">logout</a>
24
- <p><span id="m">welcome back,</span> <strong>{{ this.uname }}</strong></p>
24
+ <p><span id="m">welcome back,</span> <strong>{{ this.uname|e }}</strong></p>
25
25
  {%- endif %}
26
26
 
27
27
  {%- if msg %}
@@ -76,8 +76,12 @@
76
76
  </ul>
77
77
  {%- endif %}
78
78
 
79
- <h1 id="cc">client config:</h1>
79
+ <h1 id="cc">other stuff:</h1>
80
80
  <ul>
81
+ {%- if this.uname != '*' and this.args.shr %}
82
+ <li><a id="y" href="{{ r }}/?shares">edit shares</a></li>
83
+ {% endif %}
84
+
81
85
  {% if k304 or k304vis %}
82
86
  {% if k304 %}
83
87
  <li><a id="h" href="{{ r }}/?k304=n">disable k304</a> (currently enabled)
@@ -92,11 +96,14 @@
92
96
 
93
97
  <h1 id="l">login for more:</h1>
94
98
  <div>
95
- <form method="post" enctype="multipart/form-data" action="{{ r }}/{{ qvpath }}">
96
- <input type="hidden" name="act" value="login" />
97
- <input type="password" name="cppwd" placeholder=" password" />
99
+ <form id="lf" method="post" enctype="multipart/form-data" action="{{ r }}/{{ qvpath }}">
100
+ <input type="hidden" id="la" name="act" value="login" />
101
+ <input type="password" id="lp" name="cppwd" placeholder=" password" />
98
102
  <input type="hidden" name="uhash" id="uhash" value="x" />
99
- <input type="submit" value="Login" />
103
+ <input type="submit" id="ls" value="Login" />
104
+ {% if chpw %}
105
+ <a id="x" href="#">change password</a>
106
+ {% endif %}
100
107
  {% if ahttps %}
101
108
  <a id="w" href="{{ ahttps }}">switch to https</a>
102
109
  {% endif %}
Binary file
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.13.8
3
+ Version: 1.14.0
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
@@ -96,6 +96,7 @@ turn almost any device into a file server with resumable uploads/downloads using
96
96
  * [self-destruct](#self-destruct) - uploads can be given a lifetime
97
97
  * [race the beam](#race-the-beam) - download files while they're still uploading ([demo video](http://a.ocv.me/pub/g/nerd-stuff/cpp/2024-0418-race-the-beam.webm))
98
98
  * [file manager](#file-manager) - cut/paste, rename, and delete files/folders (if you have permission)
99
+ * [shares](#shares) - share a file or folder by creating a temporary link
99
100
  * [batch rename](#batch-rename) - select some files and press `F2` to bring up the rename UI
100
101
  * [media player](#media-player) - plays almost every audio format there is
101
102
  * [audio equalizer](#audio-equalizer) - and [dynamic range compressor](https://en.wikipedia.org/wiki/Dynamic_range_compression)
@@ -130,6 +131,7 @@ turn almost any device into a file server with resumable uploads/downloads using
130
131
  * [upload events](#upload-events) - the older, more powerful approach ([examples](./bin/mtag/))
131
132
  * [handlers](#handlers) - redefine behavior with plugins ([examples](./bin/handlers/))
132
133
  * [identity providers](#identity-providers) - replace copyparty passwords with oauth and such
134
+ * [user-changeable passwords](#user-changeable-passwords) - if permitted, users can change their own passwords
133
135
  * [using the cloud as storage](#using-the-cloud-as-storage) - connecting to an aws s3 bucket and similar
134
136
  * [hiding from google](#hiding-from-google) - tell search engines you dont wanna be indexed
135
137
  * [themes](#themes)
@@ -798,6 +800,33 @@ file selection: click somewhere on the line (not the link itsef), then:
798
800
  you can move files across browser tabs (cut in one tab, paste in another)
799
801
 
800
802
 
803
+ ## shares
804
+
805
+ share a file or folder by creating a temporary link
806
+
807
+ when enabled in the server settings (`--shr`), click the bottom-right `share` button to share the folder you're currently in, or select a file first to share only that file
808
+
809
+ this feature was made with [identity providers](#identity-providers) in mind -- configure your reverseproxy to skip the IdP's access-control for a given URL prefix and use that to safely share specific files/folders sans the usual auth checks
810
+
811
+ when creating a share, the creator can choose any of the following options:
812
+
813
+ * password-protection
814
+ * expire after a certain time
815
+ * allow visitors to upload (if the user who creates the share has write-access)
816
+
817
+ semi-intentional limitations:
818
+
819
+ * cleanup of expired shares only works when global option `e2d` is set, and/or at least one volume on the server has volflag `e2d`
820
+ * 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
821
+ * no option to "delete after first access" because tricky
822
+ * when linking something to discord (for example) it'll get accessed by their scraper and that would count as a hit
823
+ * browsers wouldn't be able to resume a broken download unless the requester's IP gets allowlisted for X minutes (ref. tricky)
824
+
825
+ the links are created inside a specific toplevel folder which must be specified with server-config `--shr`, for example `--shr /share/` (this also enables the feature)
826
+
827
+ users can delete their own shares in the controlpanel, and a list of privileged users (`--shr-adm`) are allowed to see and/or delet any share on the server
828
+
829
+
801
830
  ## batch rename
802
831
 
803
832
  select some files and press `F2` to bring up the rename UI
@@ -1409,6 +1438,29 @@ there is a [docker-compose example](./docs/examples/docker/idp-authelia-traefik)
1409
1438
 
1410
1439
  a more complete example of the copyparty configuration options [look like this](./docs/examples/docker/idp/copyparty.conf)
1411
1440
 
1441
+ but if you just want to let users change their own passwords, then you probably want [user-changeable passwords](#user-changeable-passwords) instead
1442
+
1443
+
1444
+ ## user-changeable passwords
1445
+
1446
+ if permitted, users can change their own passwords in the control-panel
1447
+
1448
+ * not compatible with [identity providers](#identity-providers)
1449
+
1450
+ * must be enabled with `--chpw` because account-sharing is a popular usecase
1451
+
1452
+ * if you want to enable the feature but deny password-changing for a specific list of accounts, you can do that with `--chpw-no name1,name2,name3,...`
1453
+
1454
+ * to perform a password reset, edit the server config and give the user another password there, then do a [config reload](#server-config) or server restart
1455
+
1456
+ * the custom passwords are kept in a textfile at filesystem-path `--chpw-db`, by default `chpw.json` in the copyparty config folder
1457
+
1458
+ * if you run multiple copyparty instances with different users you *almost definitely* want to specify separate DBs for each instance
1459
+
1460
+ * if [password hashing](#password-hashing) is enbled, the passwords in the db are also hashed
1461
+
1462
+ * ...which means that all user-defined passwords will be forgotten if you change password-hashing settings
1463
+
1412
1464
 
1413
1465
  ## using the cloud as storage
1414
1466
 
@@ -1513,7 +1565,7 @@ some reverse proxies (such as [Caddy](https://caddyserver.com/)) can automatical
1513
1565
  * **warning:** nginx-QUIC (HTTP/3) is still experimental and can make uploads much slower, so HTTP/1.1 is recommended for now
1514
1566
  * depending on server/client, HTTP/1.1 can also be 5x faster than HTTP/2
1515
1567
 
1516
- for improved security (and a tiny performance boost) consider listening on a unix-socket with `-i /tmp/party.sock` instead of `-i 127.0.0.1`
1568
+ for improved security (and a 10% performance boost) consider listening on a unix-socket with `-i unix:770:www:/tmp/party.sock` (permission `770` means only members of group `www` can access it)
1517
1569
 
1518
1570
  example webserver configs:
1519
1571
 
@@ -1954,7 +2006,7 @@ some notes on hardening
1954
2006
  * cors doesn't work right otherwise
1955
2007
  * if you allow anonymous uploads or otherwise don't trust the contents of a volume, you can prevent XSS with volflag `nohtml`
1956
2008
  * this returns html documents as plaintext, and also disables markdown rendering
1957
- * when running behind a reverse-proxy, listen on a unix-socket with `-i /tmp/party.sock` instead of `-i 127.0.0.1` for tighter access control (plus you get a tiny performance boost for free)
2009
+ * when running behind a reverse-proxy, listen on a unix-socket for tighter access control (and more performance); see [reverse-proxy](#reverse-proxy) or `--help-bind`
1958
2010
 
1959
2011
  safety profiles:
1960
2012
 
@@ -1,7 +1,7 @@
1
1
  copyparty/__init__.py,sha256=fUINM1abqDGzCCH_JcXdOnLdKOV-SrTI2Xo2QgQW2P4,1703
2
- copyparty/__main__.py,sha256=-bNgNkASImj8_qwQybMROWYOG8weMhW_97CvSrk493E,104553
3
- copyparty/__version__.py,sha256=uHkZa2-eQGLrrdaXQTTJQo_ykRJ6argjaKoQORnBprc,255
4
- copyparty/authsrv.py,sha256=TQSpXc2meEcC4FTkHfLYaF0JwR6subinZTlGrhItTLM,87266
2
+ copyparty/__main__.py,sha256=JBSVuRhMEnI_LMdRe5VLs09Li7WRJFcLlYGStcu0F90,107832
3
+ copyparty/__version__.py,sha256=WaooTD72_XSmTadut-eIUgjzkuntfRYhU0umcNxzvXw,258
4
+ copyparty/authsrv.py,sha256=5LEz9yBB4PGEgbVsnJne-XevAsHbolFP-yfanOsDsUs,94305
5
5
  copyparty/broker_mp.py,sha256=YFe1S6Zziht8Qc__dCLj_ff8z0DDny9lqk_Mi5ajsJk,3868
6
6
  copyparty/broker_mpw.py,sha256=4ZI7bJYOwUibeAJVv9_FPGNmHrr9eOtkj_Kz0JEppTU,3197
7
7
  copyparty/broker_thr.py,sha256=eKr--HJGig5zqvNGwH9UoBG9Nvi9mT2axrRmJwknd0s,1759
@@ -11,9 +11,9 @@ copyparty/cfg.py,sha256=i8-bjWgbguQooxiA172RcptqR_SEOwDHJ4cqldrZ8oQ,9792
11
11
  copyparty/dxml.py,sha256=lZpg-kn-kQsXRtNY1n6fRaS-b7uXzMCyv8ovKnhZcZc,1548
12
12
  copyparty/fsutil.py,sha256=hnEHgySI43-XJJKbI8n6t1A6oVHzR_nYdsBcAwtreBk,4610
13
13
  copyparty/ftpd.py,sha256=1vD-KTy07xfEEEk1dx37pUYModpNO2gIhVXvFUr205M,17497
14
- copyparty/httpcli.py,sha256=9tUh7S7NMWnopK7gW6ciC8RmjozruLilJ7AFJhECVw8,174999
14
+ copyparty/httpcli.py,sha256=xk8ZjiZkb3Cko-_A95bgFgm68rpHrmASLwqRmlOss1U,180620
15
15
  copyparty/httpconn.py,sha256=mwIDup85cBowIfJOse8rla5bqTz7nf-ChgfR-5-V0JM,6938
16
- copyparty/httpsrv.py,sha256=a3paDKN_eq0-vDfJ1Vqi2Ta_MNK3HRDn8XwpDW69jgU,17104
16
+ copyparty/httpsrv.py,sha256=8_1Ivg3eco7HJDjqL_rUB58IOUaUnoXGhO62bOMXLBk,17242
17
17
  copyparty/ico.py,sha256=eWSxEae4wOCfheHl-m-wchYvFRAR_97kJDb4NGaB-Z8,3561
18
18
  copyparty/mdns.py,sha256=vC078llnL1v0pvL3mnwacuStFHPJUQuxo9Opj-IbHL4,18155
19
19
  copyparty/metrics.py,sha256=O8qiPNDxNjub_PI8C8Qu9rBQ_z0J1mnKonqkcTeAtf4,8845
@@ -24,15 +24,15 @@ copyparty/smbd.py,sha256=8zkC9BjVtGiKXMLajbdakxoKeFzACdM75SW0_SvqXJA,14490
24
24
  copyparty/ssdp.py,sha256=8iyF5sqIjATJLWcAtnJa8eadHosOn0CP4ywltzJ7bVY,7023
25
25
  copyparty/star.py,sha256=tV5BbX6AiQ7N4UU8DYtSTckNYeoeey4DBqq4LjfymbY,3818
26
26
  copyparty/sutil.py,sha256=JTMrQwcWH85hXB_cKG206eDZ967WZDGaP00AWvl_gB0,3214
27
- copyparty/svchub.py,sha256=r7tht72fjl4HrrScTgXrIKGJHIzaB9pmnXSIs6c7wxA,34952
27
+ copyparty/svchub.py,sha256=eAvlDGhKAXUYxAHd03lHY-iNat32Bbt1rZHZwF46Kzg,37367
28
28
  copyparty/szip.py,sha256=tor4yjdHhEL4Ox-Xg7-cuUFrMO0IwQD29aRX5Cp8MYs,8605
29
- copyparty/tcpsrv.py,sha256=_K4ftXPmOANXA6CdD0wVLFb5XPKJTEIwy3qctI8gEhc,19297
29
+ copyparty/tcpsrv.py,sha256=jM_Za64O8LEMfMrU4irJluIJZrU494e2b759r_KhaUQ,19881
30
30
  copyparty/tftpd.py,sha256=i1-oZ05DJq2_nDOW3g3PfTkMoUCr2lAcDYFMWArwtKA,13568
31
31
  copyparty/th_cli.py,sha256=o6FMkerYvAXS455z3DUossVztu_nzFlYSQhs6qN6Jt8,4636
32
32
  copyparty/th_srv.py,sha256=27IftjIXUQzRRiUytt-CgXkybEoP3HHHoXaDAvxEmLo,29217
33
- copyparty/u2idx.py,sha256=NSlY-3Wo-jjzkOWNjnrKXf40LlTCssiy7j5iP2UoUXA,13082
34
- copyparty/up2k.py,sha256=6WR2mwFSMrCMLp2WbkvwcsVWBr9OnrSMkhJT5odStC0,150956
35
- copyparty/util.py,sha256=ftOsJD9ofoZGywvNT5xgT8t33E9CPYVDbENz9JSWwe4,88625
33
+ copyparty/u2idx.py,sha256=t4mzjj2GDrkjIHt0RM68y1EgT5qOBoz6mkYgjMbqA38,13526
34
+ copyparty/up2k.py,sha256=YclDPGVM_DvRXvZya8mtr2XBzYdBsUM5Ox41X-p0PaI,153007
35
+ copyparty/util.py,sha256=S7FuQBPbl2FX7ULIH9VNgiB7Z_rceqTJssXz4SGErwA,88625
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,14 +55,14 @@ 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=4dS8-r4si84ca71l98672ahnRI86Aq95MU-bc5knykk,7962
58
- copyparty/web/browser.css.gz,sha256=Pm5mArar_T87v9ji1SMkWEHzeKRtYq2roV_bAxXMIP0,11525
59
- copyparty/web/browser.html,sha256=-tLasq2GKe9mUceqXG4PczQ7odBMrX0qlWuyaA9SjPI,4882
60
- copyparty/web/browser.js.gz,sha256=-FlIylCcVX7aQvOInLDdSNZAqsVzs6RKczzvNBSFQ50,69593
61
- copyparty/web/browser2.html,sha256=XU8fD9fFbS4koraRz1Ok4z9OEV5EBoH4vT2Vc1mNWPc,1589
58
+ copyparty/web/browser.css.gz,sha256=tE4SKTvB2l6t91Mb_bhadKbV0QMLrYbAcVE-JQ7MPUk,11494
59
+ copyparty/web/browser.html,sha256=vvfWiu_aOFRar8u5lridMRKQSPF4R0YkA41zrsh82Qs,4878
60
+ copyparty/web/browser.js.gz,sha256=lF2coe19rlOIwgDZlcqdnascDjqCJDVzVxtyZopQE2Y,71016
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
64
64
  copyparty/web/md.css.gz,sha256=UZpN0J7ubVM05CZkbZYkQRJeGgJt_GNDEzKTGSQd8h4,2032
65
- copyparty/web/md.html,sha256=PZtHGVQ1mtppfpgqG3qjehu3KnRIs9QPsnv7yUXqB8k,4191
65
+ copyparty/web/md.html,sha256=isNbIzWbp_oqkhQSXm0uf3st3h4uB3LLTXFcHHcvgPQ,4189
66
66
  copyparty/web/md.js.gz,sha256=AHRQ3a-PZq_UiGh4CjNwXRllJCvA0IqqYmeHhFWhCig,4179
67
67
  copyparty/web/md2.css.gz,sha256=uIVHKScThdbcfhXNSHgKZnALYpxbnXC-WuEzOJ20Lpc,699
68
68
  copyparty/web/md2.js.gz,sha256=0fTA3lahQ1iDvJR4Q3W9v8dX5hc5VP8nunTtoDwFySs,8363
@@ -71,14 +71,17 @@ copyparty/web/mde.html,sha256=ImBhQAaEUCke2M85QU_fl4X2XQExRLcEzgCEN8RNe9o,1759
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=w9CM3hkLLGJX9fWEaG4gSbTOPe2GcPqW8BpSCDiFzOI,977
74
- copyparty/web/splash.css.gz,sha256=zgDs-SY3VrInsXeARRPcGHziVOUs-1hUtSObzybwD1g,1006
75
- copyparty/web/splash.html,sha256=noOLEb8NVsFkkWp7njl_KvpUdjOlAFoOam6XW4lnD-Q,3986
76
- copyparty/web/splash.js.gz,sha256=P4BLL_SBqfqWniq_gzUD-opVAkblAPgKDwmfxyfDB7o,1469
74
+ copyparty/web/shares.css.gz,sha256=4OqsDr0aby14LPy61nU6JdEsgDyBw3TMQiClLvOPFds,477
75
+ copyparty/web/shares.html,sha256=sogrhA6HCzG413qSrHar8-RFSocuBxACTWArO_HOP28,2208
76
+ copyparty/web/shares.js.gz,sha256=PYOZ2jjzDTy_g7lali1kozUjUoI-97LsjXxKUzoThiU,319
77
+ copyparty/web/splash.css.gz,sha256=lCleyzwvc5KdkFtuLhImeOeRZKYi_ISiLppCDcmRK7Y,1023
78
+ copyparty/web/splash.html,sha256=FDCcWzO8E_mm_D4EaCWgeMyFSkMTAnGxWwPh9dn1e4Y,4221
79
+ copyparty/web/splash.js.gz,sha256=RUH5mxrYtCAQ4eLsOUfLl0ryHa1f6-kf_I2j8FitMB0,1840
77
80
  copyparty/web/svcs.html,sha256=v0C3cOFWXYlvp3GEifz1Qj0W3MD8JANT3WTON05GZ9o,11797
78
81
  copyparty/web/svcs.js.gz,sha256=k81ZvZ3I-f4fMHKrNGGOgOlvXnCBz0mVjD-8mieoWCA,520
79
82
  copyparty/web/ui.css.gz,sha256=GnR_PxnZGcNs2IJnb5hFffnhlW3cUHkPad3tNIm-7DQ,2637
80
83
  copyparty/web/up2k.js.gz,sha256=KufMtRViAZQo2rVj67iEWbdPxlVeXW85emRYVJoY3aA,22946
81
- copyparty/web/util.js.gz,sha256=uZDsKkwTcEiFv-GTfy-zmArqirjhxGBLKjAhtLvj72s,14524
84
+ copyparty/web/util.js.gz,sha256=9LeqbO0j_Z4pEXH2pl9FxWxv5eG7d-SE997AFGboK74,14682
82
85
  copyparty/web/w.hash.js.gz,sha256=7wP9EZQNXQxwZnCCFUVsi_-6TM9PLZJeZ9krutXRRj8,1060
83
86
  copyparty/web/a/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
84
87
  copyparty/web/a/partyfuse.py,sha256=MuRkaSuYsdfWfBFMOkbPwDXqSvNTw3sd7QhhlKCDZ8I,32311
@@ -102,9 +105,9 @@ copyparty/web/deps/prismd.css.gz,sha256=ObUlksQVr-OuYlTz-I4B23TeBg2QDVVGRnWBz8cV
102
105
  copyparty/web/deps/scp.woff2,sha256=w99BDU5i8MukkMEL-iW0YO9H4vFFZSPWxbkH70ytaAg,8612
103
106
  copyparty/web/deps/sha512.ac.js.gz,sha256=lFZaCLumgWxrvEuDr4bqdKHsqjX82AbVAb7_F45Yk88,7033
104
107
  copyparty/web/deps/sha512.hw.js.gz,sha256=vqoXeracj-99Z5MfY3jK2N4WiSzYQdfjy0RnUlQDhSU,8110
105
- copyparty-1.13.8.dist-info/LICENSE,sha256=gOr4h33pCsBEg9uIy9AYmb7qlocL4V9t2uPJS5wllr0,1072
106
- copyparty-1.13.8.dist-info/METADATA,sha256=CJbOEiTcmpkZ7NV4rEgkmD-8olsizvHlpPRwdWCqT30,127902
107
- copyparty-1.13.8.dist-info/WHEEL,sha256=R0nc6qTxuoLk7ShA2_Y-UWkN8ZdfDBG2B6Eqpz2WXbs,91
108
- copyparty-1.13.8.dist-info/entry_points.txt,sha256=4zw6a3rqASywQomiYLObjjlxybaI65LYYOTJwgKz7b0,128
109
- copyparty-1.13.8.dist-info/top_level.txt,sha256=LnYUPsDyk-8kFgM6YJLG4h820DQekn81cObKSu9g-sI,10
110
- copyparty-1.13.8.dist-info/RECORD,,
108
+ copyparty-1.14.0.dist-info/LICENSE,sha256=gOr4h33pCsBEg9uIy9AYmb7qlocL4V9t2uPJS5wllr0,1072
109
+ copyparty-1.14.0.dist-info/METADATA,sha256=LDXOH7TctyfP7bNEY9BtHEVrU2zk0MPEJdhauMb09TM,130962
110
+ copyparty-1.14.0.dist-info/WHEEL,sha256=HiCZjzuy6Dw0hdX5R3LCFPDmFS4BWl8H-8W39XfmgX4,91
111
+ copyparty-1.14.0.dist-info/entry_points.txt,sha256=4zw6a3rqASywQomiYLObjjlxybaI65LYYOTJwgKz7b0,128
112
+ copyparty-1.14.0.dist-info/top_level.txt,sha256=LnYUPsDyk-8kFgM6YJLG4h820DQekn81cObKSu9g-sI,10
113
+ copyparty-1.14.0.dist-info/RECORD,,
@@ -1,5 +1,5 @@
1
1
  Wheel-Version: 1.0
2
- Generator: setuptools (72.1.0)
2
+ Generator: setuptools (72.2.0)
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
5
5