copyparty 1.13.8__py3-none-any.whl → 1.14.1__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,17 @@ 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
+ if self.args.shr:
461
+ timeout = min(self._check_shares(), timeout)
462
+ except Exception as ex:
463
+ t = "could not check for expiring shares: %r"
464
+ self.log(t % (ex,), 1)
459
465
 
460
466
  try:
461
467
  timeout = min(timeout, now + self._check_xiu())
@@ -558,6 +564,34 @@ class Up2k(object):
558
564
 
559
565
  return timeout
560
566
 
567
+ def _check_shares(self) :
568
+ assert sqlite3 # type: ignore
569
+
570
+ now = time.time()
571
+ timeout = now + 9001
572
+
573
+ db = sqlite3.connect(self.args.shr_db, timeout=2)
574
+ cur = db.cursor()
575
+
576
+ q = "select k from sh where t1 and t1 <= ?"
577
+ rm = [x[0] for x in cur.execute(q, (now,))]
578
+ if rm:
579
+ self.log("forgetting expired shares %s" % (rm,))
580
+ q = "delete from sh where k=?"
581
+ cur.executemany(q, [(x,) for x in rm])
582
+ db.commit()
583
+ Daemon(self.hub._reload_blocking, "sharedrop", (False, False))
584
+
585
+ q = "select min(t1) from sh where t1 > 1"
586
+ (earliest,) = cur.execute(q).fetchone()
587
+ if earliest:
588
+ timeout = earliest - now
589
+
590
+ cur.close()
591
+ db.close()
592
+
593
+ return timeout
594
+
561
595
  def _check_xiu(self) :
562
596
  if self.xiu_busy:
563
597
  return 2
@@ -2532,6 +2566,10 @@ class Up2k(object):
2532
2566
 
2533
2567
  cur.connection.commit()
2534
2568
 
2569
+ def wake_rescanner(self):
2570
+ with self.rescan_cond:
2571
+ self.rescan_cond.notify_all()
2572
+
2535
2573
  def handle_json(
2536
2574
  self, cj , busy_aps
2537
2575
  ) :
@@ -2561,7 +2599,10 @@ class Up2k(object):
2561
2599
 
2562
2600
  return ret
2563
2601
 
2564
- def _handle_json(self, cj ) :
2602
+ def _handle_json(self, cj , depth = 1) :
2603
+ if depth > 16:
2604
+ raise Pebkac(500, "too many xbu relocs, giving up")
2605
+
2565
2606
  ptop = cj["ptop"]
2566
2607
  if not self.register_vpath(ptop, cj["vcfg"]):
2567
2608
  if ptop not in self.registry:
@@ -2754,7 +2795,8 @@ class Up2k(object):
2754
2795
  job = deepcopy(job)
2755
2796
  job["wark"] = wark
2756
2797
  job["at"] = cj.get("at") or time.time()
2757
- for k in "lmod ptop vtop prel name host user addr".split():
2798
+ zs = "lmod ptop vtop prel name host user addr poke"
2799
+ for k in zs.split():
2758
2800
  job[k] = cj.get(k) or ""
2759
2801
 
2760
2802
  pdir = djoin(cj["ptop"], cj["prel"])
@@ -2791,12 +2833,18 @@ class Up2k(object):
2791
2833
  if hr.get("reloc"):
2792
2834
  x = pathmod(self.asrv.vfs, dst, vp, hr["reloc"])
2793
2835
  if x:
2836
+ zvfs = vfs
2794
2837
  pdir, _, job["name"], (vfs, rem) = x
2795
2838
  dst = os.path.join(pdir, job["name"])
2839
+ job["vcfg"] = vfs.flags
2796
2840
  job["ptop"] = vfs.realpath
2797
2841
  job["vtop"] = vfs.vpath
2798
2842
  job["prel"] = rem
2799
- bos.makedirs(pdir)
2843
+ if zvfs.vpath != vfs.vpath:
2844
+ # print(json.dumps(job, sort_keys=True, indent=4))
2845
+ job["hash"] = cj["hash"]
2846
+ self.log("xbu reloc1:%d..." % (depth,), 6)
2847
+ return self._handle_json(job, depth + 1)
2800
2848
 
2801
2849
  job["name"] = self._untaken(pdir, job, now)
2802
2850
 
@@ -2877,7 +2925,9 @@ class Up2k(object):
2877
2925
  lut.add(k)
2878
2926
 
2879
2927
  try:
2880
- self._new_upload(job)
2928
+ ret = self._new_upload(job, vfs, depth)
2929
+ if ret:
2930
+ return ret # xbu recursed
2881
2931
  except:
2882
2932
  self.registry[job["ptop"]].pop(job["wark"], None)
2883
2933
  raise
@@ -4173,22 +4223,17 @@ class Up2k(object):
4173
4223
 
4174
4224
  return ret
4175
4225
 
4176
- def _new_upload(self, job ) :
4226
+ def _new_upload(self, job , vfs , depth ) :
4177
4227
  pdir = djoin(job["ptop"], job["prel"])
4178
4228
  if not job["size"]:
4179
4229
  try:
4180
4230
  inf = bos.stat(djoin(pdir, job["name"]))
4181
4231
  if stat.S_ISREG(inf.st_mode):
4182
4232
  job["lmod"] = inf.st_size
4183
- return
4233
+ return {}
4184
4234
  except:
4185
4235
  pass
4186
4236
 
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
4237
  xbu = self.flags[job["ptop"]].get("xbu")
4193
4238
  ap_chk = djoin(pdir, job["name"])
4194
4239
  vp_chk = djoin(job["vtop"], job["prel"], job["name"])
@@ -4217,10 +4262,18 @@ class Up2k(object):
4217
4262
  if hr.get("reloc"):
4218
4263
  x = pathmod(self.asrv.vfs, ap_chk, vp_chk, hr["reloc"])
4219
4264
  if x:
4265
+ zvfs = vfs
4220
4266
  pdir, _, job["name"], (vfs, rem) = x
4267
+ job["vcfg"] = vfs.flags
4221
4268
  job["ptop"] = vfs.realpath
4222
4269
  job["vtop"] = vfs.vpath
4223
4270
  job["prel"] = rem
4271
+ if zvfs.vpath != vfs.vpath:
4272
+ self.log("xbu reloc2:%d..." % (depth,), 6)
4273
+ return self._handle_json(job, depth + 1)
4274
+
4275
+ job["name"] = self._untaken(pdir, job, job["t0"])
4276
+ self.registry[job["ptop"]][job["wark"]] = job
4224
4277
 
4225
4278
  tnam = job["name"] + ".PARTIAL"
4226
4279
  if self.args.dotpart:
@@ -4230,7 +4283,7 @@ class Up2k(object):
4230
4283
  job["tnam"] = tnam
4231
4284
  if not job["hash"]:
4232
4285
  del self.registry[job["ptop"]][job["wark"]]
4233
- return
4286
+ return {}
4234
4287
 
4235
4288
  if self.args.plain_ip:
4236
4289
  dip = job["addr"].replace(":", ".")
@@ -4290,6 +4343,8 @@ class Up2k(object):
4290
4343
  if not job["hash"]:
4291
4344
  self._finish_upload(job["ptop"], job["wark"])
4292
4345
 
4346
+ return {}
4347
+
4293
4348
  def _snapshot(self) :
4294
4349
  slp = self.args.snap_wri
4295
4350
  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.1
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=dTu12M9eISQGxeta4ssAuHyXgdmB0G1mXgoIPbzdzt8,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=Ys3tbEm4RW4FLxaFwrdgG7RSsDd0Hr2832I0nCvLtfM,153049
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.1.dist-info/LICENSE,sha256=gOr4h33pCsBEg9uIy9AYmb7qlocL4V9t2uPJS5wllr0,1072
109
+ copyparty-1.14.1.dist-info/METADATA,sha256=AXs4o0mUOTU-WVhn3Kh5QyI-swMa36Rqrk3a4v1Gp38,130962
110
+ copyparty-1.14.1.dist-info/WHEEL,sha256=HiCZjzuy6Dw0hdX5R3LCFPDmFS4BWl8H-8W39XfmgX4,91
111
+ copyparty-1.14.1.dist-info/entry_points.txt,sha256=4zw6a3rqASywQomiYLObjjlxybaI65LYYOTJwgKz7b0,128
112
+ copyparty-1.14.1.dist-info/top_level.txt,sha256=LnYUPsDyk-8kFgM6YJLG4h820DQekn81cObKSu9g-sI,10
113
+ copyparty-1.14.1.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