copyparty 1.18.4__py3-none-any.whl → 1.18.6__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/__main__.py CHANGED
@@ -539,14 +539,15 @@ def get_sects():
539
539
  when running behind a reverse-proxy, it's recommended to
540
540
  use unix-sockets for improved performance and security;
541
541
 
542
- \033[32m-i unix:770:www:\033[33m/tmp/a.sock\033[0m listens on \033[33m/tmp/a.sock\033[0m with
543
- permissions \033[33m0770\033[0m; only accessible to members of the \033[33mwww\033[0m
544
- group. This is the best approach. Alternatively,
542
+ \033[32m-i unix:770:www:\033[33m/dev/shm/party.sock\033[0m listens on
543
+ \033[33m/dev/shm/party.sock\033[0m with permissions \033[33m0770\033[0m;
544
+ only accessible to members of the \033[33mwww\033[0m group.
545
+ This is the best approach. Alternatively,
545
546
 
546
- \033[32m-i unix:777:\033[33m/tmp/a.sock\033[0m sets perms \033[33m0777\033[0m so anyone can
547
- access it; bad unless it's inside a restricted folder
547
+ \033[32m-i unix:777:\033[33m/dev/shm/party.sock\033[0m sets perms \033[33m0777\033[0m so anyone
548
+ can access it; bad unless it's inside a restricted folder
548
549
 
549
- \033[32m-i unix:\033[33m/tmp/a.sock\033[0m keeps umask-defined permissions
550
+ \033[32m-i unix:\033[33m/dev/shm/party.sock\033[0m keeps umask-defined permission
550
551
  (usually \033[33m0600\033[0m) and the same user/group as copyparty
551
552
 
552
553
  \033[33m-p\033[0m (tcp ports) is ignored for unix sockets
@@ -864,31 +865,31 @@ def get_sects():
864
865
 
865
866
  similarly, \033[33m--chmod-d\033[0m and \033[33mchmod_d\033[0m sets the directory/folder perm
866
867
 
867
- the value is a three-digit octal number such as 755, 750, 644, etc.
868
+ the value is a three-digit octal number such as \033[32m755\033[0m, \033[32m750\033[0m, \033[32m644\033[0m, etc.
868
869
 
869
870
  first digit = "User"; permission for the unix-user
870
871
  second digit = "Group"; permission for the unix-group
871
872
  third digit = "Other"; permission for all other users/groups
872
873
 
873
874
  for files:
874
- 0 = --- = no access
875
- 1 = --x = can execute the file as a program
876
- 2 = -w- = can write
877
- 3 = -wx = can write and execute
878
- 4 = r-- = can read
879
- 5 = r-x = can read and execute
880
- 6 = rw- = can read and write
881
- 7 = rwx = can read, write, execute
875
+ \033[32m0\033[0m = \033[35m---\033[0m = no access
876
+ \033[32m1\033[0m = \033[35m--x\033[0m = can execute the file as a program
877
+ \033[32m2\033[0m = \033[35m-w-\033[0m = can write
878
+ \033[32m3\033[0m = \033[35m-wx\033[0m = can write and execute
879
+ \033[32m4\033[0m = \033[35mr--\033[0m = can read
880
+ \033[32m5\033[0m = \033[35mr-x\033[0m = can read and execute
881
+ \033[32m6\033[0m = \033[35mrw-\033[0m = can read and write
882
+ \033[32m7\033[0m = \033[35mrwx\033[0m = can read, write, execute
882
883
 
883
884
  for directories/folders:
884
- 0 = --- = no access
885
- 1 = --x = can read files in folder but not list contents
886
- 2 = -w- = n/a
887
- 3 = -wx = can create files but not list
888
- 4 = r-- = can list, but not read/write
889
- 5 = r-x = can list and read files
890
- 6 = rw- = n/a
891
- 7 = rwx = can read, write, list
885
+ \033[32m0\033[0m = \033[35m---\033[0m = no access
886
+ \033[32m1\033[0m = \033[35m--x\033[0m = can read files in folder but not list contents
887
+ \033[32m2\033[0m = \033[35m-w-\033[0m = n/a
888
+ \033[32m3\033[0m = \033[35m-wx\033[0m = can create files but not list
889
+ \033[32m4\033[0m = \033[35mr--\033[0m = can list, but not read/write
890
+ \033[32m5\033[0m = \033[35mr-x\033[0m = can list and read files
891
+ \033[32m6\033[0m = \033[35mrw-\033[0m = n/a
892
+ \033[32m7\033[0m = \033[35mrwx\033[0m = can read, write, list
892
893
  """
893
894
  ),
894
895
  ],
@@ -1048,6 +1049,7 @@ def add_upload(ap):
1048
1049
  ap2.add_argument("--safe-dedup", metavar="N", type=int, default=50, help="how careful to be when deduplicating files; [\033[32m1\033[0m] = just verify the filesize, [\033[32m50\033[0m] = verify file contents have not been altered (volflag=safededup)")
1049
1050
  ap2.add_argument("--hardlink", action="store_true", help="enable hardlink-based dedup; will fallback on symlinks when that is impossible (across filesystems) (volflag=hardlink)")
1050
1051
  ap2.add_argument("--hardlink-only", action="store_true", help="do not fallback to symlinks when a hardlink cannot be made (volflag=hardlinkonly)")
1052
+ ap2.add_argument("--reflink", action="store_true", help="enable reflink-based dedup; will fallback on full copies when that is impossible (non-CoW filesystem) (volflag=reflink)")
1051
1053
  ap2.add_argument("--no-dupe", action="store_true", help="reject duplicate files during upload; only matches within the same volume (volflag=nodupe)")
1052
1054
  ap2.add_argument("--no-clone", action="store_true", help="do not use existing data on disk to satisfy dupe uploads; reduces server HDD reads in exchange for much more network load (volflag=noclone)")
1053
1055
  ap2.add_argument("--no-snap", action="store_true", help="disable snapshots -- forget unfinished uploads on shutdown; don't create .hist/up2k.snap files -- abandoned/interrupted uploads must be cleaned up manually")
@@ -1280,6 +1282,7 @@ def add_stats(ap):
1280
1282
  def add_yolo(ap):
1281
1283
  ap2 = ap.add_argument_group('yolo options')
1282
1284
  ap2.add_argument("--allow-csrf", action="store_true", help="disable csrf protections; let other domains/sites impersonate you through cross-site requests")
1285
+ ap2.add_argument("--cookie-lax", action="store_true", help="allow cookies from other domains (if you follow a link from another website into your server, you will arrive logged-in); this reduces protection against CSRF")
1283
1286
  ap2.add_argument("--getmod", action="store_true", help="permit ?move=[...] and ?delete as GET")
1284
1287
  ap2.add_argument("--wo-up-readme", action="store_true", help="allow users with write-only access to upload logues and readmes without adding the _wo_ filename prefix (volflag=wo_up_readme)")
1285
1288
 
@@ -1327,6 +1330,7 @@ def add_safety(ap):
1327
1330
  ap2.add_argument("--no-robots", action="store_true", help="adds http and html headers asking search engines to not index anything (volflag=norobots)")
1328
1331
  ap2.add_argument("--logout", metavar="H", type=float, default=8086.0, help="logout clients after \033[33mH\033[0m hours of inactivity; [\033[32m0.0028\033[0m]=10sec, [\033[32m0.1\033[0m]=6min, [\033[32m24\033[0m]=day, [\033[32m168\033[0m]=week, [\033[32m720\033[0m]=month, [\033[32m8760\033[0m]=year)")
1329
1332
  ap2.add_argument("--ban-pw", metavar="N,W,B", type=u, default="9,60,1440", help="more than \033[33mN\033[0m wrong passwords in \033[33mW\033[0m minutes = ban for \033[33mB\033[0m minutes; disable with [\033[32mno\033[0m]")
1333
+ ap2.add_argument("--ban-pwc", metavar="N,W,B", type=u, default="5,60,1440", help="more than \033[33mN\033[0m password-changes in \033[33mW\033[0m minutes = ban for \033[33mB\033[0m minutes; disable with [\033[32mno\033[0m]")
1330
1334
  ap2.add_argument("--ban-404", metavar="N,W,B", type=u, default="50,60,1440", help="hitting more than \033[33mN\033[0m 404's in \033[33mW\033[0m minutes = ban for \033[33mB\033[0m minutes; only affects users who cannot see directory listings because their access is either g/G/h")
1331
1335
  ap2.add_argument("--ban-403", metavar="N,W,B", type=u, default="9,2,1440", help="hitting more than \033[33mN\033[0m 403's in \033[33mW\033[0m minutes = ban for \033[33mB\033[0m minutes; [\033[32m1440\033[0m]=day, [\033[32m10080\033[0m]=week, [\033[32m43200\033[0m]=month")
1332
1336
  ap2.add_argument("--ban-422", metavar="N,W,B", type=u, default="9,2,1440", help="hitting more than \033[33mN\033[0m 422's in \033[33mW\033[0m minutes = ban for \033[33mB\033[0m minutes (invalid requests, attempted exploits ++)")
@@ -1557,7 +1561,7 @@ def add_ui(ap, retry):
1557
1561
  ap2.add_argument("--txt-max", metavar="KiB", type=int, default=64, help="max size of embedded textfiles on ?doc= (anything bigger will be lazy-loaded by JS)")
1558
1562
  ap2.add_argument("--doctitle", metavar="TXT", type=u, default="copyparty @ --name", help="title / service-name to show in html documents")
1559
1563
  ap2.add_argument("--bname", metavar="TXT", type=u, default="--name", help="server name (displayed in filebrowser document title)")
1560
- ap2.add_argument("--pb-url", metavar="URL", type=u, default=URL_PRJ, help="powered-by link; disable with \033[33m-np\033[0m")
1564
+ ap2.add_argument("--pb-url", metavar="URL", type=u, default=URL_PRJ, help="powered-by link; disable with \033[33m-nb\033[0m")
1561
1565
  ap2.add_argument("--ver", action="store_true", help="show version on the control panel (incompatible with \033[33m-nb\033[0m)")
1562
1566
  ap2.add_argument("--k304", metavar="NUM", type=int, default=0, help="configure the option to enable/disable k304 on the controlpanel (workaround for buggy reverse-proxies); [\033[32m0\033[0m] = hidden and default-off, [\033[32m1\033[0m] = visible and default-off, [\033[32m2\033[0m] = visible and default-on")
1563
1567
  ap2.add_argument("--no304", metavar="NUM", type=int, default=0, help="configure the option to enable/disable no304 on the controlpanel (workaround for buggy caching in browsers); [\033[32m0\033[0m] = hidden and default-off, [\033[32m1\033[0m] = visible and default-off, [\033[32m2\033[0m] = visible and default-on")
copyparty/__version__.py CHANGED
@@ -1,8 +1,8 @@
1
1
  # coding: utf-8
2
2
 
3
- VERSION = (1, 18, 4)
3
+ VERSION = (1, 18, 6)
4
4
  CODENAME = "logtail"
5
- BUILD_DT = (2025, 7, 25)
5
+ BUILD_DT = (2025, 7, 28)
6
6
 
7
7
  S_VERSION = ".".join(map(str, VERSION))
8
8
  S_BUILD_DT = "{0:04d}-{1:02d}-{2:02d}".format(*BUILD_DT)
copyparty/authsrv.py CHANGED
@@ -2115,6 +2115,7 @@ class AuthSrv(object):
2115
2115
  all_mte = {}
2116
2116
  errors = False
2117
2117
  free_umask = False
2118
+ have_reflink = False
2118
2119
  for vol in vfs.all_nodes.values():
2119
2120
  if (self.args.e2ds and vol.axs.uwrite) or self.args.e2dsa:
2120
2121
  vol.flags["e2ds"] = True
@@ -2198,6 +2199,9 @@ class AuthSrv(object):
2198
2199
  if "unlistcr" in vol.flags or "unlistcw" in vol.flags:
2199
2200
  self.args.have_unlistc = True
2200
2201
 
2202
+ if "reflink" in vol.flags:
2203
+ have_reflink = True
2204
+
2201
2205
  zs = str(vol.flags.get("tcolor", "")).lstrip("#")
2202
2206
  if len(zs) == 3: # fc5 => ffcc55
2203
2207
  vol.flags["tcolor"] = "".join([x * 2 for x in zs])
@@ -2562,6 +2566,13 @@ class AuthSrv(object):
2562
2566
  t = "WARNING! The following IdP volumes are mounted below another volume where other users can read and/or write files. This is a SECURITY HAZARD!! When copyparty is restarted, it will not know about these IdP volumes yet. These volumes will then be accessible by an unexpected set of permissions UNTIL one of the users associated with their volume sends a request to the server. RECOMMENDATION: You should create a restricted volume where nobody can read/write files, and make sure that all IdP volumes are configured to appear somewhere below that volume."
2563
2567
  self.log(t + "".join(self.idp_err), 1)
2564
2568
 
2569
+ if have_reflink:
2570
+ t = "WARNING: Reflink-based dedup was requested, but %s. This will not work; files will be full copies instead."
2571
+ if sys.version_info < (3, 14):
2572
+ self.log(t % "your python version is not new enough", 1)
2573
+ if not sys.platform.startswith("linux"):
2574
+ self.log(t % "your OS is not Linux", 1)
2575
+
2565
2576
  self.vfs = vfs
2566
2577
  self.acct = acct
2567
2578
  self.defpw = defpw
copyparty/cfg.py CHANGED
@@ -52,6 +52,7 @@ def vf_bmap() :
52
52
  "og_no_head",
53
53
  "og_s_title",
54
54
  "rand",
55
+ "reflink",
55
56
  "rmagic",
56
57
  "rss",
57
58
  "wo_up_readme",
@@ -168,6 +169,7 @@ flagcats = {
168
169
  "dedup": "enable symlink-based file deduplication",
169
170
  "hardlink": "enable hardlink-based file deduplication,\nwith fallback on symlinks when that is impossible",
170
171
  "hardlinkonly": "dedup with hardlink only, never symlink;\nmake a full copy if hardlink is impossible",
172
+ "reflink": "enable reflink-based file deduplication,\nwith fallback on full copy when that is impossible",
171
173
  "safededup": "verify on-disk data before using it for dedup",
172
174
  "noclone": "take dupe data from clients, even if available on HDD",
173
175
  "nodupe": "rejects existing files (instead of linking/cloning them)",
copyparty/httpcli.py CHANGED
@@ -2900,6 +2900,7 @@ class HttpCli(object):
2900
2900
 
2901
2901
  ok, msg = self.asrv.chpw(self.conn.hsrv.broker, self.uname, pwd)
2902
2902
  if ok:
2903
+ self.cbonk(self.conn.hsrv.gpwc, pwd, "pw", "too many password changes")
2903
2904
  ok, msg = self.get_pwd_cookie(pwd)
2904
2905
  if ok:
2905
2906
  msg = "new password OK"
@@ -2981,12 +2982,20 @@ class HttpCli(object):
2981
2982
  # reset both plaintext and tls
2982
2983
  # (only affects active tls cookies when tls)
2983
2984
  for k in ("cppwd", "cppws") if self.is_https else ("cppwd",):
2984
- ck = gencookie(k, pwd, self.args.R, False)
2985
+ ck = gencookie(k, pwd, self.args.R, self.args.cookie_lax, False)
2985
2986
  self.out_headerlist.append(("Set-Cookie", ck))
2986
2987
  self.out_headers.pop("Set-Cookie", None) # drop keepalive
2987
2988
  else:
2988
2989
  k = "cppws" if self.is_https else "cppwd"
2989
- ck = gencookie(k, pwd, self.args.R, self.is_https, dur, "; HttpOnly")
2990
+ ck = gencookie(
2991
+ k,
2992
+ pwd,
2993
+ self.args.R,
2994
+ self.args.cookie_lax,
2995
+ self.is_https,
2996
+ dur,
2997
+ "; HttpOnly",
2998
+ )
2990
2999
  self.out_headers["Set-Cookie"] = ck
2991
3000
 
2992
3001
  return dur > 0, msg
@@ -3002,6 +3011,9 @@ class HttpCli(object):
3002
3011
  self.gctx = vpath
3003
3012
  vpath = undot(vpath)
3004
3013
  vfs, rem = self.asrv.vfs.get(vpath, self.uname, False, True)
3014
+ if "nosub" in vfs.flags:
3015
+ raise Pebkac(403, "mkdir is forbidden below this folder")
3016
+
3005
3017
  rem = sanitize_vpath(rem, "/")
3006
3018
  fn = vfs.canonical(rem)
3007
3019
 
@@ -4843,13 +4855,21 @@ class HttpCli(object):
4843
4855
  def tx_svcs(self) :
4844
4856
  aname = re.sub("[^0-9a-zA-Z]+", "", self.args.vname) or "a"
4845
4857
  ep = self.host
4846
- host = ep.split(":")[0]
4847
- hport = ep[ep.find(":") :] if ":" in ep else ""
4848
- rip = (
4849
- host
4850
- if self.args.rclone_mdns or not self.args.zm
4851
- else self.conn.hsrv.nm.map(self.ip) or host
4852
- )
4858
+ sep = "]:" if "]" in ep else ":"
4859
+ if sep in ep:
4860
+ host, hport = ep.rsplit(":", 1)
4861
+ hport = ":" + hport
4862
+ else:
4863
+ host = ep
4864
+ hport = ""
4865
+
4866
+ if host.endswith(".local") and self.args.zm and not self.args.rclone_mdns:
4867
+ rip = self.conn.hsrv.nm.map(self.ip) or host
4868
+ if ":" in rip and "[" not in rip:
4869
+ rip = "[%s]" % (rip,)
4870
+ else:
4871
+ rip = host
4872
+
4853
4873
  # safer than html_escape/quotep since this avoids both XSS and shell-stuff
4854
4874
  pw = re.sub(r"[<>&$?`\"']", "_", self.pw or "hunter2")
4855
4875
  vp = re.sub(r"[<>&$?`\"']", "_", self.uparam["hc"] or "").lstrip("/")
@@ -5018,7 +5038,7 @@ class HttpCli(object):
5018
5038
  def setck(self) :
5019
5039
  k, v = self.uparam["setck"].split("=", 1)
5020
5040
  t = 0 if v in ("", "x") else 86400 * 299
5021
- ck = gencookie(k, v, self.args.R, False, t)
5041
+ ck = gencookie(k, v, self.args.R, self.args.cookie_lax, False, t)
5022
5042
  self.out_headerlist.append(("Set-Cookie", ck))
5023
5043
  if "cc" in self.ouparam:
5024
5044
  self.redirect("", "?h#cc")
@@ -5030,7 +5050,7 @@ class HttpCli(object):
5030
5050
  for k in ALL_COOKIES:
5031
5051
  if k not in self.cookies:
5032
5052
  continue
5033
- cookie = gencookie(k, "x", self.args.R, False)
5053
+ cookie = gencookie(k, "x", self.args.R, self.args.cookie_lax, False)
5034
5054
  self.out_headerlist.append(("Set-Cookie", cookie))
5035
5055
 
5036
5056
  self.redirect("", "?h#cc")
copyparty/httpsrv.py CHANGED
@@ -120,6 +120,7 @@ class HttpSrv(object):
120
120
  self.nm = NetMap([], [])
121
121
  self.ssdp = None
122
122
  self.gpwd = Garda(self.args.ban_pw)
123
+ self.gpwc = Garda(self.args.ban_pwc)
123
124
  self.g404 = Garda(self.args.ban_404)
124
125
  self.g403 = Garda(self.args.ban_403)
125
126
  self.g422 = Garda(self.args.ban_422, False)
copyparty/mtag.py CHANGED
@@ -160,12 +160,13 @@ def au_unpk(
160
160
  znil = [x for x in znil if "cover" in x[0]] or znil
161
161
  znil = [x for x in znil if CBZ_01.search(x[0])] or znil
162
162
  t = "cbz: %d files, %d hits" % (nf, len(znil))
163
+ using = sorted(znil)[0][1].filename
163
164
  if znil:
164
- t += ", using " + znil[0][1].filename
165
+ t += ", using " + using
165
166
  log(t)
166
167
  if not znil:
167
168
  raise Exception("no images inside cbz")
168
- fi = zf.open(znil[0][1])
169
+ fi = zf.open(using)
169
170
 
170
171
  else:
171
172
  raise Exception("unknown compression %s" % (pk,))
copyparty/svchub.py CHANGED
@@ -162,6 +162,7 @@ class SvcHub(object):
162
162
  # for non-http clients (ftp, tftp)
163
163
  self.bans = {}
164
164
  self.gpwd = Garda(self.args.ban_pw)
165
+ self.gpwc = Garda(self.args.ban_pwc)
165
166
  self.g404 = Garda(self.args.ban_404)
166
167
  self.g403 = Garda(self.args.ban_403)
167
168
  self.g422 = Garda(self.args.ban_422, False)
copyparty/up2k.py CHANGED
@@ -3460,6 +3460,8 @@ class Up2k(object):
3460
3460
 
3461
3461
  linked = False
3462
3462
  try:
3463
+ if "reflink" in flags:
3464
+ raise Exception("reflink")
3463
3465
  if not is_mv and not flags.get("dedup"):
3464
3466
  raise Exception("dedup is disabled in config")
3465
3467
 
@@ -3516,7 +3518,8 @@ class Up2k(object):
3516
3518
 
3517
3519
  linked = True
3518
3520
  except Exception as ex:
3519
- self.log("cannot link; creating copy: " + repr(ex))
3521
+ if str(ex) != "reflink":
3522
+ self.log("cannot link; creating copy: " + repr(ex))
3520
3523
  if bos.path.isfile(src):
3521
3524
  csrc = src
3522
3525
  elif fsrc and bos.path.isfile(fsrc):
copyparty/util.py CHANGED
@@ -1951,15 +1951,25 @@ def formatdate(ts = None) :
1951
1951
  return RFC2822 % (WKDAYS[wd], d, MONTHS[mo - 1], y, h, mi, s)
1952
1952
 
1953
1953
 
1954
- def gencookie(k , v , r , tls , dur = 0, txt = "") :
1954
+ def gencookie(
1955
+ k , v , r , lax , tls , dur = 0, txt = ""
1956
+ ) :
1955
1957
  v = v.replace("%", "%25").replace(";", "%3B")
1956
1958
  if dur:
1957
1959
  exp = formatdate(time.time() + dur)
1958
1960
  else:
1959
1961
  exp = "Fri, 15 Aug 1997 01:00:00 GMT"
1960
1962
 
1961
- t = "%s=%s; Path=/%s; Expires=%s%s%s; SameSite=Lax"
1962
- return t % (k, v, r, exp, "; Secure" if tls else "", txt)
1963
+ t = "%s=%s; Path=/%s; Expires=%s%s%s; SameSite=%s"
1964
+ return t % (
1965
+ k,
1966
+ v,
1967
+ r,
1968
+ exp,
1969
+ "; Secure" if tls else "",
1970
+ txt,
1971
+ "Lax" if lax else "Strict",
1972
+ )
1963
1973
 
1964
1974
 
1965
1975
  def humansize(sz , terse = False) :
Binary file
copyparty/web/svcs.html CHANGED
@@ -36,7 +36,7 @@
36
36
  <span class="os lin mac">
37
37
  {% if accs %}<code><b id="pw0">{{ pw }}</b></code>=password, {% endif %}<code><b>mp</b></code>=mountpoint
38
38
  </span>
39
- <a href="#" id="setpw">use real password</a>
39
+ {% if accs %}<a href="#" id="setpw">use real password</a>{% endif %}
40
40
  </p>
41
41
 
42
42
 
copyparty/web/svcs.js.gz CHANGED
Binary file
copyparty/web/util.js.gz CHANGED
Binary file
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: copyparty
3
- Version: 1.18.4
3
+ Version: 1.18.6
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
@@ -70,7 +70,7 @@ turn almost any device into a file server with resumable uploads/downloads using
70
70
 
71
71
  📷 **screenshots:** [browser](#the-browser) // [upload](#uploading) // [unpost](#unpost) // [thumbnails](#thumbnails) // [search](#searching) // [fsearch](#file-search) // [zip-DL](#zip-downloads) // [md-viewer](#markdown-viewer)
72
72
 
73
- 🎬 **videos:** [upload](https://a.ocv.me/pub/demo/pics-vids/up2k.webm) // [cli-upload](https://a.ocv.me/pub/demo/pics-vids/u2cli.webm) // [race-the-beam](https://a.ocv.me/pub/g/nerd-stuff/cpp/2024-0418-race-the-beam.webm)
73
+ 🎬 **videos:** [upload](https://a.ocv.me/pub/demo/pics-vids/up2k.webm) // [cli-upload](https://a.ocv.me/pub/demo/pics-vids/u2cli.webm) // [race-the-beam](https://a.ocv.me/pub/g/nerd-stuff/cpp/2024-0418-race-the-beam.webm) // 👉 **[feature-showcase](https://a.ocv.me/pub/demo/showcase-hq.webm)** ([youtube](https://www.youtube.com/watch?v=15_-hgsX2V0))
74
74
 
75
75
  made in Norway 🇳🇴
76
76
 
@@ -1497,12 +1497,17 @@ if you enable deduplication with `--dedup` then it'll create a symlink instead o
1497
1497
  **warning:** when enabling dedup, you should also:
1498
1498
  * enable indexing with `-e2dsa` or volflag `e2dsa` (see [file indexing](#file-indexing) section below); strongly recommended
1499
1499
  * ...and/or `--hardlink-only` to use hardlink-based deduplication instead of symlinks; see explanation below
1500
+ * ...and/or `--reflink` to use CoW/reflink-based dedup (much safer than hardlink, but OS/FS-dependent)
1500
1501
 
1501
1502
  it will not be safe to rename/delete files if you only enable dedup and none of the above; if you enable indexing then it is not *necessary* to also do hardlinks (but you may still want to)
1502
1503
 
1503
1504
  by default, deduplication is done based on symlinks (symbolic links); these are tiny files which are pointers to the nearest full copy of the file
1504
1505
 
1505
- you can choose to use hardlinks instead of softlinks, globally with `--hardlink-only` or volflag `hardlinkonly`;
1506
+ you can choose to use hardlinks instead of softlinks, globally with `--hardlink-only` or volflag `hardlinkonly`, and you can choose to use reflinks with `--reflink` or volflag `reflink`
1507
+
1508
+ advantages of using reflinks (CoW, copy-on-write):
1509
+ * entirely safe (when your filesystem supports it correctly); either file can be edited or deleted without affecting other copies
1510
+ * only linux 5.3 or newer, only python 3.14 or newer, only some filesystems (btrfs probably ok, maybe xfs too, but zfs had bugs)
1506
1511
 
1507
1512
  advantages of using hardlinks:
1508
1513
  * hardlinks are more compatible with other software; they behave entirely like regular files
@@ -2080,7 +2085,7 @@ some reverse proxies (such as [Caddy](https://caddyserver.com/)) can automatical
2080
2085
  * **warning:** nginx-QUIC (HTTP/3) is still experimental and can make uploads much slower, so HTTP/1.1 is recommended for now
2081
2086
  * depending on server/client, HTTP/1.1 can also be 5x faster than HTTP/2
2082
2087
 
2083
- 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)
2088
+ for improved security (and a 10% performance boost) consider listening on a unix-socket with `-i unix:770:www:/dev/shm/party.sock` (permission `770` means only members of group `www` can access it)
2084
2089
 
2085
2090
  example webserver / reverse-proxy configs:
2086
2091
 
@@ -2301,7 +2306,7 @@ NOTE: there used to be an aur package; this evaporated when copyparty was adopte
2301
2306
 
2302
2307
  ## fedora package
2303
2308
 
2304
- does not exist yet; using the [copr-pypi](https://copr.fedorainfracloud.org/coprs/g/copr/PyPI/) builds is **NOT recommended** because updates can be delayed by [several months](https://github.com/fedora-copr/copr/issues/3056)
2309
+ does not exist yet; there are rumours that it is being packaged! keep an eye on this space...
2305
2310
 
2306
2311
 
2307
2312
  ## nix package
@@ -1,38 +1,38 @@
1
1
  copyparty/__init__.py,sha256=4aJw_Mt3eSNMV8sJ95Nh4ris-tBUYhCOV094Rnxa5Xo,2651
2
- copyparty/__main__.py,sha256=rfSaVAHy9NpF6U-dWu4NS6zab96v7DLnG95M7WRXyxo,126024
3
- copyparty/__version__.py,sha256=VYBE-faUq6KuT0awfdhYnaqRvlnX2Tni0a63zOMGx_A,249
4
- copyparty/authsrv.py,sha256=PDX6-ob-vqpKE8XkMCEph662EE4Mp8IKbtIEZUKk5IM,120514
2
+ copyparty/__main__.py,sha256=Cy0ivEsRSPkVaXVLN8MAb0eXoqAWUimJtpAlfkFfiAQ,127229
3
+ copyparty/__version__.py,sha256=_F7FWcR2IUumXhoBLRfrzOu5Lo_sQzMEt-ZOMo5BN_k,249
4
+ copyparty/authsrv.py,sha256=dF1K3Tx5Semm6JWJAPr3Nv-H6LzpH_lPvoHYYvVDE1U,120995
5
5
  copyparty/broker_mp.py,sha256=QdOXXvV2Xn6J0CysEqyY3GZbqxQMyWnTpnba-a5lMc0,4987
6
6
  copyparty/broker_mpw.py,sha256=PpSS4SK3pItlpfD8OwVr3QmJEPKlUgaf2nuMOozixgU,3347
7
7
  copyparty/broker_thr.py,sha256=fjoYtpSscUA7-nMl4r1n2R7UK3J9lrvLS3rUZ-iJzKQ,1721
8
8
  copyparty/broker_util.py,sha256=76mfnFOpX1gUUvtjm8UQI7jpTIaVINX10QonM-B7ggc,1680
9
9
  copyparty/cert.py,sha256=pSSeVYticrDsnsrdRtfpUQN-8WRObsqrYtSRroXmgxo,7992
10
- copyparty/cfg.py,sha256=O2jhYbt7WV9X80_Av1f7r4u1JVi7U5Z_cLgSGhpipLg,15423
10
+ copyparty/cfg.py,sha256=nP8SVI3DMuhmbG1xSHex-965KmhDwI6G1kLqa28nZas,15557
11
11
  copyparty/dxml.py,sha256=vu5uZQtwvwoqnFHbULs2Zh_y2DETu0T-ENpMZ1i2CV4,2505
12
12
  copyparty/fsutil.py,sha256=NC_CJC4TDag399vVDH9_uQfdfpTMwRFLNxERSWhlVvs,4594
13
13
  copyparty/ftpd.py,sha256=xDDWixo5O2HT8wlexXQ0QRazU_fYERIJ4yF0mtu9wD0,18141
14
- copyparty/httpcli.py,sha256=ZNwaI4DVM6ljDz5ALRVuk07qG19i66_CLm9h6eARTSA,230544
14
+ copyparty/httpcli.py,sha256=O6YnFXBKYt17Y4SpGOR-wezrFrQHvzrQ_ywKvpKN7Lo,231164
15
15
  copyparty/httpconn.py,sha256=IA9fdCjigawZ4kWhgvVN3nSiy5pb3W2qaE6rFqUYdq0,6943
16
- copyparty/httpsrv.py,sha256=x6dl6ZjpwYREbm-eJZYnwdkhDeCA58hw_iwUMCD1Wz8,18819
16
+ copyparty/httpsrv.py,sha256=MCNjOEH_xM2qXCLGcoN6W0RhWlikv68-zBx0nICIheU,18864
17
17
  copyparty/ico.py,sha256=-7QjF_jIxnPo4Vr0oUPksQ_U_Ef0HRsSPm3s71idOz8,3879
18
18
  copyparty/mdns.py,sha256=G73OWWg1copda47LgayCRK7qjVrk6cnUGpMR5ugmi7o,18315
19
19
  copyparty/metrics.py,sha256=1dim0ShnsD5cfspRbeN9Mt14wOIxPRtxCZY2IScikKw,8974
20
- copyparty/mtag.py,sha256=7lINRFc1Vrc-ebP2hU3dBHH3BRFOnEmEZ0jzlpYb8Jg,19910
20
+ copyparty/mtag.py,sha256=ljqkiUblKzmLF6NVSXBRcFvy61j8QdVOjXToi2xQcyM,19939
21
21
  copyparty/multicast.py,sha256=Me4XEEJijvvK2lMRwmGU2hsaI5_E9AEpCjIC4b9UefA,12393
22
22
  copyparty/pwhash.py,sha256=zHoz9FHGkFBxoRvSfG1XyjN3ibww_h5GE6_m5yS-fws,4246
23
23
  copyparty/smbd.py,sha256=jeKGkVLG9-Q0zPNDZdIwb_O59388rvGzG2cQQ2qPXpk,14659
24
24
  copyparty/ssdp.py,sha256=R1Z61GZOxBMF2Sk4RTxKWMOemogmcjEWG-CvLihd45k,7023
25
25
  copyparty/star.py,sha256=tV5BbX6AiQ7N4UU8DYtSTckNYeoeey4DBqq4LjfymbY,3818
26
26
  copyparty/sutil.py,sha256=E65jAaOzHlJYnqsOKDMPVT8kALPUVexpkSStWBdItkY,3231
27
- copyparty/svchub.py,sha256=M7UnnqNUtVz5DQRYMHcmmyvDDtPzXKAOrW-XgJWfujc,49038
27
+ copyparty/svchub.py,sha256=x64KviAMgIoo60L49D4qxij0Npb5pyUjuofpOjTV4o0,49083
28
28
  copyparty/szip.py,sha256=9srQzjsTBrBadf6QMh4YRAL70rkZLevAOHqXWK5jvr8,8846
29
29
  copyparty/tcpsrv.py,sha256=BCOqlT_mRu1ibHJpPzvf9c4h83AnIMEfd8nBBednCCg,20484
30
30
  copyparty/tftpd.py,sha256=sNBMqazIB37t3jwhv_F1tr0lHFsiRX-nCsICM8nbkvc,14170
31
31
  copyparty/th_cli.py,sha256=IEX5tCb0gw9Z2aRIDL9bwdvJ6g5jhWZ8OEAAz16_xN4,5426
32
32
  copyparty/th_srv.py,sha256=INLaV1_NH1VKtBx9XaqyJbZNAj2ZhfcQwz0_5Y5fyiY,32744
33
33
  copyparty/u2idx.py,sha256=4Y5OOPyVkc-pS0z6e3p4StXAMnjHobSOMmMsvNUTD34,13674
34
- copyparty/up2k.py,sha256=S-SPTzLqxFvgSkFsWHqJwgUeT7QguLZgdZMQIh5eWiU,178957
35
- copyparty/util.py,sha256=p4Z2JHjIKWo-x5RS1kQl5qBG5T_E1FUV2pRfukAdyzA,104391
34
+ copyparty/up2k.py,sha256=6VjhlYG3jDTqjdFmrQRtrV_fpzeK3L9K-OEcYU3Mo9I,179076
35
+ copyparty/util.py,sha256=AtY7rVW64F6xJ00FbM7f43YBiVI6ctjtjUeb6zahAeY,104493
36
36
  copyparty/bos/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
37
37
  copyparty/bos/bos.py,sha256=ZwpTla_mFpoN_BbGn9h0dEn7wpZ607QJ7uYyxWJMcmw,1953
38
38
  copyparty/bos/path.py,sha256=yEjCq2ki9CvxA5sCT8pS0keEXwugs0ZeUyUhdBziOCI,777
@@ -57,7 +57,7 @@ copyparty/stolen/ifaddr/_win32.py,sha256=EE-QyoBgeB7lYQ6z62VjXNaRozaYfCkaJBHGNA8
57
57
  copyparty/web/baguettebox.js.gz,sha256=MxRofvhXjmUN7RtXtC17_9AlROVNUT-66WwJ_pHLY9c,8258
58
58
  copyparty/web/browser.css.gz,sha256=29D3F4uB-VMd6uJo-SxWAwLfn08jcETYZm0SOJFJLAE,11847
59
59
  copyparty/web/browser.html,sha256=auvhLVE_t0aIN0q-nk0zOWFqITgDhroMAAviBNLoFfc,4788
60
- copyparty/web/browser.js.gz,sha256=EZ58H7mtO6VEjeNxU5ZOlbelSRTuc_-JAmAGd3S11aY,96694
60
+ copyparty/web/browser.js.gz,sha256=CUpLvqCMFQXpRFf_T15Ie0tJsCqmdJzJK-HYdD6Ea_o,96908
61
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
@@ -81,11 +81,11 @@ copyparty/web/shares.js.gz,sha256=emeY2-wjkh8x1JgaW6ny5fcC7XpZzZzfE1f-sEyntQ4,94
81
81
  copyparty/web/splash.css.gz,sha256=S8_A7JJl71xACRBYGzafeaD82OacW6Fa7oKPiNyrhAs,1087
82
82
  copyparty/web/splash.html,sha256=0MvDe1lKfGqczi7d4nKjWjG0cRVyvs8J6sDEj3DCPSI,6376
83
83
  copyparty/web/splash.js.gz,sha256=xMl4Rly-ykhTx7LCI2MK1DpCblFWmFU9uA1rgivgen8,2771
84
- copyparty/web/svcs.html,sha256=cxgrhX9wD0Z_kvidry3aS9ubuGXYDj2f4ehq1X8T1EA,14227
85
- copyparty/web/svcs.js.gz,sha256=lMXEP9W-VlXyANlva4q0ASSxvvHYlE2CrmxGgZXZop0,713
84
+ copyparty/web/svcs.html,sha256=wiwcbmGi3vypVdVtD2FXYJYLGoExqLacRzJjBNKyBpE,14251
85
+ copyparty/web/svcs.js.gz,sha256=AYatNKyT_bKRWX8sb3WD_iujBY3L4P7HWBrsuMctsLs,722
86
86
  copyparty/web/ui.css.gz,sha256=e3iIflzddmjoyPrun_1jsu9j7fbdonNQLyhEE2oKKOQ,2819
87
87
  copyparty/web/up2k.js.gz,sha256=_uOZzORAFO91SG3TUHd9xhKhAIXwL3fUFBNEUKnEVHY,24812
88
- copyparty/web/util.js.gz,sha256=qa1B5w3bW7NNOTtuiiiL1ZWboqD9YVNZMKn3y1mf-oU,15247
88
+ copyparty/web/util.js.gz,sha256=zC_5OONJOR2g33uVlyn4GufUWIOvVZCleUY-VW3lnTc,15327
89
89
  copyparty/web/w.hash.js.gz,sha256=cFH6Xo4YRgH9Wr7RmHMSEfpuTmmIvEmzmSvv4RLmyPU,1193
90
90
  copyparty/web/a/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
91
91
  copyparty/web/a/partyfuse.py,sha256=9p5Hpg_IBiSimv7j9kmPhCGpy-FLXSRUOYnLjJ5JifU,28049
@@ -110,9 +110,9 @@ copyparty/web/deps/prismd.css.gz,sha256=ObUlksQVr-OuYlTz-I4B23TeBg2QDVVGRnWBz8cV
110
110
  copyparty/web/deps/scp.woff2,sha256=w99BDU5i8MukkMEL-iW0YO9H4vFFZSPWxbkH70ytaAg,8612
111
111
  copyparty/web/deps/sha512.ac.js.gz,sha256=lFZaCLumgWxrvEuDr4bqdKHsqjX82AbVAb7_F45Yk88,7033
112
112
  copyparty/web/deps/sha512.hw.js.gz,sha256=UAed2_ocklZCnIzcSYz2h4P1ycztlCLj-ewsRTud2lU,7939
113
- copyparty-1.18.4.dist-info/licenses/LICENSE,sha256=gOr4h33pCsBEg9uIy9AYmb7qlocL4V9t2uPJS5wllr0,1072
114
- copyparty-1.18.4.dist-info/METADATA,sha256=4D8UUVWS75gzR3fW8ngJNPa_TNcGz8Dmci1CF_OHzq8,166420
115
- copyparty-1.18.4.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
116
- copyparty-1.18.4.dist-info/entry_points.txt,sha256=4zw6a3rqASywQomiYLObjjlxybaI65LYYOTJwgKz7b0,128
117
- copyparty-1.18.4.dist-info/top_level.txt,sha256=LnYUPsDyk-8kFgM6YJLG4h820DQekn81cObKSu9g-sI,10
118
- copyparty-1.18.4.dist-info/RECORD,,
113
+ copyparty-1.18.6.dist-info/licenses/LICENSE,sha256=gOr4h33pCsBEg9uIy9AYmb7qlocL4V9t2uPJS5wllr0,1072
114
+ copyparty-1.18.6.dist-info/METADATA,sha256=reukmKR4ZWFmItgVokiPVrt_WeE-bBIQD9Se71FLRDA,166911
115
+ copyparty-1.18.6.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
116
+ copyparty-1.18.6.dist-info/entry_points.txt,sha256=4zw6a3rqASywQomiYLObjjlxybaI65LYYOTJwgKz7b0,128
117
+ copyparty-1.18.6.dist-info/top_level.txt,sha256=LnYUPsDyk-8kFgM6YJLG4h820DQekn81cObKSu9g-sI,10
118
+ copyparty-1.18.6.dist-info/RECORD,,