copyparty 1.13.6__py3-none-any.whl → 1.13.8__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.
Files changed (42) hide show
  1. copyparty/__main__.py +25 -7
  2. copyparty/__version__.py +2 -2
  3. copyparty/authsrv.py +9 -6
  4. copyparty/cert.py +1 -1
  5. copyparty/fsutil.py +3 -3
  6. copyparty/ftpd.py +15 -2
  7. copyparty/httpcli.py +224 -81
  8. copyparty/httpconn.py +3 -0
  9. copyparty/httpsrv.py +38 -11
  10. copyparty/ico.py +1 -1
  11. copyparty/mtag.py +15 -6
  12. copyparty/pwhash.py +10 -0
  13. copyparty/smbd.py +20 -2
  14. copyparty/ssdp.py +3 -3
  15. copyparty/stolen/dnslib/dns.py +6 -0
  16. copyparty/stolen/ifaddr/__init__.py +15 -1
  17. copyparty/stolen/ifaddr/_shared.py +1 -0
  18. copyparty/stolen/qrcodegen.py +6 -0
  19. copyparty/sutil.py +1 -1
  20. copyparty/svchub.py +72 -3
  21. copyparty/szip.py +1 -3
  22. copyparty/tcpsrv.py +63 -8
  23. copyparty/tftpd.py +30 -4
  24. copyparty/th_srv.py +22 -1
  25. copyparty/u2idx.py +4 -1
  26. copyparty/up2k.py +221 -93
  27. copyparty/util.py +166 -31
  28. copyparty/web/a/u2c.py +10 -3
  29. copyparty/web/browser.css.gz +0 -0
  30. copyparty/web/browser2.html +0 -1
  31. copyparty/web/md.html +3 -0
  32. copyparty/web/mde.html +3 -0
  33. copyparty/web/msg.html +3 -0
  34. copyparty/web/splash.html +3 -0
  35. copyparty/web/svcs.html +3 -0
  36. copyparty/web/up2k.js.gz +0 -0
  37. {copyparty-1.13.6.dist-info → copyparty-1.13.8.dist-info}/METADATA +64 -14
  38. {copyparty-1.13.6.dist-info → copyparty-1.13.8.dist-info}/RECORD +42 -42
  39. {copyparty-1.13.6.dist-info → copyparty-1.13.8.dist-info}/LICENSE +0 -0
  40. {copyparty-1.13.6.dist-info → copyparty-1.13.8.dist-info}/WHEEL +0 -0
  41. {copyparty-1.13.6.dist-info → copyparty-1.13.8.dist-info}/entry_points.txt +0 -0
  42. {copyparty-1.13.6.dist-info → copyparty-1.13.8.dist-info}/top_level.txt +0 -0
copyparty/httpcli.py CHANGED
@@ -13,18 +13,22 @@ import json
13
13
  import os
14
14
  import random
15
15
  import re
16
+ import socket
16
17
  import stat
17
18
  import string
18
19
  import threading # typechk
19
20
  import time
20
21
  import uuid
21
22
  from datetime import datetime
22
- from email.utils import formatdate, parsedate
23
+ from email.utils import parsedate
23
24
  from operator import itemgetter
24
25
 
25
26
  import jinja2 # typechk
26
27
 
27
28
  try:
29
+ if os.environ.get("PRTY_NO_LZMA"):
30
+ raise Exception()
31
+
28
32
  import lzma
29
33
  except:
30
34
  pass
@@ -54,6 +58,7 @@ from .util import (
54
58
  alltrace,
55
59
  atomic_move,
56
60
  exclude_dotfiles,
61
+ formatdate,
57
62
  fsenc,
58
63
  gen_filekey,
59
64
  gen_filekey_dbg,
@@ -69,7 +74,9 @@ from .util import (
69
74
  humansize,
70
75
  ipnorm,
71
76
  loadpy,
77
+ log_reloc,
72
78
  min_ex,
79
+ pathmod,
73
80
  quotep,
74
81
  rand_name,
75
82
  read_header,
@@ -101,6 +108,9 @@ from .util import (
101
108
  if TYPE_CHECKING:
102
109
  from .httpconn import HttpConn
103
110
 
111
+ if not hasattr(socket, "AF_UNIX"):
112
+ setattr(socket, "AF_UNIX", -9001)
113
+
104
114
  _ = (argparse, threading)
105
115
 
106
116
  NO_CACHE = {"Cache-Control": "no-cache"}
@@ -218,6 +228,11 @@ class HttpCli(object):
218
228
  ka["s_doctitle"] = self.args.doctitle
219
229
  ka["tcolor"] = self.vn.flags["tcolor"]
220
230
 
231
+ if self.args.js_other and "js" not in ka:
232
+ zs = self.args.js_other
233
+ zs += "&" if "?" in zs else "?"
234
+ ka["js"] = zs
235
+
221
236
  zso = self.vn.flags.get("html_head")
222
237
  if zso:
223
238
  ka["this"] = self
@@ -299,8 +314,11 @@ class HttpCli(object):
299
314
  )
300
315
  self.host = self.headers.get("host") or ""
301
316
  if not self.host:
302
- zs = "%s:%s" % self.s.getsockname()[:2]
303
- self.host = zs[7:] if zs.startswith("::ffff:") else zs
317
+ if self.s.family == socket.AF_UNIX:
318
+ self.host = self.args.name
319
+ else:
320
+ zs = "%s:%s" % self.s.getsockname()[:2]
321
+ self.host = zs[7:] if zs.startswith("::ffff:") else zs
304
322
 
305
323
  trusted_xff = False
306
324
  n = self.args.rproxy
@@ -687,6 +705,9 @@ class HttpCli(object):
687
705
  xban = self.vn.flags.get("xban")
688
706
  if not xban or not runhook(
689
707
  self.log,
708
+ self.conn.hsrv.broker,
709
+ None,
710
+ "xban",
690
711
  xban,
691
712
  self.vn.canonical(self.rem),
692
713
  self.vpath,
@@ -783,7 +804,7 @@ class HttpCli(object):
783
804
 
784
805
  # close if unknown length, otherwise take client's preference
785
806
  response.append("Connection: " + ("Keep-Alive" if self.keepalive else "Close"))
786
- response.append("Date: " + formatdate(usegmt=True))
807
+ response.append("Date: " + formatdate())
787
808
 
788
809
  # headers{} overrides anything set previously
789
810
  if headers:
@@ -807,9 +828,9 @@ class HttpCli(object):
807
828
  self.cbonk(self.conn.hsrv.gmal, zs, "cc_hdr", "Cc in out-hdr")
808
829
  raise Pebkac(999)
809
830
 
831
+ response.append("\r\n")
810
832
  try:
811
- # best practice to separate headers and body into different packets
812
- self.s.sendall("\r\n".join(response).encode("utf-8") + b"\r\n\r\n")
833
+ self.s.sendall("\r\n".join(response).encode("utf-8"))
813
834
  except:
814
835
  raise Pebkac(400, "client d/c while replying headers")
815
836
 
@@ -1142,7 +1163,7 @@ class HttpCli(object):
1142
1163
  return self.tx_mounts()
1143
1164
 
1144
1165
  # conditional redirect to single volumes
1145
- if self.vpath == "" and not self.ouparam:
1166
+ if not self.vpath and not self.ouparam:
1146
1167
  nread = len(self.rvol)
1147
1168
  nwrite = len(self.wvol)
1148
1169
  if nread + nwrite == 1 or (self.rvol == self.wvol and nread == 1):
@@ -1164,7 +1185,8 @@ class HttpCli(object):
1164
1185
  if self.args.no_dav:
1165
1186
  raise Pebkac(405, "WebDAV is disabled in server config")
1166
1187
 
1167
- vn, rem = self.asrv.vfs.get(self.vpath, self.uname, False, False, err=401)
1188
+ vn = self.vn
1189
+ rem = self.rem
1168
1190
  tap = vn.canonical(rem)
1169
1191
 
1170
1192
  if "davauth" in vn.flags and self.uname == "*":
@@ -1301,7 +1323,7 @@ class HttpCli(object):
1301
1323
 
1302
1324
  pvs = {
1303
1325
  "displayname": html_escape(rp.split("/")[-1]),
1304
- "getlastmodified": formatdate(mtime, usegmt=True),
1326
+ "getlastmodified": formatdate(mtime),
1305
1327
  "resourcetype": '<D:collection xmlns:D="DAV:"/>' if isdir else "",
1306
1328
  "supportedlock": '<D:lockentry xmlns:D="DAV:"><D:lockscope><D:exclusive/></D:lockscope><D:locktype><D:write/></D:locktype></D:lockentry>',
1307
1329
  }
@@ -1548,8 +1570,8 @@ class HttpCli(object):
1548
1570
  self.log("PUT %s @%s" % (self.req, self.uname))
1549
1571
 
1550
1572
  if not self.can_write:
1551
- t = "user {} does not have write-access here"
1552
- raise Pebkac(403, t.format(self.uname))
1573
+ t = "user %s does not have write-access under /%s"
1574
+ raise Pebkac(403, t % (self.uname, self.vn.vpath))
1553
1575
 
1554
1576
  if not self.args.no_dav and self._applesan():
1555
1577
  return self.headers.get("content-length") == "0"
@@ -1624,6 +1646,9 @@ class HttpCli(object):
1624
1646
  if xm:
1625
1647
  runhook(
1626
1648
  self.log,
1649
+ self.conn.hsrv.broker,
1650
+ None,
1651
+ "xm",
1627
1652
  xm,
1628
1653
  self.vn.canonical(self.rem),
1629
1654
  self.vpath,
@@ -1772,11 +1797,15 @@ class HttpCli(object):
1772
1797
 
1773
1798
  if xbu:
1774
1799
  at = time.time() - lifetime
1775
- if not runhook(
1800
+ vp = vjoin(self.vpath, fn) if nameless else self.vpath
1801
+ hr = runhook(
1776
1802
  self.log,
1803
+ self.conn.hsrv.broker,
1804
+ None,
1805
+ "xbu.http.dump",
1777
1806
  xbu,
1778
1807
  path,
1779
- self.vpath,
1808
+ vp,
1780
1809
  self.host,
1781
1810
  self.uname,
1782
1811
  self.asrv.vfs.get_perms(self.vpath, self.uname),
@@ -1785,10 +1814,25 @@ class HttpCli(object):
1785
1814
  self.ip,
1786
1815
  at,
1787
1816
  "",
1788
- ):
1817
+ )
1818
+ if not hr:
1789
1819
  t = "upload blocked by xbu server config"
1790
1820
  self.log(t, 1)
1791
1821
  raise Pebkac(403, t)
1822
+ if hr.get("reloc"):
1823
+ x = pathmod(self.asrv.vfs, path, vp, hr["reloc"])
1824
+ if x:
1825
+ if self.args.hook_v:
1826
+ log_reloc(self.log, hr["reloc"], x, path, vp, fn, vfs, rem)
1827
+ fdir, self.vpath, fn, (vfs, rem) = x
1828
+ if self.args.nw:
1829
+ fn = os.devnull
1830
+ else:
1831
+ bos.makedirs(fdir)
1832
+ path = os.path.join(fdir, fn)
1833
+ if not nameless:
1834
+ self.vpath = vjoin(self.vpath, fn)
1835
+ params["fdir"] = fdir
1792
1836
 
1793
1837
  if is_put and not (self.args.no_dav or self.args.nw) and bos.path.exists(path):
1794
1838
  # allow overwrite if...
@@ -1863,24 +1907,45 @@ class HttpCli(object):
1863
1907
  fn = fn2
1864
1908
  path = path2
1865
1909
 
1866
- if xau and not runhook(
1867
- self.log,
1868
- xau,
1869
- path,
1870
- self.vpath,
1871
- self.host,
1872
- self.uname,
1873
- self.asrv.vfs.get_perms(self.vpath, self.uname),
1874
- mt,
1875
- post_sz,
1876
- self.ip,
1877
- at,
1878
- "",
1879
- ):
1880
- t = "upload blocked by xau server config"
1881
- self.log(t, 1)
1882
- wunlink(self.log, path, vfs.flags)
1883
- raise Pebkac(403, t)
1910
+ if xau:
1911
+ vp = vjoin(self.vpath, fn) if nameless else self.vpath
1912
+ hr = runhook(
1913
+ self.log,
1914
+ self.conn.hsrv.broker,
1915
+ None,
1916
+ "xau.http.dump",
1917
+ xau,
1918
+ path,
1919
+ vp,
1920
+ self.host,
1921
+ self.uname,
1922
+ self.asrv.vfs.get_perms(self.vpath, self.uname),
1923
+ mt,
1924
+ post_sz,
1925
+ self.ip,
1926
+ at,
1927
+ "",
1928
+ )
1929
+ if not hr:
1930
+ t = "upload blocked by xau server config"
1931
+ self.log(t, 1)
1932
+ wunlink(self.log, path, vfs.flags)
1933
+ raise Pebkac(403, t)
1934
+ if hr.get("reloc"):
1935
+ x = pathmod(self.asrv.vfs, path, vp, hr["reloc"])
1936
+ if x:
1937
+ if self.args.hook_v:
1938
+ log_reloc(self.log, hr["reloc"], x, path, vp, fn, vfs, rem)
1939
+ fdir, self.vpath, fn, (vfs, rem) = x
1940
+ bos.makedirs(fdir)
1941
+ path2 = os.path.join(fdir, fn)
1942
+ atomic_move(self.log, path, path2, vfs.flags)
1943
+ path = path2
1944
+ if not nameless:
1945
+ self.vpath = vjoin(self.vpath, fn)
1946
+ sz = bos.path.getsize(path)
1947
+ else:
1948
+ sz = post_sz
1884
1949
 
1885
1950
  vfs, rem = vfs.get_dbv(rem)
1886
1951
  self.conn.hsrv.broker.say(
@@ -1903,7 +1968,7 @@ class HttpCli(object):
1903
1968
  alg,
1904
1969
  self.args.fk_salt,
1905
1970
  path,
1906
- post_sz,
1971
+ sz,
1907
1972
  0 if ANYWIN else bos.stat(path).st_ino,
1908
1973
  )[: vfs.flags["fk"]]
1909
1974
 
@@ -2206,13 +2271,21 @@ class HttpCli(object):
2206
2271
  raise Pebkac(400, "need hash and wark headers for binary POST")
2207
2272
 
2208
2273
  chashes = [x.strip() for x in chashes]
2274
+ if len(chashes) == 3 and len(chashes[1]) == 1:
2275
+ # the first hash, then length of consecutive hashes,
2276
+ # then a list of stitched hashes as one long string
2277
+ clen = int(chashes[1])
2278
+ siblings = chashes[2]
2279
+ chashes = [chashes[0]]
2280
+ for n in range(0, len(siblings), clen):
2281
+ chashes.append(siblings[n : n + clen])
2209
2282
 
2210
2283
  vfs, _ = self.asrv.vfs.get(self.vpath, self.uname, False, True)
2211
2284
  ptop = (vfs.dbv or vfs).realpath
2212
2285
 
2213
2286
  x = self.conn.hsrv.broker.ask("up2k.handle_chunks", ptop, wark, chashes)
2214
2287
  response = x.get()
2215
- chunksize, cstarts, path, lastmod, sprs = response
2288
+ chashes, chunksize, cstarts, path, lastmod, sprs = response
2216
2289
  maxsize = chunksize * len(chashes)
2217
2290
  cstart0 = cstarts[0]
2218
2291
 
@@ -2520,18 +2593,15 @@ class HttpCli(object):
2520
2593
  fname = sanitize_fn(
2521
2594
  p_file or "", "", [".prologue.html", ".epilogue.html"]
2522
2595
  )
2596
+ abspath = os.path.join(fdir, fname)
2597
+ suffix = "-%.6f-%s" % (time.time(), dip)
2523
2598
  if p_file and not nullwrite:
2524
2599
  if rnd:
2525
2600
  fname = rand_name(fdir, fname, rnd)
2526
2601
 
2527
- if not bos.path.isdir(fdir):
2528
- raise Pebkac(404, "that folder does not exist")
2529
-
2530
- suffix = "-{:.6f}-{}".format(time.time(), dip)
2531
2602
  open_args = {"fdir": fdir, "suffix": suffix}
2532
2603
 
2533
2604
  if "replace" in self.uparam:
2534
- abspath = os.path.join(fdir, fname)
2535
2605
  if not self.can_delete:
2536
2606
  self.log("user not allowed to overwrite with ?replace")
2537
2607
  elif bos.path.exists(abspath):
@@ -2541,16 +2611,6 @@ class HttpCli(object):
2541
2611
  except:
2542
2612
  t = "toctou while deleting for ?replace: %s"
2543
2613
  self.log(t % (abspath,))
2544
-
2545
- # reserve destination filename
2546
- with ren_open(fname, "wb", fdir=fdir, suffix=suffix) as zfw:
2547
- fname = zfw["orz"][1]
2548
-
2549
- tnam = fname + ".PARTIAL"
2550
- if self.args.dotpart:
2551
- tnam = "." + tnam
2552
-
2553
- abspath = os.path.join(fdir, fname)
2554
2614
  else:
2555
2615
  open_args = {}
2556
2616
  tnam = fname = os.devnull
@@ -2558,23 +2618,65 @@ class HttpCli(object):
2558
2618
 
2559
2619
  if xbu:
2560
2620
  at = time.time() - lifetime
2561
- if not runhook(
2621
+ hr = runhook(
2562
2622
  self.log,
2623
+ self.conn.hsrv.broker,
2624
+ None,
2625
+ "xbu.http.bup",
2563
2626
  xbu,
2564
2627
  abspath,
2565
- self.vpath,
2628
+ vjoin(upload_vpath, fname),
2566
2629
  self.host,
2567
2630
  self.uname,
2568
- self.asrv.vfs.get_perms(self.vpath, self.uname),
2631
+ self.asrv.vfs.get_perms(upload_vpath, self.uname),
2569
2632
  at,
2570
2633
  0,
2571
2634
  self.ip,
2572
2635
  at,
2573
2636
  "",
2574
- ):
2637
+ )
2638
+ if not hr:
2575
2639
  t = "upload blocked by xbu server config"
2576
2640
  self.log(t, 1)
2577
2641
  raise Pebkac(403, t)
2642
+ if hr.get("reloc"):
2643
+ zs = vjoin(upload_vpath, fname)
2644
+ x = pathmod(self.asrv.vfs, abspath, zs, hr["reloc"])
2645
+ if x:
2646
+ if self.args.hook_v:
2647
+ log_reloc(
2648
+ self.log,
2649
+ hr["reloc"],
2650
+ x,
2651
+ abspath,
2652
+ zs,
2653
+ fname,
2654
+ vfs,
2655
+ rem,
2656
+ )
2657
+ fdir, upload_vpath, fname, (vfs, rem) = x
2658
+ abspath = os.path.join(fdir, fname)
2659
+ if nullwrite:
2660
+ fdir = abspath = ""
2661
+ else:
2662
+ open_args["fdir"] = fdir
2663
+
2664
+ if p_file and not nullwrite:
2665
+ bos.makedirs(fdir)
2666
+
2667
+ # reserve destination filename
2668
+ with ren_open(fname, "wb", fdir=fdir, suffix=suffix) as zfw:
2669
+ fname = zfw["orz"][1]
2670
+
2671
+ tnam = fname + ".PARTIAL"
2672
+ if self.args.dotpart:
2673
+ tnam = "." + tnam
2674
+
2675
+ abspath = os.path.join(fdir, fname)
2676
+ else:
2677
+ open_args = {}
2678
+ tnam = fname = os.devnull
2679
+ fdir = abspath = ""
2578
2680
 
2579
2681
  if lim:
2580
2682
  lim.chk_bup(self.ip)
@@ -2618,29 +2720,58 @@ class HttpCli(object):
2618
2720
 
2619
2721
  tabspath = ""
2620
2722
 
2723
+ at = time.time() - lifetime
2724
+ if xau:
2725
+ hr = runhook(
2726
+ self.log,
2727
+ self.conn.hsrv.broker,
2728
+ None,
2729
+ "xau.http.bup",
2730
+ xau,
2731
+ abspath,
2732
+ vjoin(upload_vpath, fname),
2733
+ self.host,
2734
+ self.uname,
2735
+ self.asrv.vfs.get_perms(upload_vpath, self.uname),
2736
+ at,
2737
+ sz,
2738
+ self.ip,
2739
+ at,
2740
+ "",
2741
+ )
2742
+ if not hr:
2743
+ t = "upload blocked by xau server config"
2744
+ self.log(t, 1)
2745
+ wunlink(self.log, abspath, vfs.flags)
2746
+ raise Pebkac(403, t)
2747
+ if hr.get("reloc"):
2748
+ zs = vjoin(upload_vpath, fname)
2749
+ x = pathmod(self.asrv.vfs, abspath, zs, hr["reloc"])
2750
+ if x:
2751
+ if self.args.hook_v:
2752
+ log_reloc(
2753
+ self.log,
2754
+ hr["reloc"],
2755
+ x,
2756
+ abspath,
2757
+ zs,
2758
+ fname,
2759
+ vfs,
2760
+ rem,
2761
+ )
2762
+ fdir, upload_vpath, fname, (vfs, rem) = x
2763
+ ap2 = os.path.join(fdir, fname)
2764
+ if nullwrite:
2765
+ fdir = ap2 = ""
2766
+ else:
2767
+ bos.makedirs(fdir)
2768
+ atomic_move(self.log, abspath, ap2, vfs.flags)
2769
+ abspath = ap2
2770
+ sz = bos.path.getsize(abspath)
2771
+
2621
2772
  files.append(
2622
2773
  (sz, sha_hex, sha_b64, p_file or "(discarded)", fname, abspath)
2623
2774
  )
2624
- at = time.time() - lifetime
2625
- if xau and not runhook(
2626
- self.log,
2627
- xau,
2628
- abspath,
2629
- self.vpath,
2630
- self.host,
2631
- self.uname,
2632
- self.asrv.vfs.get_perms(self.vpath, self.uname),
2633
- at,
2634
- sz,
2635
- self.ip,
2636
- at,
2637
- "",
2638
- ):
2639
- t = "upload blocked by xau server config"
2640
- self.log(t, 1)
2641
- wunlink(self.log, abspath, vfs.flags)
2642
- raise Pebkac(403, t)
2643
-
2644
2775
  dbv, vrem = vfs.get_dbv(rem)
2645
2776
  self.conn.hsrv.broker.say(
2646
2777
  "up2k.hash_file",
@@ -2696,13 +2827,14 @@ class HttpCli(object):
2696
2827
  for sz, sha_hex, sha_b64, ofn, lfn, ap in files:
2697
2828
  vsuf = ""
2698
2829
  if (self.can_read or self.can_upget) and "fk" in vfs.flags:
2830
+ st = bos.stat(ap)
2699
2831
  alg = 2 if "fka" in vfs.flags else 1
2700
2832
  vsuf = "?k=" + self.gen_fk(
2701
2833
  alg,
2702
2834
  self.args.fk_salt,
2703
2835
  ap,
2704
- sz,
2705
- 0 if ANYWIN or not ap else bos.stat(ap).st_ino,
2836
+ st.st_size,
2837
+ 0 if ANYWIN or not ap else st.st_ino,
2706
2838
  )[: vfs.flags["fk"]]
2707
2839
 
2708
2840
  if "media" in self.uparam or "medialinks" in vfs.flags:
@@ -2869,6 +3001,9 @@ class HttpCli(object):
2869
3001
  if xbu:
2870
3002
  if not runhook(
2871
3003
  self.log,
3004
+ self.conn.hsrv.broker,
3005
+ None,
3006
+ "xbu.http.txt",
2872
3007
  xbu,
2873
3008
  fp,
2874
3009
  self.vpath,
@@ -2908,6 +3043,9 @@ class HttpCli(object):
2908
3043
  xau = vfs.flags.get("xau")
2909
3044
  if xau and not runhook(
2910
3045
  self.log,
3046
+ self.conn.hsrv.broker,
3047
+ None,
3048
+ "xau.http.txt",
2911
3049
  xau,
2912
3050
  fp,
2913
3051
  self.vpath,
@@ -2948,7 +3086,7 @@ class HttpCli(object):
2948
3086
  return True
2949
3087
 
2950
3088
  def _chk_lastmod(self, file_ts ) :
2951
- file_lastmod = formatdate(file_ts, usegmt=True)
3089
+ file_lastmod = formatdate(file_ts)
2952
3090
  cli_lastmod = self.headers.get("if-modified-since")
2953
3091
  if cli_lastmod:
2954
3092
  try:
@@ -3030,8 +3168,8 @@ class HttpCli(object):
3030
3168
  for n, fn in enumerate([".prologue.html", ".epilogue.html"]):
3031
3169
  if lnames is not None and fn not in lnames:
3032
3170
  continue
3033
- fn = os.path.join(abspath, fn)
3034
- if bos.path.exists(fn):
3171
+ fn = "%s/%s" % (abspath, fn)
3172
+ if bos.path.isfile(fn):
3035
3173
  with open(fsenc(fn), "rb") as f:
3036
3174
  logues[n] = f.read().decode("utf-8")
3037
3175
  if "exp" in vn.flags:
@@ -3049,7 +3187,7 @@ class HttpCli(object):
3049
3187
  fns = []
3050
3188
 
3051
3189
  for fn in fns:
3052
- fn = os.path.join(abspath, fn)
3190
+ fn = "%s/%s" % (abspath, fn)
3053
3191
  if bos.path.isfile(fn):
3054
3192
  with open(fsenc(fn), "rb") as f:
3055
3193
  readme = f.read().decode("utf-8")
@@ -3584,7 +3722,7 @@ class HttpCli(object):
3584
3722
  # (useragent-sniffing kinshi due to caching proxies)
3585
3723
  mime, ico = self.ico.get(txt, not small, "raster" in self.uparam)
3586
3724
 
3587
- lm = formatdate(self.E.t0, usegmt=True)
3725
+ lm = formatdate(self.E.t0)
3588
3726
  self.reply(ico, mime=mime, headers={"Last-Modified": lm})
3589
3727
  return True
3590
3728
 
@@ -3663,6 +3801,11 @@ class HttpCli(object):
3663
3801
  "arg_base": arg_base,
3664
3802
  }
3665
3803
 
3804
+ if self.args.js_other and "js" not in targs:
3805
+ zs = self.args.js_other
3806
+ zs += "&" if "?" in zs else "?"
3807
+ targs["js"] = zs
3808
+
3666
3809
  zfv = self.vn.flags.get("html_head")
3667
3810
  if zfv:
3668
3811
  targs["this"] = self
@@ -4140,7 +4283,7 @@ class HttpCli(object):
4140
4283
  if self.args.no_mv:
4141
4284
  raise Pebkac(403, "the rename/move feature is disabled in server config")
4142
4285
 
4143
- x = self.conn.hsrv.broker.ask("up2k.handle_mv", self.uname, vsrc, vdst)
4286
+ x = self.conn.hsrv.broker.ask("up2k.handle_mv", self.uname, self.ip, vsrc, vdst)
4144
4287
  self.loud_reply(x.get(), status=201)
4145
4288
  return True
4146
4289
 
copyparty/httpconn.py CHANGED
@@ -9,6 +9,9 @@ import threading # typechk
9
9
  import time
10
10
 
11
11
  try:
12
+ if os.environ.get("PRTY_NO_TLS"):
13
+ raise Exception()
14
+
12
15
  HAVE_SSL = True
13
16
  import ssl
14
17
  except:
copyparty/httpsrv.py CHANGED
@@ -12,7 +12,7 @@ import time
12
12
 
13
13
  import queue
14
14
 
15
- from .__init__ import ANYWIN, CORES, EXE, MACOS, TYPE_CHECKING, EnvParams, unicode
15
+ from .__init__ import ANYWIN, CORES, EXE, MACOS, PY2, TYPE_CHECKING, EnvParams, unicode
16
16
 
17
17
  try:
18
18
  MNFE = ModuleNotFoundError
@@ -81,6 +81,13 @@ if TYPE_CHECKING:
81
81
  from .broker_util import BrokerCli
82
82
  from .ssdp import SSDPr
83
83
 
84
+ if PY2:
85
+ range = xrange # type: ignore
86
+
87
+ if not hasattr(socket, "AF_UNIX"):
88
+ setattr(socket, "AF_UNIX", -9001)
89
+
90
+
84
91
  class HttpSrv(object):
85
92
  """
86
93
  handles incoming connections using HttpConn to process http,
@@ -236,15 +243,24 @@ class HttpSrv(object):
236
243
  return
237
244
 
238
245
  def listen(self, sck , nlisteners ) :
246
+ tcp = sck.family != socket.AF_UNIX
247
+
239
248
  if self.args.j != 1:
240
249
  # lost in the pickle; redefine
241
250
  if not ANYWIN or self.args.reuseaddr:
242
251
  sck.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
243
252
 
244
- sck.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1)
253
+ if tcp:
254
+ sck.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1)
255
+
245
256
  sck.settimeout(None) # < does not inherit, ^ opts above do
246
257
 
247
- ip, port = sck.getsockname()[:2]
258
+ if tcp:
259
+ ip, port = sck.getsockname()[:2]
260
+ else:
261
+ ip = re.sub(r"\.[0-9]+$", "", sck.getsockname().split("/")[-1])
262
+ port = 0
263
+
248
264
  self.srvs.append(sck)
249
265
  self.bound.add((ip, port))
250
266
  self.nclimax = math.ceil(self.args.nc * 1.0 / nlisteners)
@@ -256,10 +272,19 @@ class HttpSrv(object):
256
272
 
257
273
  def thr_listen(self, srv_sck ) :
258
274
  """listens on a shared tcp server"""
259
- ip, port = srv_sck.getsockname()[:2]
260
275
  fno = srv_sck.fileno()
261
- hip = "[{}]".format(ip) if ":" in ip else ip
262
- msg = "subscribed @ {}:{} f{} p{}".format(hip, port, fno, os.getpid())
276
+ if srv_sck.family == socket.AF_UNIX:
277
+ ip = re.sub(r"\.[0-9]+$", "", srv_sck.getsockname())
278
+ msg = "subscribed @ %s f%d p%d" % (ip, fno, os.getpid())
279
+ ip = ip.split("/")[-1]
280
+ port = 0
281
+ tcp = False
282
+ else:
283
+ tcp = True
284
+ ip, port = srv_sck.getsockname()[:2]
285
+ hip = "[%s]" % (ip,) if ":" in ip else ip
286
+ msg = "subscribed @ %s:%d f%d p%d" % (hip, port, fno, os.getpid())
287
+
263
288
  self.log(self.name, msg)
264
289
 
265
290
  Daemon(self.broker.say, "sig-hsrv-up1", ("cb_httpsrv_up",))
@@ -331,11 +356,13 @@ class HttpSrv(object):
331
356
 
332
357
  try:
333
358
  sck, saddr = srv_sck.accept()
334
- cip = unicode(saddr[0])
335
- if cip.startswith("::ffff:"):
336
- cip = cip[7:]
337
-
338
- addr = (cip, saddr[1])
359
+ if tcp:
360
+ cip = unicode(saddr[0])
361
+ if cip.startswith("::ffff:"):
362
+ cip = cip[7:]
363
+ addr = (cip, saddr[1])
364
+ else:
365
+ addr = (ip, sck.fileno())
339
366
  except (OSError, socket.error) as ex:
340
367
  if self.stopping:
341
368
  break
copyparty/ico.py CHANGED
@@ -74,7 +74,7 @@ class Ico(object):
74
74
  try:
75
75
  _, _, tw, th = pb.textbbox((0, 0), ext)
76
76
  except:
77
- tw, th = pb.textsize(ext)
77
+ tw, th = pb.textsize(ext) # type: ignore
78
78
 
79
79
  tw += len(ext)
80
80
  cw = tw // len(ext)