copyparty 1.13.3__py3-none-any.whl → 1.13.5__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/httpcli.py CHANGED
@@ -644,6 +644,7 @@ class HttpCli(object):
644
644
 
645
645
  em = str(ex)
646
646
  msg = em if pex is ex else min_ex()
647
+
647
648
  if pex.code != 404 or self.do_log:
648
649
  self.log(
649
650
  "%s\033[0m, %s" % (msg, self.vpath),
@@ -691,6 +692,7 @@ class HttpCli(object):
691
692
  self.vpath,
692
693
  self.host,
693
694
  self.uname,
695
+ "",
694
696
  time.time(),
695
697
  0,
696
698
  self.ip,
@@ -1627,6 +1629,7 @@ class HttpCli(object):
1627
1629
  self.vpath,
1628
1630
  self.host,
1629
1631
  self.uname,
1632
+ self.asrv.vfs.get_perms(self.vpath, self.uname),
1630
1633
  time.time(),
1631
1634
  len(buf),
1632
1635
  self.ip,
@@ -1670,6 +1673,8 @@ class HttpCli(object):
1670
1673
  remains = int(self.headers.get("content-length", -1))
1671
1674
  if remains == -1:
1672
1675
  self.keepalive = False
1676
+ self.in_hdr_recv = True
1677
+ self.s.settimeout(max(self.args.s_tbody // 20, 1))
1673
1678
  return read_socket_unbounded(self.sr, bufsz), remains
1674
1679
  else:
1675
1680
  return read_socket(self.sr, bufsz, remains), remains
@@ -1774,6 +1779,7 @@ class HttpCli(object):
1774
1779
  self.vpath,
1775
1780
  self.host,
1776
1781
  self.uname,
1782
+ self.asrv.vfs.get_perms(self.vpath, self.uname),
1777
1783
  at,
1778
1784
  remains,
1779
1785
  self.ip,
@@ -1864,6 +1870,7 @@ class HttpCli(object):
1864
1870
  self.vpath,
1865
1871
  self.host,
1866
1872
  self.uname,
1873
+ self.asrv.vfs.get_perms(self.vpath, self.uname),
1867
1874
  mt,
1868
1875
  post_sz,
1869
1876
  self.ip,
@@ -1900,6 +1907,9 @@ class HttpCli(object):
1900
1907
  0 if ANYWIN else bos.stat(path).st_ino,
1901
1908
  )[: vfs.flags["fk"]]
1902
1909
 
1910
+ if "media" in self.uparam or "medialinks" in vfs.flags:
1911
+ vsuf += "&v" if vsuf else "?v"
1912
+
1903
1913
  vpath = "/".join([x for x in [vfs.vpath, rem, fn] if x])
1904
1914
  vpath = quotep(vpath)
1905
1915
 
@@ -2021,7 +2031,7 @@ class HttpCli(object):
2021
2031
 
2022
2032
  v = self.uparam[k]
2023
2033
 
2024
- if self._use_dirkey():
2034
+ if self._use_dirkey(self.vn, ""):
2025
2035
  vn = self.vn
2026
2036
  rem = self.rem
2027
2037
  else:
@@ -2185,33 +2195,39 @@ class HttpCli(object):
2185
2195
 
2186
2196
  def handle_post_binary(self) :
2187
2197
  try:
2188
- remains = int(self.headers["content-length"])
2198
+ postsize = remains = int(self.headers["content-length"])
2189
2199
  except:
2190
2200
  raise Pebkac(400, "you must supply a content-length for binary POST")
2191
2201
 
2192
2202
  try:
2193
- chash = self.headers["x-up2k-hash"]
2203
+ chashes = self.headers["x-up2k-hash"].split(",")
2194
2204
  wark = self.headers["x-up2k-wark"]
2195
2205
  except KeyError:
2196
2206
  raise Pebkac(400, "need hash and wark headers for binary POST")
2197
2207
 
2208
+ chashes = [x.strip() for x in chashes]
2209
+
2198
2210
  vfs, _ = self.asrv.vfs.get(self.vpath, self.uname, False, True)
2199
2211
  ptop = (vfs.dbv or vfs).realpath
2200
2212
 
2201
- x = self.conn.hsrv.broker.ask("up2k.handle_chunk", ptop, wark, chash)
2213
+ x = self.conn.hsrv.broker.ask("up2k.handle_chunks", ptop, wark, chashes)
2202
2214
  response = x.get()
2203
- chunksize, cstart, path, lastmod, sprs = response
2215
+ chunksize, cstarts, path, lastmod, sprs = response
2216
+ maxsize = chunksize * len(chashes)
2217
+ cstart0 = cstarts[0]
2204
2218
 
2205
2219
  try:
2206
2220
  if self.args.nw:
2207
2221
  path = os.devnull
2208
2222
 
2209
- if remains > chunksize:
2210
- raise Pebkac(400, "your chunk is too big to fit")
2211
-
2212
- self.log("writing {} #{} @{} len {}".format(path, chash, cstart, remains))
2223
+ if remains > maxsize:
2224
+ t = "your client is sending %d bytes which is too much (server expected %d bytes at most)"
2225
+ raise Pebkac(400, t % (remains, maxsize))
2213
2226
 
2214
- reader = read_socket(self.sr, self.args.s_rd_sz, remains)
2227
+ t = "writing %s %s+%d #%d+%d %s"
2228
+ chunkno = cstart0[0] // chunksize
2229
+ zs = " ".join([chashes[0][:15]] + [x[:9] for x in chashes[1:]])
2230
+ self.log(t % (path, cstart0, remains, chunkno, len(chashes), zs))
2215
2231
 
2216
2232
  f = None
2217
2233
  fpool = not self.args.no_fpool and sprs
@@ -2225,37 +2241,43 @@ class HttpCli(object):
2225
2241
  f = f or open(fsenc(path), "rb+", self.args.iobuf)
2226
2242
 
2227
2243
  try:
2228
- f.seek(cstart[0])
2229
- post_sz, _, sha_b64 = hashcopy(reader, f, self.args.s_wr_slp)
2244
+ for chash, cstart in zip(chashes, cstarts):
2245
+ f.seek(cstart[0])
2246
+ reader = read_socket(
2247
+ self.sr, self.args.s_rd_sz, min(remains, chunksize)
2248
+ )
2249
+ post_sz, _, sha_b64 = hashcopy(reader, f, self.args.s_wr_slp)
2230
2250
 
2231
- if sha_b64 != chash:
2232
- try:
2233
- self.bakflip(f, cstart[0], post_sz, sha_b64, vfs.flags)
2234
- except:
2235
- self.log("bakflip failed: " + min_ex())
2251
+ if sha_b64 != chash:
2252
+ try:
2253
+ self.bakflip(f, cstart[0], post_sz, sha_b64, vfs.flags)
2254
+ except:
2255
+ self.log("bakflip failed: " + min_ex())
2236
2256
 
2237
- t = "your chunk got corrupted somehow (received {} bytes); expected vs received hash:\n{}\n{}"
2238
- raise Pebkac(400, t.format(post_sz, chash, sha_b64))
2257
+ t = "your chunk got corrupted somehow (received {} bytes); expected vs received hash:\n{}\n{}"
2258
+ raise Pebkac(400, t.format(post_sz, chash, sha_b64))
2239
2259
 
2240
- if len(cstart) > 1 and path != os.devnull:
2241
- self.log(
2242
- "clone {} to {}".format(
2243
- cstart[0], " & ".join(unicode(x) for x in cstart[1:])
2260
+ remains -= chunksize
2261
+
2262
+ if len(cstart) > 1 and path != os.devnull:
2263
+ self.log(
2264
+ "clone {} to {}".format(
2265
+ cstart[0], " & ".join(unicode(x) for x in cstart[1:])
2266
+ )
2244
2267
  )
2245
- )
2246
- ofs = 0
2247
- while ofs < chunksize:
2248
- bufsz = max(4 * 1024 * 1024, self.args.iobuf)
2249
- bufsz = min(chunksize - ofs, bufsz)
2250
- f.seek(cstart[0] + ofs)
2251
- buf = f.read(bufsz)
2252
- for wofs in cstart[1:]:
2253
- f.seek(wofs + ofs)
2254
- f.write(buf)
2268
+ ofs = 0
2269
+ while ofs < chunksize:
2270
+ bufsz = max(4 * 1024 * 1024, self.args.iobuf)
2271
+ bufsz = min(chunksize - ofs, bufsz)
2272
+ f.seek(cstart[0] + ofs)
2273
+ buf = f.read(bufsz)
2274
+ for wofs in cstart[1:]:
2275
+ f.seek(wofs + ofs)
2276
+ f.write(buf)
2255
2277
 
2256
- ofs += len(buf)
2278
+ ofs += len(buf)
2257
2279
 
2258
- self.log("clone {} done".format(cstart[0]))
2280
+ self.log("clone {} done".format(cstart[0]))
2259
2281
 
2260
2282
  if not fpool:
2261
2283
  f.close()
@@ -2267,10 +2289,10 @@ class HttpCli(object):
2267
2289
  f.close()
2268
2290
  raise
2269
2291
  finally:
2270
- x = self.conn.hsrv.broker.ask("up2k.release_chunk", ptop, wark, chash)
2292
+ x = self.conn.hsrv.broker.ask("up2k.release_chunks", ptop, wark, chashes)
2271
2293
  x.get() # block client until released
2272
2294
 
2273
- x = self.conn.hsrv.broker.ask("up2k.confirm_chunk", ptop, wark, chash)
2295
+ x = self.conn.hsrv.broker.ask("up2k.confirm_chunks", ptop, wark, chashes)
2274
2296
  ztis = x.get()
2275
2297
  try:
2276
2298
  num_left, fin_path = ztis
@@ -2289,7 +2311,7 @@ class HttpCli(object):
2289
2311
 
2290
2312
  cinf = self.headers.get("x-up2k-stat", "")
2291
2313
 
2292
- spd = self._spd(post_sz)
2314
+ spd = self._spd(postsize)
2293
2315
  self.log("{:70} thank {}".format(spd, cinf))
2294
2316
  self.reply(b"thank")
2295
2317
  return True
@@ -2543,6 +2565,7 @@ class HttpCli(object):
2543
2565
  self.vpath,
2544
2566
  self.host,
2545
2567
  self.uname,
2568
+ self.asrv.vfs.get_perms(self.vpath, self.uname),
2546
2569
  at,
2547
2570
  0,
2548
2571
  self.ip,
@@ -2606,6 +2629,7 @@ class HttpCli(object):
2606
2629
  self.vpath,
2607
2630
  self.host,
2608
2631
  self.uname,
2632
+ self.asrv.vfs.get_perms(self.vpath, self.uname),
2609
2633
  at,
2610
2634
  sz,
2611
2635
  self.ip,
@@ -2681,6 +2705,9 @@ class HttpCli(object):
2681
2705
  0 if ANYWIN or not ap else bos.stat(ap).st_ino,
2682
2706
  )[: vfs.flags["fk"]]
2683
2707
 
2708
+ if "media" in self.uparam or "medialinks" in vfs.flags:
2709
+ vsuf += "&v" if vsuf else "?v"
2710
+
2684
2711
  vpath = "{}/{}".format(upload_vpath, lfn).strip("/")
2685
2712
  rel_url = quotep(self.args.RS + vpath) + vsuf
2686
2713
  msg += 'sha512: {} // {} // {} bytes // <a href="/{}">{}</a> {}\n'.format(
@@ -2847,6 +2874,7 @@ class HttpCli(object):
2847
2874
  self.vpath,
2848
2875
  self.host,
2849
2876
  self.uname,
2877
+ self.asrv.vfs.get_perms(self.vpath, self.uname),
2850
2878
  time.time(),
2851
2879
  0,
2852
2880
  self.ip,
@@ -2885,6 +2913,7 @@ class HttpCli(object):
2885
2913
  self.vpath,
2886
2914
  self.host,
2887
2915
  self.uname,
2916
+ self.asrv.vfs.get_perms(self.vpath, self.uname),
2888
2917
  new_lastmod,
2889
2918
  sz,
2890
2919
  self.ip,
@@ -2939,22 +2968,24 @@ class HttpCli(object):
2939
2968
 
2940
2969
  return file_lastmod, True
2941
2970
 
2942
- def _use_dirkey(self, ap = "") :
2971
+ def _use_dirkey(self, vn , ap ) :
2943
2972
  if self.can_read or not self.can_get:
2944
2973
  return False
2945
2974
 
2946
- if self.vn.flags.get("dky"):
2975
+ if vn.flags.get("dky"):
2947
2976
  return True
2948
2977
 
2949
2978
  req = self.uparam.get("k") or ""
2950
2979
  if not req:
2951
2980
  return False
2952
2981
 
2953
- dk_len = self.vn.flags.get("dk")
2982
+ dk_len = vn.flags.get("dk")
2954
2983
  if not dk_len:
2955
2984
  return False
2956
2985
 
2957
- ap = ap or self.vn.canonical(self.rem)
2986
+ if not ap:
2987
+ ap = vn.canonical(self.rem)
2988
+
2958
2989
  zs = self.gen_fk(2, self.args.dk_salt, ap, 0, 0)[:dk_len]
2959
2990
  if req == zs:
2960
2991
  return True
@@ -2963,6 +2994,71 @@ class HttpCli(object):
2963
2994
  self.log(t % (zs, req, self.req, ap), 6)
2964
2995
  return False
2965
2996
 
2997
+ def _use_filekey(self, vn , ap , st ) :
2998
+ if self.can_read or not self.can_get:
2999
+ return False
3000
+
3001
+ req = self.uparam.get("k") or ""
3002
+ if not req:
3003
+ return False
3004
+
3005
+ fk_len = vn.flags.get("fk")
3006
+ if not fk_len:
3007
+ return False
3008
+
3009
+ if not ap:
3010
+ ap = self.vn.canonical(self.rem)
3011
+
3012
+ alg = 2 if "fka" in vn.flags else 1
3013
+
3014
+ zs = self.gen_fk(
3015
+ alg, self.args.fk_salt, ap, st.st_size, 0 if ANYWIN else st.st_ino
3016
+ )[:fk_len]
3017
+
3018
+ if req == zs:
3019
+ return True
3020
+
3021
+ t = "wrong filekey, want %s, got %s\n vp: %s\n ap: %s"
3022
+ self.log(t % (zs, req, self.req, ap), 6)
3023
+ return False
3024
+
3025
+ def _add_logues(
3026
+ self, vn , abspath , lnames
3027
+ ) :
3028
+ logues = ["", ""]
3029
+ if not self.args.no_logues:
3030
+ for n, fn in enumerate([".prologue.html", ".epilogue.html"]):
3031
+ if lnames is not None and fn not in lnames:
3032
+ continue
3033
+ fn = os.path.join(abspath, fn)
3034
+ if bos.path.exists(fn):
3035
+ with open(fsenc(fn), "rb") as f:
3036
+ logues[n] = f.read().decode("utf-8")
3037
+ if "exp" in vn.flags:
3038
+ logues[n] = self._expand(
3039
+ logues[n], vn.flags.get("exp_lg") or []
3040
+ )
3041
+
3042
+ readme = ""
3043
+ if not self.args.no_readme and not logues[1]:
3044
+ if lnames is None:
3045
+ fns = ["README.md", "readme.md"]
3046
+ elif "readme.md" in lnames:
3047
+ fns = [lnames["readme.md"]]
3048
+ else:
3049
+ fns = []
3050
+
3051
+ for fn in fns:
3052
+ fn = os.path.join(abspath, fn)
3053
+ if bos.path.isfile(fn):
3054
+ with open(fsenc(fn), "rb") as f:
3055
+ readme = f.read().decode("utf-8")
3056
+ break
3057
+ if readme and "exp" in vn.flags:
3058
+ readme = self._expand(readme, vn.flags.get("exp_md") or [])
3059
+
3060
+ return logues, readme
3061
+
2966
3062
  def _expand(self, txt , phs ) :
2967
3063
  for ph in phs:
2968
3064
  if ph.startswith("hdr."):
@@ -2992,6 +3088,7 @@ class HttpCli(object):
2992
3088
  logtail = ""
2993
3089
 
2994
3090
  if ptop is not None:
3091
+ ap_data = "<%s>" % (req_path,)
2995
3092
  try:
2996
3093
  dp, fn = os.path.split(req_path)
2997
3094
  tnam = fn + ".PARTIAL"
@@ -3338,7 +3435,16 @@ class HttpCli(object):
3338
3435
 
3339
3436
  if lower < upper and not broken:
3340
3437
  with open(req_path, "rb") as f:
3341
- remains = sendfile_py(self.log, lower, upper, f, self.s, wr_sz, wr_slp)
3438
+ remains = sendfile_py(
3439
+ self.log,
3440
+ lower,
3441
+ upper,
3442
+ f,
3443
+ self.s,
3444
+ wr_sz,
3445
+ wr_slp,
3446
+ not self.args.no_poll,
3447
+ )
3342
3448
 
3343
3449
  spd = self._spd((upper - lower) - remains)
3344
3450
  if self.do_log:
@@ -3850,7 +3956,7 @@ class HttpCli(object):
3850
3956
  dk_sz = False
3851
3957
  if dk:
3852
3958
  vn, rem = vfs.get(top, self.uname, False, False)
3853
- if vn.flags.get("dks") and self._use_dirkey(vn.canonical(rem)):
3959
+ if vn.flags.get("dks") and self._use_dirkey(vn, vn.canonical(rem)):
3854
3960
  dk_sz = vn.flags.get("dk")
3855
3961
 
3856
3962
  dots = False
@@ -4159,6 +4265,9 @@ class HttpCli(object):
4159
4265
  add_og = True
4160
4266
  og_fn = ""
4161
4267
 
4268
+ if "v" in self.uparam:
4269
+ add_og = og_ua = True
4270
+
4162
4271
  if "b" in self.uparam:
4163
4272
  self.out_headers["X-Robots-Tag"] = "noindex, nofollow"
4164
4273
 
@@ -4171,9 +4280,20 @@ class HttpCli(object):
4171
4280
  if idx and hasattr(idx, "p_end"):
4172
4281
  icur = idx.get_cur(dbv)
4173
4282
 
4283
+ if "k" in self.uparam or "dky" in vn.flags:
4284
+ if is_dir:
4285
+ use_dirkey = self._use_dirkey(vn, abspath)
4286
+ use_filekey = False
4287
+ else:
4288
+ use_filekey = self._use_filekey(vn, abspath, st)
4289
+ use_dirkey = False
4290
+ else:
4291
+ use_dirkey = use_filekey = False
4292
+
4174
4293
  th_fmt = self.uparam.get("th")
4175
4294
  if self.can_read or (
4176
- self.can_get and (vn.flags.get("dk") or "fk" not in vn.flags)
4295
+ self.can_get
4296
+ and (use_filekey or use_dirkey or (not is_dir and "fk" not in vn.flags))
4177
4297
  ):
4178
4298
  if th_fmt is not None:
4179
4299
  nothumb = "dthumb" in dbv.flags
@@ -4190,18 +4310,21 @@ class HttpCli(object):
4190
4310
  if cfn:
4191
4311
  fn = cfn[0]
4192
4312
  fp = os.path.join(abspath, fn)
4193
- if bos.path.exists(fp):
4194
- vrem = "{}/{}".format(vrem, fn).strip("/")
4195
- is_dir = False
4313
+ st = bos.stat(fp)
4314
+ vrem = "{}/{}".format(vrem, fn).strip("/")
4315
+ is_dir = False
4196
4316
  except:
4197
4317
  pass
4198
4318
  else:
4199
4319
  for fn in self.args.th_covers:
4200
4320
  fp = os.path.join(abspath, fn)
4201
- if bos.path.exists(fp):
4321
+ try:
4322
+ st = bos.stat(fp)
4202
4323
  vrem = "{}/{}".format(vrem, fn).strip("/")
4203
4324
  is_dir = False
4204
4325
  break
4326
+ except:
4327
+ pass
4205
4328
 
4206
4329
  if is_dir:
4207
4330
  return self.tx_svg("folder")
@@ -4253,21 +4376,10 @@ class HttpCli(object):
4253
4376
 
4254
4377
  if not is_dir and (self.can_read or self.can_get):
4255
4378
  if not self.can_read and not fk_pass and "fk" in vn.flags:
4256
- alg = 2 if "fka" in vn.flags else 1
4257
- correct = self.gen_fk(
4258
- alg,
4259
- self.args.fk_salt,
4260
- abspath,
4261
- st.st_size,
4262
- 0 if ANYWIN else st.st_ino,
4263
- )[: vn.flags["fk"]]
4264
- got = self.uparam.get("k")
4265
- if got != correct:
4266
- t = "wrong filekey, want %s, got %s\n vp: %s\n ap: %s"
4267
- self.log(t % (correct, got, self.req, abspath), 6)
4379
+ if not use_filekey:
4268
4380
  return self.tx_404()
4269
4381
 
4270
- if add_og:
4382
+ if add_og and not abspath.lower().endswith(".md"):
4271
4383
  if og_ua or self.host not in self.headers.get("referer", ""):
4272
4384
  self.vpath, og_fn = vsplit(self.vpath)
4273
4385
  vpath = self.vpath
@@ -4282,7 +4394,7 @@ class HttpCli(object):
4282
4394
  (abspath.endswith(".md") or self.can_delete)
4283
4395
  and "nohtml" not in vn.flags
4284
4396
  and (
4285
- "v" in self.uparam
4397
+ ("v" in self.uparam and abspath.endswith(".md"))
4286
4398
  or "edit" in self.uparam
4287
4399
  or "edit2" in self.uparam
4288
4400
  )
@@ -4295,7 +4407,7 @@ class HttpCli(object):
4295
4407
  )
4296
4408
 
4297
4409
  elif is_dir and not self.can_read:
4298
- if self._use_dirkey(abspath):
4410
+ if use_dirkey:
4299
4411
  is_dk = True
4300
4412
  elif not self.can_write:
4301
4413
  return self.tx_404(True)
@@ -4352,29 +4464,6 @@ class HttpCli(object):
4352
4464
  tpl = "browser2"
4353
4465
  is_js = False
4354
4466
 
4355
- logues = ["", ""]
4356
- if not self.args.no_logues:
4357
- for n, fn in enumerate([".prologue.html", ".epilogue.html"]):
4358
- fn = os.path.join(abspath, fn)
4359
- if bos.path.exists(fn):
4360
- with open(fsenc(fn), "rb") as f:
4361
- logues[n] = f.read().decode("utf-8")
4362
- if "exp" in vn.flags:
4363
- logues[n] = self._expand(
4364
- logues[n], vn.flags.get("exp_lg") or []
4365
- )
4366
-
4367
- readme = ""
4368
- if not self.args.no_readme and not logues[1]:
4369
- for fn in ["README.md", "readme.md"]:
4370
- fn = os.path.join(abspath, fn)
4371
- if bos.path.isfile(fn):
4372
- with open(fsenc(fn), "rb") as f:
4373
- readme = f.read().decode("utf-8")
4374
- break
4375
- if readme and "exp" in vn.flags:
4376
- readme = self._expand(readme, vn.flags.get("exp_md") or [])
4377
-
4378
4467
  vf = vn.flags
4379
4468
  unlist = vf.get("unlist", "")
4380
4469
  ls_ret = {
@@ -4393,8 +4482,6 @@ class HttpCli(object):
4393
4482
  "frand": bool(vn.flags.get("rand")),
4394
4483
  "unlist": unlist,
4395
4484
  "perms": perms,
4396
- "logues": logues,
4397
- "readme": readme,
4398
4485
  }
4399
4486
  cgv = {
4400
4487
  "ls0": None,
@@ -4412,8 +4499,8 @@ class HttpCli(object):
4412
4499
  "have_zip": (not self.args.no_zip),
4413
4500
  "have_unpost": int(self.args.unpost),
4414
4501
  "sb_md": "" if "no_sb_md" in vf else (vf.get("md_sbf") or "y"),
4415
- "readme": readme,
4416
4502
  "dgrid": "grid" in vf,
4503
+ "dgsel": "gsel" in vf,
4417
4504
  "dsort": vf["sort"],
4418
4505
  "dcrop": vf["crop"],
4419
4506
  "dth3x": vf["th3x"],
@@ -4421,6 +4508,7 @@ class HttpCli(object):
4421
4508
  "themes": self.args.themes,
4422
4509
  "turbolvl": self.args.turbo,
4423
4510
  "u2j": self.args.u2j,
4511
+ "u2sz": self.args.u2sz,
4424
4512
  "idxh": int(self.args.ih),
4425
4513
  "u2sort": self.args.u2sort,
4426
4514
  }
@@ -4434,7 +4522,6 @@ class HttpCli(object):
4434
4522
  "have_b_u": (self.can_write and self.uparam.get("b") == "u"),
4435
4523
  "sb_lg": "" if "no_sb_lg" in vf else (vf.get("lg_sbf") or "y"),
4436
4524
  "url_suf": url_suf,
4437
- "logues": logues,
4438
4525
  "title": html_escape("%s %s" % (self.args.bname, self.vpath), crlf=True),
4439
4526
  "srv_info": srv_infot,
4440
4527
  "dtheme": self.args.theme,
@@ -4454,6 +4541,10 @@ class HttpCli(object):
4454
4541
  j2a["no_prism"] = True
4455
4542
 
4456
4543
  if not self.can_read and not is_dk:
4544
+ logues, readme = self._add_logues(vn, abspath, None)
4545
+ ls_ret["logues"] = j2a["logues"] = logues
4546
+ ls_ret["readme"] = cgv["readme"] = readme
4547
+
4457
4548
  if is_ls:
4458
4549
  return self.tx_ls(ls_ret)
4459
4550
 
@@ -4510,6 +4601,8 @@ class HttpCli(object):
4510
4601
  ):
4511
4602
  ls_names = exclude_dotfiles(ls_names)
4512
4603
 
4604
+ lnames = {x.lower(): x for x in ls_names}
4605
+
4513
4606
  add_dk = vf.get("dk")
4514
4607
  add_fk = vf.get("fk")
4515
4608
  fk_alg = 2 if "fka" in vf else 1
@@ -4699,9 +4792,45 @@ class HttpCli(object):
4699
4792
  else:
4700
4793
  taglist = list(tagset)
4701
4794
 
4795
+ logues, readme = self._add_logues(vn, abspath, lnames)
4796
+ ls_ret["logues"] = j2a["logues"] = logues
4797
+ ls_ret["readme"] = cgv["readme"] = readme
4798
+
4702
4799
  if not files and not dirs and not readme and not logues[0] and not logues[1]:
4703
4800
  logues[1] = "this folder is empty"
4704
4801
 
4802
+ if "descript.ion" in lnames and os.path.isfile(
4803
+ os.path.join(abspath, lnames["descript.ion"])
4804
+ ):
4805
+ rem = []
4806
+ with open(os.path.join(abspath, lnames["descript.ion"]), "rb") as f:
4807
+ for bln in [x.strip() for x in f]:
4808
+ try:
4809
+ if bln.endswith(b"\x04\xc2"):
4810
+ # multiline comment; replace literal r"\n" with " // "
4811
+ bln = bln.replace(br"\\n", b" // ")[:-2]
4812
+ ln = bln.decode("utf-8", "replace")
4813
+ if ln.startswith('"'):
4814
+ fn, desc = ln.split('" ', 1)
4815
+ fn = fn[1:]
4816
+ else:
4817
+ fn, desc = ln.split(" ", 1)
4818
+ fe = next(
4819
+ (x for x in files if x["name"].lower() == fn.lower()), None
4820
+ )
4821
+ if fe:
4822
+ fe["tags"]["descript.ion"] = desc
4823
+ else:
4824
+ t = "<li><code>%s</code> %s</li>"
4825
+ rem.append(t % (html_escape(fn), html_escape(desc)))
4826
+ except:
4827
+ pass
4828
+ if "descript.ion" not in taglist:
4829
+ taglist.insert(0, "descript.ion")
4830
+ if rem and not logues[1]:
4831
+ t = "<h3>descript.ion</h3><ul>\n"
4832
+ logues[1] = t + "\n".join(rem) + "</ul>"
4833
+
4705
4834
  if is_ls:
4706
4835
  ls_ret["dirs"] = dirs
4707
4836
  ls_ret["files"] = files
@@ -4771,14 +4900,13 @@ class HttpCli(object):
4771
4900
  self.conn.hsrv.j2[tpl] = j2env.get_template(tname)
4772
4901
  thumb = ""
4773
4902
  is_pic = is_vid = is_au = False
4774
- covernames = self.args.th_coversd
4775
- for fn in ls_names:
4776
- if fn.lower() in covernames:
4777
- thumb = fn
4903
+ for fn in self.args.th_coversd:
4904
+ if fn in lnames:
4905
+ thumb = lnames[fn]
4778
4906
  break
4779
4907
  if og_fn:
4780
4908
  ext = og_fn.split(".")[-1].lower()
4781
- if ext in self.thumbcli.thumbable:
4909
+ if self.thumbcli and ext in self.thumbcli.thumbable:
4782
4910
  is_pic = (
4783
4911
  ext in self.thumbcli.fmt_pil
4784
4912
  or ext in self.thumbcli.fmt_vips
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
15
+ from .__init__ import ANYWIN, CORES, EXE, MACOS, TYPE_CHECKING, EnvParams, unicode
16
16
 
17
17
  try:
18
18
  MNFE = ModuleNotFoundError
@@ -331,11 +331,11 @@ class HttpSrv(object):
331
331
 
332
332
  try:
333
333
  sck, saddr = srv_sck.accept()
334
- cip, cport = saddr[:2]
334
+ cip = unicode(saddr[0])
335
335
  if cip.startswith("::ffff:"):
336
336
  cip = cip[7:]
337
337
 
338
- addr = (cip, cport)
338
+ addr = (cip, saddr[1])
339
339
  except (OSError, socket.error) as ex:
340
340
  if self.stopping:
341
341
  break
copyparty/mdns.py CHANGED
@@ -357,7 +357,7 @@ class MDNS(MCast):
357
357
  except:
358
358
  pass
359
359
 
360
- self.srv = {}
360
+ self.srv.clear()
361
361
 
362
362
  def eat(self, buf , addr , sck ) :
363
363
  cip = addr[0]
copyparty/mtag.py CHANGED
@@ -133,6 +133,9 @@ def au_unpk(
133
133
  zil = [x for x in zil if x.filename.lower().split(".")[-1] == au]
134
134
  fi = zf.open(zil[0])
135
135
 
136
+ else:
137
+ raise Exception("unknown compression %s" % (pk,))
138
+
136
139
  with os.fdopen(fd, "wb") as fo:
137
140
  while True:
138
141
  buf = fi.read(32768)
copyparty/smbd.py CHANGED
@@ -237,7 +237,7 @@ class SMB(object):
237
237
 
238
238
  xbu = vfs.flags.get("xbu")
239
239
  if xbu and not runhook(
240
- self.nlog, xbu, ap, vpath, "", "", 0, 0, "1.7.6.2", 0, ""
240
+ self.nlog, xbu, ap, vpath, "", "", "", 0, 0, "1.7.6.2", 0, ""
241
241
  ):
242
242
  yeet("blocked by xbu server config: " + vpath)
243
243