copyparty 1.16.6__tar.gz → 1.16.7__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (124) hide show
  1. {copyparty-1.16.6 → copyparty-1.16.7}/PKG-INFO +1 -1
  2. {copyparty-1.16.6 → copyparty-1.16.7}/copyparty/__version__.py +2 -2
  3. {copyparty-1.16.6 → copyparty-1.16.7}/copyparty/authsrv.py +2 -2
  4. {copyparty-1.16.6 → copyparty-1.16.7}/copyparty/httpcli.py +77 -31
  5. {copyparty-1.16.6 → copyparty-1.16.7}/copyparty/httpsrv.py +0 -4
  6. {copyparty-1.16.6 → copyparty-1.16.7}/copyparty/tcpsrv.py +3 -3
  7. {copyparty-1.16.6 → copyparty-1.16.7}/copyparty/up2k.py +1 -1
  8. {copyparty-1.16.6 → copyparty-1.16.7}/copyparty/web/a/u2c.py +1 -1
  9. {copyparty-1.16.6 → copyparty-1.16.7}/copyparty/web/browser.html +1 -1
  10. {copyparty-1.16.6 → copyparty-1.16.7}/copyparty/web/browser.js.gz +0 -0
  11. {copyparty-1.16.6 → copyparty-1.16.7}/copyparty/web/md.html +2 -2
  12. {copyparty-1.16.6 → copyparty-1.16.7}/copyparty/web/mde.html +2 -2
  13. copyparty-1.16.7/copyparty/web/rups.css.gz +0 -0
  14. {copyparty-1.16.6 → copyparty-1.16.7}/copyparty/web/rups.html +8 -25
  15. copyparty-1.16.7/copyparty/web/rups.js.gz +0 -0
  16. {copyparty-1.16.6 → copyparty-1.16.7}/copyparty/web/shares.html +4 -3
  17. {copyparty-1.16.6 → copyparty-1.16.7}/copyparty/web/splash.html +1 -1
  18. {copyparty-1.16.6 → copyparty-1.16.7}/copyparty/web/svcs.html +1 -1
  19. {copyparty-1.16.6 → copyparty-1.16.7}/copyparty.egg-info/PKG-INFO +1 -1
  20. copyparty-1.16.6/copyparty/web/rups.css.gz +0 -0
  21. copyparty-1.16.6/copyparty/web/rups.js.gz +0 -0
  22. {copyparty-1.16.6 → copyparty-1.16.7}/LICENSE +0 -0
  23. {copyparty-1.16.6 → copyparty-1.16.7}/README.md +0 -0
  24. {copyparty-1.16.6 → copyparty-1.16.7}/copyparty/__init__.py +0 -0
  25. {copyparty-1.16.6 → copyparty-1.16.7}/copyparty/__main__.py +0 -0
  26. {copyparty-1.16.6 → copyparty-1.16.7}/copyparty/bos/__init__.py +0 -0
  27. {copyparty-1.16.6 → copyparty-1.16.7}/copyparty/bos/bos.py +0 -0
  28. {copyparty-1.16.6 → copyparty-1.16.7}/copyparty/bos/path.py +0 -0
  29. {copyparty-1.16.6 → copyparty-1.16.7}/copyparty/broker_mp.py +0 -0
  30. {copyparty-1.16.6 → copyparty-1.16.7}/copyparty/broker_mpw.py +0 -0
  31. {copyparty-1.16.6 → copyparty-1.16.7}/copyparty/broker_thr.py +0 -0
  32. {copyparty-1.16.6 → copyparty-1.16.7}/copyparty/broker_util.py +0 -0
  33. {copyparty-1.16.6 → copyparty-1.16.7}/copyparty/cert.py +0 -0
  34. {copyparty-1.16.6 → copyparty-1.16.7}/copyparty/cfg.py +0 -0
  35. {copyparty-1.16.6 → copyparty-1.16.7}/copyparty/dxml.py +0 -0
  36. {copyparty-1.16.6 → copyparty-1.16.7}/copyparty/fsutil.py +0 -0
  37. {copyparty-1.16.6 → copyparty-1.16.7}/copyparty/ftpd.py +0 -0
  38. {copyparty-1.16.6 → copyparty-1.16.7}/copyparty/httpconn.py +0 -0
  39. {copyparty-1.16.6 → copyparty-1.16.7}/copyparty/ico.py +0 -0
  40. {copyparty-1.16.6 → copyparty-1.16.7}/copyparty/mdns.py +0 -0
  41. {copyparty-1.16.6 → copyparty-1.16.7}/copyparty/metrics.py +0 -0
  42. {copyparty-1.16.6 → copyparty-1.16.7}/copyparty/mtag.py +0 -0
  43. {copyparty-1.16.6 → copyparty-1.16.7}/copyparty/multicast.py +0 -0
  44. {copyparty-1.16.6 → copyparty-1.16.7}/copyparty/pwhash.py +0 -0
  45. {copyparty-1.16.6 → copyparty-1.16.7}/copyparty/res/COPYING.txt +0 -0
  46. {copyparty-1.16.6 → copyparty-1.16.7}/copyparty/res/__init__.py +0 -0
  47. {copyparty-1.16.6 → copyparty-1.16.7}/copyparty/res/insecure.pem +0 -0
  48. {copyparty-1.16.6 → copyparty-1.16.7}/copyparty/smbd.py +0 -0
  49. {copyparty-1.16.6 → copyparty-1.16.7}/copyparty/ssdp.py +0 -0
  50. {copyparty-1.16.6 → copyparty-1.16.7}/copyparty/star.py +0 -0
  51. {copyparty-1.16.6 → copyparty-1.16.7}/copyparty/stolen/__init__.py +0 -0
  52. {copyparty-1.16.6 → copyparty-1.16.7}/copyparty/stolen/dnslib/__init__.py +0 -0
  53. {copyparty-1.16.6 → copyparty-1.16.7}/copyparty/stolen/dnslib/bimap.py +0 -0
  54. {copyparty-1.16.6 → copyparty-1.16.7}/copyparty/stolen/dnslib/bit.py +0 -0
  55. {copyparty-1.16.6 → copyparty-1.16.7}/copyparty/stolen/dnslib/buffer.py +0 -0
  56. {copyparty-1.16.6 → copyparty-1.16.7}/copyparty/stolen/dnslib/dns.py +0 -0
  57. {copyparty-1.16.6 → copyparty-1.16.7}/copyparty/stolen/dnslib/label.py +0 -0
  58. {copyparty-1.16.6 → copyparty-1.16.7}/copyparty/stolen/dnslib/lex.py +0 -0
  59. {copyparty-1.16.6 → copyparty-1.16.7}/copyparty/stolen/dnslib/ranges.py +0 -0
  60. {copyparty-1.16.6 → copyparty-1.16.7}/copyparty/stolen/ifaddr/__init__.py +0 -0
  61. {copyparty-1.16.6 → copyparty-1.16.7}/copyparty/stolen/ifaddr/_posix.py +0 -0
  62. {copyparty-1.16.6 → copyparty-1.16.7}/copyparty/stolen/ifaddr/_shared.py +0 -0
  63. {copyparty-1.16.6 → copyparty-1.16.7}/copyparty/stolen/ifaddr/_win32.py +0 -0
  64. {copyparty-1.16.6 → copyparty-1.16.7}/copyparty/stolen/qrcodegen.py +0 -0
  65. {copyparty-1.16.6 → copyparty-1.16.7}/copyparty/stolen/surrogateescape.py +0 -0
  66. {copyparty-1.16.6 → copyparty-1.16.7}/copyparty/sutil.py +0 -0
  67. {copyparty-1.16.6 → copyparty-1.16.7}/copyparty/svchub.py +0 -0
  68. {copyparty-1.16.6 → copyparty-1.16.7}/copyparty/szip.py +0 -0
  69. {copyparty-1.16.6 → copyparty-1.16.7}/copyparty/tftpd.py +0 -0
  70. {copyparty-1.16.6 → copyparty-1.16.7}/copyparty/th_cli.py +0 -0
  71. {copyparty-1.16.6 → copyparty-1.16.7}/copyparty/th_srv.py +0 -0
  72. {copyparty-1.16.6 → copyparty-1.16.7}/copyparty/u2idx.py +0 -0
  73. {copyparty-1.16.6 → copyparty-1.16.7}/copyparty/util.py +0 -0
  74. {copyparty-1.16.6 → copyparty-1.16.7}/copyparty/web/a/__init__.py +0 -0
  75. {copyparty-1.16.6 → copyparty-1.16.7}/copyparty/web/a/partyfuse.py +0 -0
  76. {copyparty-1.16.6 → copyparty-1.16.7}/copyparty/web/a/webdav-cfg.bat +0 -0
  77. {copyparty-1.16.6 → copyparty-1.16.7}/copyparty/web/baguettebox.js.gz +0 -0
  78. {copyparty-1.16.6 → copyparty-1.16.7}/copyparty/web/browser.css.gz +0 -0
  79. {copyparty-1.16.6 → copyparty-1.16.7}/copyparty/web/browser2.html +0 -0
  80. {copyparty-1.16.6 → copyparty-1.16.7}/copyparty/web/cf.html +0 -0
  81. {copyparty-1.16.6 → copyparty-1.16.7}/copyparty/web/dbg-audio.js.gz +0 -0
  82. {copyparty-1.16.6 → copyparty-1.16.7}/copyparty/web/dd/2.png +0 -0
  83. {copyparty-1.16.6 → copyparty-1.16.7}/copyparty/web/dd/3.png +0 -0
  84. {copyparty-1.16.6 → copyparty-1.16.7}/copyparty/web/dd/4.png +0 -0
  85. {copyparty-1.16.6 → copyparty-1.16.7}/copyparty/web/dd/5.png +0 -0
  86. {copyparty-1.16.6 → copyparty-1.16.7}/copyparty/web/dd/__init__.py +0 -0
  87. {copyparty-1.16.6 → copyparty-1.16.7}/copyparty/web/deps/__init__.py +0 -0
  88. {copyparty-1.16.6 → copyparty-1.16.7}/copyparty/web/deps/busy.mp3.gz +0 -0
  89. {copyparty-1.16.6 → copyparty-1.16.7}/copyparty/web/deps/easymde.css.gz +0 -0
  90. {copyparty-1.16.6 → copyparty-1.16.7}/copyparty/web/deps/easymde.js.gz +0 -0
  91. {copyparty-1.16.6 → copyparty-1.16.7}/copyparty/web/deps/fuse.py +0 -0
  92. {copyparty-1.16.6 → copyparty-1.16.7}/copyparty/web/deps/marked.js.gz +0 -0
  93. {copyparty-1.16.6 → copyparty-1.16.7}/copyparty/web/deps/mini-fa.css.gz +0 -0
  94. {copyparty-1.16.6 → copyparty-1.16.7}/copyparty/web/deps/mini-fa.woff +0 -0
  95. {copyparty-1.16.6 → copyparty-1.16.7}/copyparty/web/deps/prism.css.gz +0 -0
  96. {copyparty-1.16.6 → copyparty-1.16.7}/copyparty/web/deps/prism.js.gz +0 -0
  97. {copyparty-1.16.6 → copyparty-1.16.7}/copyparty/web/deps/prismd.css.gz +0 -0
  98. {copyparty-1.16.6 → copyparty-1.16.7}/copyparty/web/deps/scp.woff2 +0 -0
  99. {copyparty-1.16.6 → copyparty-1.16.7}/copyparty/web/deps/sha512.ac.js.gz +0 -0
  100. {copyparty-1.16.6 → copyparty-1.16.7}/copyparty/web/deps/sha512.hw.js.gz +0 -0
  101. {copyparty-1.16.6 → copyparty-1.16.7}/copyparty/web/md.css.gz +0 -0
  102. {copyparty-1.16.6 → copyparty-1.16.7}/copyparty/web/md.js.gz +0 -0
  103. {copyparty-1.16.6 → copyparty-1.16.7}/copyparty/web/md2.css.gz +0 -0
  104. {copyparty-1.16.6 → copyparty-1.16.7}/copyparty/web/md2.js.gz +0 -0
  105. {copyparty-1.16.6 → copyparty-1.16.7}/copyparty/web/mde.css.gz +0 -0
  106. {copyparty-1.16.6 → copyparty-1.16.7}/copyparty/web/mde.js.gz +0 -0
  107. {copyparty-1.16.6 → copyparty-1.16.7}/copyparty/web/msg.css.gz +0 -0
  108. {copyparty-1.16.6 → copyparty-1.16.7}/copyparty/web/msg.html +0 -0
  109. {copyparty-1.16.6 → copyparty-1.16.7}/copyparty/web/shares.css.gz +0 -0
  110. {copyparty-1.16.6 → copyparty-1.16.7}/copyparty/web/shares.js.gz +0 -0
  111. {copyparty-1.16.6 → copyparty-1.16.7}/copyparty/web/splash.css.gz +0 -0
  112. {copyparty-1.16.6 → copyparty-1.16.7}/copyparty/web/splash.js.gz +0 -0
  113. {copyparty-1.16.6 → copyparty-1.16.7}/copyparty/web/svcs.js.gz +0 -0
  114. {copyparty-1.16.6 → copyparty-1.16.7}/copyparty/web/ui.css.gz +0 -0
  115. {copyparty-1.16.6 → copyparty-1.16.7}/copyparty/web/up2k.js.gz +0 -0
  116. {copyparty-1.16.6 → copyparty-1.16.7}/copyparty/web/util.js.gz +0 -0
  117. {copyparty-1.16.6 → copyparty-1.16.7}/copyparty/web/w.hash.js.gz +0 -0
  118. {copyparty-1.16.6 → copyparty-1.16.7}/copyparty.egg-info/SOURCES.txt +0 -0
  119. {copyparty-1.16.6 → copyparty-1.16.7}/copyparty.egg-info/dependency_links.txt +0 -0
  120. {copyparty-1.16.6 → copyparty-1.16.7}/copyparty.egg-info/entry_points.txt +0 -0
  121. {copyparty-1.16.6 → copyparty-1.16.7}/copyparty.egg-info/requires.txt +0 -0
  122. {copyparty-1.16.6 → copyparty-1.16.7}/copyparty.egg-info/top_level.txt +0 -0
  123. {copyparty-1.16.6 → copyparty-1.16.7}/pyproject.toml +0 -0
  124. {copyparty-1.16.6 → copyparty-1.16.7}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: copyparty
3
- Version: 1.16.6
3
+ Version: 1.16.7
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
@@ -1,8 +1,8 @@
1
1
  # coding: utf-8
2
2
 
3
- VERSION = (1, 16, 6)
3
+ VERSION = (1, 16, 7)
4
4
  CODENAME = "COPYparty"
5
- BUILD_DT = (2024, 12, 19)
5
+ BUILD_DT = (2024, 12, 23)
6
6
 
7
7
  S_VERSION = ".".join(map(str, VERSION))
8
8
  S_BUILD_DT = "{0:04d}-{1:02d}-{2:02d}".format(*BUILD_DT)
@@ -2174,11 +2174,11 @@ class AuthSrv(object):
2174
2174
  if not self.args.no_voldump:
2175
2175
  self.log(t)
2176
2176
 
2177
- if have_e2d:
2177
+ if have_e2d or self.args.idp_h_usr:
2178
2178
  t = self.chk_sqlite_threadsafe()
2179
2179
  if t:
2180
2180
  self.log("\n\033[{}\033[0m\n".format(t))
2181
-
2181
+ if have_e2d:
2182
2182
  if not have_e2t:
2183
2183
  t = "hint: enable multimedia indexing (artist/title/...) with argument -e2ts"
2184
2184
  self.log(t, 6)
@@ -141,6 +141,14 @@ A_FILE = os.stat_result(
141
141
  (0o644, -1, -1, 1, 1000, 1000, 8, 0x39230101, 0x39230101, 0x39230101)
142
142
  )
143
143
 
144
+ RE_CC = re.compile(r"[\x00-\x1f]") # search always faster
145
+ RE_HSAFE = re.compile(r"[\x00-\x1f<>\"'&]") # search always much faster
146
+ RE_HOST = re.compile(r"[^][0-9a-zA-Z.:_-]") # search faster <=17ch
147
+ RE_MHOST = re.compile(r"^[][0-9a-zA-Z.:_-]+$") # match faster >=18ch
148
+ RE_K = re.compile(r"[^0-9a-zA-Z_-]") # search faster <=17ch
149
+
150
+ UPARAM_CC_OK = set("doc move tree".split())
151
+
144
152
 
145
153
  class HttpCli(object):
146
154
  """
@@ -384,6 +392,15 @@ class HttpCli(object):
384
392
  self.host = self.headers.get("x-forwarded-host") or self.host
385
393
  trusted_xff = True
386
394
 
395
+ m = RE_HOST.search(self.host)
396
+ if m and self.host != self.args.name:
397
+ zs = self.host
398
+ t = "malicious user; illegal Host header; req(%r) host(%r) => %r"
399
+ self.log(t % (self.req, zs, zs[m.span()[0] :]), 1)
400
+ self.cbonk(self.conn.hsrv.gmal, zs, "bad_host", "illegal Host header")
401
+ self.terse_reply(b"illegal Host header", 400)
402
+ return False
403
+
387
404
  if self.is_banned():
388
405
  return False
389
406
 
@@ -429,6 +446,16 @@ class HttpCli(object):
429
446
  self.loud_reply(t, status=400)
430
447
  return False
431
448
 
449
+ ptn_cc = RE_CC
450
+ m = ptn_cc.search(self.req)
451
+ if m:
452
+ zs = self.req
453
+ t = "malicious user; Cc in req0 %r => %r"
454
+ self.log(t % (zs, zs[m.span()[0] :]), 1)
455
+ self.cbonk(self.conn.hsrv.gmal, zs, "cc_r0", "Cc in req0")
456
+ self.terse_reply(b"", 500)
457
+ return False
458
+
432
459
  # split req into vpath + uparam
433
460
  uparam = {}
434
461
  if "?" not in self.req:
@@ -441,8 +468,8 @@ class HttpCli(object):
441
468
  self.trailing_slash = vpath.endswith("/")
442
469
  vpath = undot(vpath)
443
470
 
444
- ptn = self.conn.hsrv.ptn_cc
445
- k_safe = self.conn.hsrv.uparam_cc_ok
471
+ re_k = RE_K
472
+ k_safe = UPARAM_CC_OK
446
473
  for k in arglist.split("&"):
447
474
  if "=" in k:
448
475
  k, zs = k.split("=", 1)
@@ -452,6 +479,14 @@ class HttpCli(object):
452
479
  else:
453
480
  sv = ""
454
481
 
482
+ m = re_k.search(k)
483
+ if m:
484
+ t = "malicious user; bad char in query key; req(%r) qk(%r) => %r"
485
+ self.log(t % (self.req, k, k[m.span()[0] :]), 1)
486
+ self.cbonk(self.conn.hsrv.gmal, self.req, "bc_q", "illegal qkey")
487
+ self.terse_reply(b"", 500)
488
+ return False
489
+
455
490
  k = k.lower()
456
491
  uparam[k] = sv
457
492
 
@@ -459,17 +494,26 @@ class HttpCli(object):
459
494
  continue
460
495
 
461
496
  zs = "%s=%s" % (k, sv)
462
- m = ptn.search(zs)
497
+ m = ptn_cc.search(zs)
463
498
  if not m:
464
499
  continue
465
500
 
466
- hit = zs[m.span()[0] :]
467
- t = "malicious user; Cc in query [{}] => [{!r}]"
468
- self.log(t.format(self.req, hit), 1)
501
+ t = "malicious user; Cc in query; req(%r) qp(%r) => %r"
502
+ self.log(t % (self.req, zs, zs[m.span()[0] :]), 1)
469
503
  self.cbonk(self.conn.hsrv.gmal, self.req, "cc_q", "Cc in query")
470
504
  self.terse_reply(b"", 500)
471
505
  return False
472
506
 
507
+ if "k" in uparam:
508
+ m = RE_K.search(uparam["k"])
509
+ if m:
510
+ zs = uparam["k"]
511
+ t = "malicious user; illegal filekey; req(%r) k(%r) => %r"
512
+ self.log(t % (self.req, zs, zs[m.span()[0] :]), 1)
513
+ self.cbonk(self.conn.hsrv.gmal, zs, "bad_k", "illegal filekey")
514
+ self.terse_reply(b"illegal filekey", 400)
515
+ return False
516
+
473
517
  if self.is_vproxied:
474
518
  if vpath.startswith(self.args.R):
475
519
  vpath = vpath[len(self.args.R) + 1 :]
@@ -513,7 +557,7 @@ class HttpCli(object):
513
557
  return self.tx_qr()
514
558
 
515
559
  if relchk(self.vpath) and (self.vpath != "*" or self.mode != "OPTIONS"):
516
- self.log("invalid relpath %r" % ("/" + self.vpath,))
560
+ self.log("illegal relpath; req(%r) => %r" % (self.req, "/" + self.vpath))
517
561
  self.cbonk(self.conn.hsrv.gmal, self.req, "bad_vp", "invalid relpaths")
518
562
  return self.tx_404() and self.keepalive
519
563
 
@@ -866,12 +910,12 @@ class HttpCli(object):
866
910
  for k, zs in list(self.out_headers.items()) + self.out_headerlist:
867
911
  response.append("%s: %s" % (k, zs))
868
912
 
913
+ ptn_cc = RE_CC
869
914
  for zs in response:
870
- m = self.conn.hsrv.ptn_cc.search(zs)
915
+ m = ptn_cc.search(zs)
871
916
  if m:
872
- hit = zs[m.span()[0] :]
873
- t = "malicious user; Cc in out-hdr {!r} => [{!r}]"
874
- self.log(t.format(zs, hit), 1)
917
+ t = "malicious user; Cc in out-hdr; req(%r) hdr(%r) => %r"
918
+ self.log(t % (self.req, zs, zs[m.span()[0] :]), 1)
875
919
  self.cbonk(self.conn.hsrv.gmal, zs, "cc_hdr", "Cc in out-hdr")
876
920
  raise Pebkac(999)
877
921
 
@@ -997,7 +1041,7 @@ class HttpCli(object):
997
1041
  if not kv:
998
1042
  return ""
999
1043
 
1000
- r = ["%s=%s" % (k, quotep(zs)) if zs else k for k, zs in kv.items()]
1044
+ r = ["%s=%s" % (quotep(k), quotep(zs)) if zs else k for k, zs in kv.items()]
1001
1045
  return "?" + "&amp;".join(r)
1002
1046
 
1003
1047
  def ourlq(self) :
@@ -1149,8 +1193,8 @@ class HttpCli(object):
1149
1193
  return self.tx_res(res_path)
1150
1194
 
1151
1195
  if res_path != undot(res_path):
1152
- t = "malicious user; attempted path traversal %r => %r"
1153
- self.log(t % ("/" + self.vpath, res_path), 1)
1196
+ t = "malicious user; attempted path traversal; req(%r) vp(%r) => %r"
1197
+ self.log(t % (self.req, "/" + self.vpath, res_path), 1)
1154
1198
  self.cbonk(self.conn.hsrv.gmal, self.req, "trav", "path traversal")
1155
1199
 
1156
1200
  self.tx_404()
@@ -1293,8 +1337,8 @@ class HttpCli(object):
1293
1337
 
1294
1338
  pw = self.ouparam.get("pw")
1295
1339
  if pw:
1296
- q_pw = "?pw=%s" % (pw,)
1297
- a_pw = "&pw=%s" % (pw,)
1340
+ q_pw = "?pw=%s" % (html_escape(pw, True, True),)
1341
+ a_pw = "&pw=%s" % (html_escape(pw, True, True),)
1298
1342
  for i in hits:
1299
1343
  i["rp"] += a_pw if "?" in i["rp"] else q_pw
1300
1344
  else:
@@ -1655,7 +1699,7 @@ class HttpCli(object):
1655
1699
 
1656
1700
  token = str(uuid.uuid4())
1657
1701
 
1658
- if not lk.find(r"./{DAV:}depth"):
1702
+ if lk.find(r"./{DAV:}depth") is None:
1659
1703
  depth = self.headers.get("depth", "infinity")
1660
1704
  lk.append(mktnod("D:depth", depth))
1661
1705
 
@@ -3636,6 +3680,7 @@ class HttpCli(object):
3636
3680
  return logues, readmes
3637
3681
 
3638
3682
  def _expand(self, txt , phs ) :
3683
+ ptn_hsafe = RE_HSAFE
3639
3684
  for ph in phs:
3640
3685
  if ph.startswith("hdr."):
3641
3686
  sv = str(self.headers.get(ph[4:], ""))
@@ -3653,7 +3698,7 @@ class HttpCli(object):
3653
3698
  self.log("unknown placeholder in server config: [%s]" % (ph,), 3)
3654
3699
  continue
3655
3700
 
3656
- sv = self.conn.hsrv.ptn_hsafe.sub("_", sv)
3701
+ sv = ptn_hsafe.sub("_", sv)
3657
3702
  txt = txt.replace("{{%s}}" % (ph,), sv)
3658
3703
 
3659
3704
  return txt
@@ -4965,11 +5010,11 @@ class HttpCli(object):
4965
5010
  ret.sort(key=lambda x: x["at"], reverse=True) # type: ignore
4966
5011
  ret = ret[:2000]
4967
5012
 
5013
+ ret.sort(key=lambda x: x["at"], reverse=True) # type: ignore
5014
+
4968
5015
  if len(ret) > 2000:
4969
5016
  ret = ret[:2000]
4970
5017
 
4971
- ret.sort(key=lambda x: x["at"], reverse=True) # type: ignore
4972
-
4973
5018
  for rv in ret:
4974
5019
  rv["vp"] = quotep(rv["vp"])
4975
5020
  nfk = rv.pop("nfk")
@@ -5057,10 +5102,6 @@ class HttpCli(object):
5057
5102
  if not dots and "/." in vp:
5058
5103
  continue
5059
5104
 
5060
- n -= 1
5061
- if not n:
5062
- break
5063
-
5064
5105
  rv = {
5065
5106
  "vp": vp,
5066
5107
  "sz": sz,
@@ -5078,13 +5119,17 @@ class HttpCli(object):
5078
5119
  ret.sort(key=lambda x: x["at"], reverse=True) # type: ignore
5079
5120
  ret = ret[:1000]
5080
5121
 
5081
- if len(ret) > 1000:
5082
- ret = ret[:1000]
5122
+ n -= 1
5123
+ if not n:
5124
+ break
5083
5125
 
5084
5126
  ret.sort(key=lambda x: x["at"], reverse=True) # type: ignore
5085
5127
 
5128
+ if len(ret) > 1000:
5129
+ ret = ret[:1000]
5130
+
5086
5131
  for rv in ret:
5087
- rv["evp"] = quotep(rv["vp"])
5132
+ rv["vp"] = quotep(rv["vp"])
5088
5133
  nfk = rv.pop("nfk")
5089
5134
  if not nfk:
5090
5135
  continue
@@ -5117,15 +5162,16 @@ class HttpCli(object):
5117
5162
  for v in ret:
5118
5163
  v["vp"] = self.args.SR + v["vp"]
5119
5164
 
5120
- self.log("%s #%d %.2fsec" % (lm, len(ret), time.time() - t0))
5165
+ now = time.time()
5166
+ self.log("%s #%d %.2fsec" % (lm, len(ret), now - t0))
5121
5167
 
5168
+ ret2 = {"now": int(now), "filter": sfilt, "ups": ret}
5169
+ jtxt = json.dumps(ret2, separators=(",\n", ": "))
5122
5170
  if "j" in self.ouparam:
5123
- jtxt = json.dumps(ret, separators=(",\n", ": "))
5124
5171
  self.reply(jtxt.encode("utf-8", "replace"), mime="application/json")
5125
5172
  return True
5126
5173
 
5127
- rows = [[x["vp"], x["evp"], x["sz"], x["ip"], x["at"]] for x in ret]
5128
- html = self.j2s("rups", this=self, rows=rows, filt=sfilt, now=int(time.time()))
5174
+ html = self.j2s("rups", this=self, v=jtxt)
5129
5175
  self.reply(html.encode("utf-8"), status=200)
5130
5176
  return True
5131
5177
 
@@ -191,10 +191,6 @@ class HttpSrv(object):
191
191
  self.xff_nm = build_netmap(self.args.xff_src)
192
192
  self.xff_lan = build_netmap("lan")
193
193
 
194
- self.ptn_cc = re.compile(r"[\x00-\x1f]")
195
- self.ptn_hsafe = re.compile(r"[\x00-\x1f<>\"'&]")
196
- self.uparam_cc_ok = set("doc move tree".split())
197
-
198
194
  self.mallow = "GET HEAD POST PUT DELETE OPTIONS".split()
199
195
  if not self.args.no_dav:
200
196
  zs = "PROPFIND PROPPATCH LOCK UNLOCK MKCOL COPY MOVE"
@@ -403,12 +403,12 @@ class TcpSrv(object):
403
403
  rem = []
404
404
  for k, v in netdevs.items():
405
405
  if k not in self.netdevs:
406
- add.append("\n added %s = %s" % (k, v))
406
+ add.append("\n\033[32m added %s = %s" % (k, v))
407
407
  for k, v in self.netdevs.items():
408
408
  if k not in netdevs:
409
- rem.append("\nremoved %s = %s" % (k, v))
409
+ rem.append("\n\033[33mremoved %s = %s" % (k, v))
410
410
 
411
- t = "network change detected:\033[32m%s\033[33m%s"
411
+ t = "network change detected:%s%s"
412
412
  self.log("tcpsrv", t % ("".join(add), "".join(rem)), 3)
413
413
  self.netdevs = netdevs
414
414
  self._distribute_netdevs()
@@ -851,9 +851,9 @@ class Up2k(object):
851
851
  self.iacct = self.asrv.iacct
852
852
  self.grps = self.asrv.grps
853
853
 
854
+ have_e2d = self.args.idp_h_usr
854
855
  vols = list(all_vols.values())
855
856
  t0 = time.time()
856
- have_e2d = False
857
857
 
858
858
  if self.no_expr_idx:
859
859
  modified = False
@@ -1101,7 +1101,7 @@ class Ctl(object):
1101
1101
  nleft = self.nfiles - self.up_f
1102
1102
  tail = "\033[K\033[u" if VT100 and not self.ar.ns else "\r"
1103
1103
 
1104
- t = "%s eta @ %s/s, %s, %d# left\033[K" % (self.eta, spd, sleft, nleft)
1104
+ t = "%s eta @ %s/s, %s, %d# left" % (self.eta, spd, sleft, nleft)
1105
1105
  if not self.hash_b:
1106
1106
  t = " now hashing..."
1107
1107
  eprint(txt + "\033]0;{0}\033\\\r{0}{1}".format(t, tail))
@@ -131,7 +131,7 @@
131
131
  <div id="widget"></div>
132
132
 
133
133
  <script>
134
- var SR = {{ r|tojson }},
134
+ var SR = "{{ r }}",
135
135
  CGV1 = {{ cgv1 }},
136
136
  CGV = {{ cgv|tojson }},
137
137
  TS = "{{ ts }}",
@@ -128,9 +128,9 @@ write markdown (most html is 🙆 too)
128
128
 
129
129
  <script>
130
130
 
131
- var SR = {{ r|tojson }},
131
+ var SR = "{{ r }}",
132
132
  last_modified = {{ lastmod }},
133
- have_emp = {{ have_emp|tojson }},
133
+ have_emp = {{ "true" if have_emp else "false" }},
134
134
  dfavico = "{{ favico }}";
135
135
 
136
136
  var md_opt = {
@@ -26,9 +26,9 @@
26
26
  <a href="#" id="repl">π</a>
27
27
  <script>
28
28
 
29
- var SR = {{ r|tojson }},
29
+ var SR = "{{ r }}",
30
30
  last_modified = {{ lastmod }},
31
- have_emp = {{ have_emp|tojson }},
31
+ have_emp = {{ "true" if have_emp else "false" }},
32
32
  dfavico = "{{ favico }}";
33
33
 
34
34
  var md_opt = {
@@ -6,6 +6,7 @@
6
6
  <title>{{ s_doctitle }}</title>
7
7
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
8
8
  <meta name="viewport" content="width=device-width, initial-scale=0.8">
9
+ <meta name="robots" content="noindex, nofollow">
9
10
  <meta name="theme-color" content="#{{ tcolor }}">
10
11
  <link rel="stylesheet" media="screen" href="{{ r }}/.cpr/rups.css?_={{ ts }}">
11
12
  <link rel="stylesheet" media="screen" href="{{ r }}/.cpr/ui.css?_={{ ts }}">
@@ -14,14 +15,10 @@
14
15
 
15
16
  <body>
16
17
  <div id="wrap">
17
- <a id="a" href="{{ r }}/?ru" class="af">refresh</a>
18
- <a id="a" href="{{ r }}/?h" class="af">control-panel</a>
19
- <form method="get" enctype="application/x-www-form-urlencoded" accept-charset="utf-8" action="{{ r }}">
20
- <input type="hidden" name="ru" value="a" />
21
- Filter: <input type="text" name="filter" size="20" placeholder="documents/passwords" value="{{ filt }}" />
22
- <input type="submit" />
23
- </form>
24
- <span id="hits"></span>
18
+ <a href="#" id="re">refresh</a>
19
+ <a href="{{ r }}/?h">control-panel</a>
20
+ &nbsp; Filter: <input type="text" id="filter" size="20" placeholder="documents/passwords" />
21
+ &nbsp; <span id="hits"></span>
25
22
  <table id="tab"><thead><tr>
26
23
  <th>size</th>
27
24
  <th>who</th>
@@ -29,27 +26,12 @@
29
26
  <th>age</th>
30
27
  <th>dir</th>
31
28
  <th>file</th>
32
- </tr></thead><tbody>
33
- {% for vp, evp, sz, ip, at in rows %}
34
- <tr>
35
- <td>{{ sz }}</td>
36
- <td>{{ ip }}</td>
37
- <td>{{ at }}</td>
38
- <td>{{ (now-at) }}</td>
39
- <td></td>
40
- <td><a href="{{ r }}{{ evp }}">{{ vp|e }}</a></td>
41
- </tr>
42
- {% endfor %}
43
- </tbody></table>
44
- {% if not rows %}
45
- (the database is not aware of any uploads)
46
- {% endif %}
29
+ </tr></thead><tbody id="tb"></tbody></table>
47
30
  </div>
48
31
  <a href="#" id="repl">π</a>
49
32
  <script>
50
33
 
51
- var SR = {{ r|tojson }},
52
- NOW = {{ now }},
34
+ var SR="{{ r }}",
53
35
  lang="{{ lang }}",
54
36
  dfavico="{{ favico }}";
55
37
 
@@ -58,6 +40,7 @@ document.documentElement.className = (STG && STG.cpp_thm) || "{{ this.args.theme
58
40
 
59
41
  </script>
60
42
  <script src="{{ r }}/.cpr/util.js?_={{ ts }}"></script>
43
+ <script>var V={{ v }};</script>
61
44
  <script src="{{ r }}/.cpr/rups.js?_={{ ts }}"></script>
62
45
  {%- if js %}
63
46
  <script src="{{ js }}_={{ ts }}"></script>
@@ -6,6 +6,7 @@
6
6
  <title>{{ s_doctitle }}</title>
7
7
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
8
8
  <meta name="viewport" content="width=device-width, initial-scale=0.8">
9
+ <meta name="robots" content="noindex, nofollow">
9
10
  <meta name="theme-color" content="#{{ tcolor }}">
10
11
  <link rel="stylesheet" media="screen" href="{{ r }}/.cpr/shares.css?_={{ ts }}">
11
12
  <link rel="stylesheet" media="screen" href="{{ r }}/.cpr/ui.css?_={{ ts }}">
@@ -14,8 +15,8 @@
14
15
 
15
16
  <body>
16
17
  <div id="wrap">
17
- <a id="a" href="{{ r }}/?shares" class="af">refresh</a>
18
- <a id="a" href="{{ r }}/?h" class="af">control-panel</a>
18
+ <a href="{{ r }}/?shares">refresh</a>
19
+ <a href="{{ r }}/?h">control-panel</a>
19
20
 
20
21
  <span>axs = perms (read,write,move,delet)</span>
21
22
  <span>nf = numFiles (0=dir)</span>
@@ -62,7 +63,7 @@
62
63
  <a href="#" id="repl">π</a>
63
64
  <script>
64
65
 
65
- var SR = {{ r|tojson }},
66
+ var SR="{{ r }}",
66
67
  shr="{{ shr }}",
67
68
  lang="{{ lang }}",
68
69
  dfavico="{{ favico }}";
@@ -168,7 +168,7 @@
168
168
  {%- endif %}
169
169
  <script>
170
170
 
171
- var SR = {{ r|tojson }},
171
+ var SR="{{ r }}",
172
172
  lang="{{ lang }}",
173
173
  dfavico="{{ favico }}";
174
174
 
@@ -233,7 +233,7 @@
233
233
  <a href="#" id="repl">π</a>
234
234
  <script>
235
235
 
236
- var SR = {{ r|tojson }},
236
+ var SR="{{ r }}",
237
237
  lang="{{ lang }}",
238
238
  dfavico="{{ favico }}";
239
239
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: copyparty
3
- Version: 1.16.6
3
+ Version: 1.16.7
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
Binary file
Binary file
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes