copyparty 1.19.1__py3-none-any.whl → 1.19.3__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 +116 -28
- copyparty/__version__.py +2 -2
- copyparty/authsrv.py +33 -7
- copyparty/cfg.py +7 -1
- copyparty/dxml.py +3 -0
- copyparty/ftpd.py +21 -6
- copyparty/httpcli.py +81 -16
- copyparty/httpsrv.py +6 -0
- copyparty/mtag.py +88 -6
- copyparty/svchub.py +76 -5
- copyparty/tcpsrv.py +6 -0
- copyparty/th_cli.py +5 -1
- copyparty/th_srv.py +160 -51
- copyparty/u2idx.py +1 -1
- copyparty/up2k.py +80 -39
- copyparty/util.py +25 -1
- copyparty/web/baguettebox.js.gz +0 -0
- copyparty/web/browser.css.gz +0 -0
- copyparty/web/browser.js.gz +0 -0
- copyparty/web/rups.js.gz +0 -0
- copyparty/web/splash.css.gz +0 -0
- copyparty/web/splash.html +8 -1
- copyparty/web/splash.js.gz +0 -0
- copyparty/web/svcs.html +1 -1
- copyparty/web/up2k.js.gz +0 -0
- copyparty/web/util.js.gz +0 -0
- {copyparty-1.19.1.dist-info → copyparty-1.19.3.dist-info}/METADATA +39 -3
- {copyparty-1.19.1.dist-info → copyparty-1.19.3.dist-info}/RECORD +32 -32
- {copyparty-1.19.1.dist-info → copyparty-1.19.3.dist-info}/WHEEL +0 -0
- {copyparty-1.19.1.dist-info → copyparty-1.19.3.dist-info}/entry_points.txt +0 -0
- {copyparty-1.19.1.dist-info → copyparty-1.19.3.dist-info}/licenses/LICENSE +0 -0
- {copyparty-1.19.1.dist-info → copyparty-1.19.3.dist-info}/top_level.txt +0 -0
copyparty/up2k.py
CHANGED
@@ -77,7 +77,7 @@ except:
|
|
77
77
|
if HAVE_SQLITE3:
|
78
78
|
import sqlite3
|
79
79
|
|
80
|
-
DB_VER =
|
80
|
+
DB_VER = 6
|
81
81
|
|
82
82
|
if TYPE_CHECKING:
|
83
83
|
from .svchub import SvcHub
|
@@ -141,6 +141,7 @@ class Up2k(object):
|
|
141
141
|
|
142
142
|
self.salt = self.args.warksalt
|
143
143
|
self.r_hash = re.compile("^[0-9a-zA-Z_-]{44}$")
|
144
|
+
self.abrt_key = ""
|
144
145
|
|
145
146
|
self.gid = 0
|
146
147
|
self.gt0 = 0
|
@@ -897,7 +898,7 @@ class Up2k(object):
|
|
897
898
|
self.iacct = self.asrv.iacct
|
898
899
|
self.grps = self.asrv.grps
|
899
900
|
|
900
|
-
have_e2d = self.args.
|
901
|
+
have_e2d = self.args.have_idp_hdrs or self.args.chpw or self.args.shr
|
901
902
|
vols = list(all_vols.values())
|
902
903
|
t0 = time.time()
|
903
904
|
|
@@ -1645,7 +1646,7 @@ class Up2k(object):
|
|
1645
1646
|
abspath = cdirs + fn
|
1646
1647
|
nohash = reh.search(abspath) if reh else False
|
1647
1648
|
|
1648
|
-
sql = "select w, mt, sz, ip, at from up where rd = ? and fn = ?"
|
1649
|
+
sql = "select w, mt, sz, ip, at, un from up where rd = ? and fn = ?"
|
1649
1650
|
try:
|
1650
1651
|
c = db.c.execute(sql, (rd, fn))
|
1651
1652
|
except:
|
@@ -1654,7 +1655,7 @@ class Up2k(object):
|
|
1654
1655
|
in_db = list(c.fetchall())
|
1655
1656
|
if in_db:
|
1656
1657
|
self.pp.n -= 1
|
1657
|
-
dw, dts, dsz, ip, at = in_db[0]
|
1658
|
+
dw, dts, dsz, ip, at, un = in_db[0]
|
1658
1659
|
if len(in_db) > 1:
|
1659
1660
|
t = "WARN: multiple entries: %r => %r |%d|\n%r"
|
1660
1661
|
rep_db = "\n".join([repr(x) for x in in_db])
|
@@ -1667,6 +1668,9 @@ class Up2k(object):
|
|
1667
1668
|
if dts == lmod and dsz == sz and (nohash or dw[0] != "#" or not sz):
|
1668
1669
|
continue
|
1669
1670
|
|
1671
|
+
if un is None:
|
1672
|
+
un = ""
|
1673
|
+
|
1670
1674
|
t = "reindex %r => %r mtime(%s/%s) size(%s/%s)"
|
1671
1675
|
self.log(t % (top, rp, dts, lmod, dsz, sz))
|
1672
1676
|
self.db_rm(db.c, rd, fn, 0)
|
@@ -1677,6 +1681,7 @@ class Up2k(object):
|
|
1677
1681
|
dw = ""
|
1678
1682
|
ip = ""
|
1679
1683
|
at = 0
|
1684
|
+
un = ""
|
1680
1685
|
|
1681
1686
|
self.pp.msg = "a%d %s" % (self.pp.n, abspath)
|
1682
1687
|
|
@@ -1702,9 +1707,10 @@ class Up2k(object):
|
|
1702
1707
|
if dw and dw != wark:
|
1703
1708
|
ip = ""
|
1704
1709
|
at = 0
|
1710
|
+
un = ""
|
1705
1711
|
|
1706
1712
|
# skip upload hooks by not providing vflags
|
1707
|
-
self.db_add(db.c, {}, rd, fn, lmod, sz, "", "", wark, wark, "",
|
1713
|
+
self.db_add(db.c, {}, rd, fn, lmod, sz, "", "", wark, wark, "", un, ip, at)
|
1708
1714
|
db.n += 1
|
1709
1715
|
db.nf += 1
|
1710
1716
|
tfa += 1
|
@@ -2140,8 +2146,8 @@ class Up2k(object):
|
|
2140
2146
|
|
2141
2147
|
with self.mutex:
|
2142
2148
|
try:
|
2143
|
-
q = "select rd, fn, ip, at from up where substr(w,1,16)=? and +w=?"
|
2144
|
-
rd, fn, ip, at = cur.execute(q, (w16, w)).fetchone()
|
2149
|
+
q = "select rd, fn, ip, at, un from up where substr(w,1,16)=? and +w=?"
|
2150
|
+
rd, fn, ip, at, un = cur.execute(q, (w16, w)).fetchone()
|
2145
2151
|
except:
|
2146
2152
|
# file modified/deleted since spooling
|
2147
2153
|
continue
|
@@ -2160,12 +2166,15 @@ class Up2k(object):
|
|
2160
2166
|
abspath = djoin(ptop, rd, fn)
|
2161
2167
|
self.pp.msg = "c%d %s" % (nq, abspath)
|
2162
2168
|
if not mpool:
|
2163
|
-
n_tags = self._tagscan_file(cur, entags, w, abspath, ip, at)
|
2169
|
+
n_tags = self._tagscan_file(cur, entags, w, abspath, ip, at, un)
|
2164
2170
|
else:
|
2171
|
+
oth_tags = {}
|
2165
2172
|
if ip:
|
2166
|
-
oth_tags
|
2167
|
-
|
2168
|
-
oth_tags =
|
2173
|
+
oth_tags["up_ip"] = ip
|
2174
|
+
if at:
|
2175
|
+
oth_tags["up_at"] = at
|
2176
|
+
if un:
|
2177
|
+
oth_tags["up_by"] = un
|
2169
2178
|
|
2170
2179
|
mpool.put(Mpqe({}, entags, w, abspath, oth_tags))
|
2171
2180
|
with self.mutex:
|
@@ -2321,8 +2330,8 @@ class Up2k(object):
|
|
2321
2330
|
if w in in_progress:
|
2322
2331
|
continue
|
2323
2332
|
|
2324
|
-
q = "select rd, fn, ip, at from up where substr(w,1,16)=? limit 1"
|
2325
|
-
rd, fn, ip, at = cur.execute(q, (w,)).fetchone()
|
2333
|
+
q = "select rd, fn, ip, at, un from up where substr(w,1,16)=? limit 1"
|
2334
|
+
rd, fn, ip, at, un = cur.execute(q, (w,)).fetchone()
|
2326
2335
|
rd, fn = s3dec(rd, fn)
|
2327
2336
|
abspath = djoin(ptop, rd, fn)
|
2328
2337
|
|
@@ -2346,7 +2355,10 @@ class Up2k(object):
|
|
2346
2355
|
|
2347
2356
|
if ip:
|
2348
2357
|
oth_tags["up_ip"] = ip
|
2358
|
+
if at:
|
2349
2359
|
oth_tags["up_at"] = at
|
2360
|
+
if un:
|
2361
|
+
oth_tags["up_by"] = un
|
2350
2362
|
|
2351
2363
|
jobs.append(Mpqe(parsers, set(), w, abspath, oth_tags))
|
2352
2364
|
in_progress[w] = True
|
@@ -2534,6 +2546,7 @@ class Up2k(object):
|
|
2534
2546
|
abspath ,
|
2535
2547
|
ip ,
|
2536
2548
|
at ,
|
2549
|
+
un ,
|
2537
2550
|
) :
|
2538
2551
|
"""will mutex(main)"""
|
2539
2552
|
|
@@ -2553,7 +2566,10 @@ class Up2k(object):
|
|
2553
2566
|
|
2554
2567
|
if ip:
|
2555
2568
|
tags["up_ip"] = ip
|
2569
|
+
if at:
|
2556
2570
|
tags["up_at"] = at
|
2571
|
+
if un:
|
2572
|
+
tags["up_by"] = un
|
2557
2573
|
|
2558
2574
|
with self.mutex:
|
2559
2575
|
return self._tag_file(write_cur, entags, wark, abspath, tags)
|
@@ -2655,16 +2671,19 @@ class Up2k(object):
|
|
2655
2671
|
if not existed and ver is None:
|
2656
2672
|
return self._try_create_db(db_path, cur)
|
2657
2673
|
|
2658
|
-
|
2674
|
+
for upver in (4, 5):
|
2675
|
+
if ver != upver:
|
2676
|
+
continue
|
2659
2677
|
try:
|
2660
2678
|
t = "creating backup before upgrade: "
|
2661
2679
|
cur = self._backup_db(db_path, cur, ver, t)
|
2662
|
-
self
|
2663
|
-
ver
|
2680
|
+
getattr(self, "_upgrade_v%d" % (upver,))(cur)
|
2681
|
+
ver += 1 # type: ignore
|
2664
2682
|
except:
|
2665
|
-
self.log("WARN: failed to upgrade from
|
2683
|
+
self.log("WARN: failed to upgrade from v%d" % (ver,), 3)
|
2666
2684
|
|
2667
2685
|
if ver == DB_VER:
|
2686
|
+
# these no longer serve their intended purpose but they're great as additional sanchks
|
2668
2687
|
self._add_dhash_tab(cur)
|
2669
2688
|
self._add_xiu_tab(cur)
|
2670
2689
|
self._add_cv_tab(cur)
|
@@ -2765,7 +2784,7 @@ class Up2k(object):
|
|
2765
2784
|
idx = r"create index up_w on up(w)"
|
2766
2785
|
|
2767
2786
|
for cmd in [
|
2768
|
-
r"create table up (w text, mt int, sz int, rd text, fn text, ip text, at int)",
|
2787
|
+
r"create table up (w text, mt int, sz int, rd text, fn text, ip text, at int, un text)",
|
2769
2788
|
r"create index up_vp on up(rd, fn)",
|
2770
2789
|
r"create index up_fn on up(fn)",
|
2771
2790
|
r"create index up_ip on up(ip)",
|
@@ -2798,6 +2817,15 @@ class Up2k(object):
|
|
2798
2817
|
|
2799
2818
|
cur.connection.commit()
|
2800
2819
|
|
2820
|
+
def _upgrade_v5(self, cur ) :
|
2821
|
+
for cmd in [
|
2822
|
+
r"alter table up add column un text",
|
2823
|
+
r"update kv set v=6 where k='sver'",
|
2824
|
+
]:
|
2825
|
+
cur.execute(cmd)
|
2826
|
+
|
2827
|
+
cur.connection.commit()
|
2828
|
+
|
2801
2829
|
def _add_dhash_tab(self, cur ) :
|
2802
2830
|
# v5 -> v5a
|
2803
2831
|
try:
|
@@ -2995,7 +3023,7 @@ class Up2k(object):
|
|
2995
3023
|
argv = [dwark[:16], dwark]
|
2996
3024
|
|
2997
3025
|
c2 = cur.execute(q, tuple(argv))
|
2998
|
-
for _, dtime, dsize, dp_dir, dp_fn, ip, at in c2:
|
3026
|
+
for _, dtime, dsize, dp_dir, dp_fn, ip, at, _ in c2:
|
2999
3027
|
if dp_dir.startswith("//") or dp_fn.startswith("//"):
|
3000
3028
|
dp_dir, dp_fn = s3dec(dp_dir, dp_fn)
|
3001
3029
|
|
@@ -3416,7 +3444,7 @@ class Up2k(object):
|
|
3416
3444
|
try:
|
3417
3445
|
vrel = vjoin(job["prel"], fname)
|
3418
3446
|
xlink = bool(vf.get("xlink"))
|
3419
|
-
cur, wark, _, _, _, _ = self._find_from_vpath(ptop, vrel)
|
3447
|
+
cur, wark, _, _, _, _, _ = self._find_from_vpath(ptop, vrel)
|
3420
3448
|
self._forget_file(ptop, vrel, cur, wark, True, st.st_size, xlink)
|
3421
3449
|
except Exception as ex:
|
3422
3450
|
self.log("skipping replace-relink: %r" % (ex,))
|
@@ -3870,13 +3898,13 @@ class Up2k(object):
|
|
3870
3898
|
# plugins may expect this to look like an actual IP
|
3871
3899
|
db_ip = "1.1.1.1" if "no_db_ip" in vflags else ip
|
3872
3900
|
|
3873
|
-
sql = "insert into up values (
|
3874
|
-
v = (dwark, int(ts), sz, rd, fn, db_ip, int(at or 0))
|
3901
|
+
sql = "insert into up values (?,?,?,?,?,?,?,?)"
|
3902
|
+
v = (dwark, int(ts), sz, rd, fn, db_ip, int(at or 0), usr)
|
3875
3903
|
try:
|
3876
3904
|
db.execute(sql, v)
|
3877
3905
|
except:
|
3878
3906
|
rd, fn = s3enc(self.mem_cur, rd, fn)
|
3879
|
-
v = (dwark, int(ts), sz, rd, fn, db_ip, int(at or 0))
|
3907
|
+
v = (dwark, int(ts), sz, rd, fn, db_ip, int(at or 0), usr)
|
3880
3908
|
db.execute(sql, v)
|
3881
3909
|
|
3882
3910
|
self.volsize[db] += sz
|
@@ -3967,6 +3995,9 @@ class Up2k(object):
|
|
3967
3995
|
except:
|
3968
3996
|
pass
|
3969
3997
|
|
3998
|
+
def handle_fs_abrt(self, akey ) :
|
3999
|
+
self.abrt_key = akey
|
4000
|
+
|
3970
4001
|
def handle_rm(
|
3971
4002
|
self,
|
3972
4003
|
uname ,
|
@@ -4013,7 +4044,7 @@ class Up2k(object):
|
|
4013
4044
|
vn, rem = vn0.get_dbv(rem0)
|
4014
4045
|
ptop = vn.realpath
|
4015
4046
|
with self.mutex, self.reg_mutex:
|
4016
|
-
abrt_cfg =
|
4047
|
+
abrt_cfg = vn.flags.get("u2abort", 1)
|
4017
4048
|
addr = (ip or "\n") if abrt_cfg in (1, 2) else ""
|
4018
4049
|
user = ((uname or "\n"), "*") if abrt_cfg in (1, 3) else None
|
4019
4050
|
reg = self.registry.get(ptop, {}) if abrt_cfg else {}
|
@@ -4034,17 +4065,22 @@ class Up2k(object):
|
|
4034
4065
|
if partial:
|
4035
4066
|
dip = ip
|
4036
4067
|
dat = time.time()
|
4068
|
+
dun = uname
|
4069
|
+
un_cfg = 1
|
4037
4070
|
else:
|
4038
|
-
|
4071
|
+
un_cfg = vn.flags["unp_who"]
|
4072
|
+
if not self.args.unpost or not un_cfg:
|
4039
4073
|
t = "the unpost feature is disabled in server config"
|
4040
4074
|
raise Pebkac(400, t)
|
4041
4075
|
|
4042
|
-
_, _, _, _, dip, dat = self._find_from_vpath(ptop, rem)
|
4076
|
+
_, _, _, _, dip, dat, dun = self._find_from_vpath(ptop, rem)
|
4043
4077
|
|
4044
4078
|
t = "you cannot delete this: "
|
4045
4079
|
if not dip:
|
4046
4080
|
t += "file not found"
|
4047
|
-
elif dip != ip:
|
4081
|
+
elif dip != ip and un_cfg in (1, 2):
|
4082
|
+
t += "not uploaded by (You)"
|
4083
|
+
elif dun != uname and un_cfg in (1, 3):
|
4048
4084
|
t += "not uploaded by (You)"
|
4049
4085
|
elif dat < time.time() - self.args.unpost:
|
4050
4086
|
t += "uploaded too long ago"
|
@@ -4133,7 +4169,7 @@ class Up2k(object):
|
|
4133
4169
|
try:
|
4134
4170
|
ptop = dbv.realpath
|
4135
4171
|
xlink = bool(dbv.flags.get("xlink"))
|
4136
|
-
cur, wark, _, _, _, _ = self._find_from_vpath(ptop, volpath)
|
4172
|
+
cur, wark, _, _, _, _, _ = self._find_from_vpath(ptop, volpath)
|
4137
4173
|
self._forget_file(
|
4138
4174
|
ptop, volpath, cur, wark, True, st.st_size, xlink
|
4139
4175
|
)
|
@@ -4176,7 +4212,7 @@ class Up2k(object):
|
|
4176
4212
|
|
4177
4213
|
return n_files, ok + ok2, ng + ng2
|
4178
4214
|
|
4179
|
-
def handle_cp(self, uname , ip , svp , dvp ) :
|
4215
|
+
def handle_cp(self, abrt , uname , ip , svp , dvp ) :
|
4180
4216
|
if svp == dvp or dvp.startswith(svp + "/"):
|
4181
4217
|
raise Pebkac(400, "cp: cannot copy parent into subfolder")
|
4182
4218
|
|
@@ -4223,6 +4259,8 @@ class Up2k(object):
|
|
4223
4259
|
|
4224
4260
|
dvpf = dvp + svpf[len(svp) :]
|
4225
4261
|
self._cp_file(uname, ip, svpf, dvpf, curs)
|
4262
|
+
if abrt and abrt == self.abrt_key:
|
4263
|
+
raise Pebkac(400, "filecopy aborted by http-api")
|
4226
4264
|
|
4227
4265
|
for v in curs:
|
4228
4266
|
v.connection.commit()
|
@@ -4292,7 +4330,7 @@ class Up2k(object):
|
|
4292
4330
|
|
4293
4331
|
bos.makedirs(os.path.dirname(dabs), vf=dvn.flags)
|
4294
4332
|
|
4295
|
-
c1, w, ftime_, fsize_, ip, at = self._find_from_vpath(
|
4333
|
+
c1, w, ftime_, fsize_, ip, at, un = self._find_from_vpath(
|
4296
4334
|
svn_dbv.realpath, srem_dbv
|
4297
4335
|
)
|
4298
4336
|
c2 = self.cur.get(dvn.realpath)
|
@@ -4316,7 +4354,7 @@ class Up2k(object):
|
|
4316
4354
|
w,
|
4317
4355
|
w,
|
4318
4356
|
"",
|
4319
|
-
"",
|
4357
|
+
un or "",
|
4320
4358
|
ip or "",
|
4321
4359
|
at or 0,
|
4322
4360
|
)
|
@@ -4389,7 +4427,7 @@ class Up2k(object):
|
|
4389
4427
|
|
4390
4428
|
return "k"
|
4391
4429
|
|
4392
|
-
def handle_mv(self, uname , ip , svp , dvp ) :
|
4430
|
+
def handle_mv(self, abrt , uname , ip , svp , dvp ) :
|
4393
4431
|
if svp == dvp or dvp.startswith(svp + "/"):
|
4394
4432
|
raise Pebkac(400, "mv: cannot move parent into subfolder")
|
4395
4433
|
|
@@ -4444,6 +4482,8 @@ class Up2k(object):
|
|
4444
4482
|
|
4445
4483
|
dvpf = dvp + svpf[len(svp) :]
|
4446
4484
|
self._mv_file(uname, ip, svpf, dvpf, curs)
|
4485
|
+
if abrt and abrt == self.abrt_key:
|
4486
|
+
raise Pebkac(400, "filemove aborted by http-api")
|
4447
4487
|
|
4448
4488
|
for v in curs:
|
4449
4489
|
v.connection.commit()
|
@@ -4575,7 +4615,7 @@ class Up2k(object):
|
|
4575
4615
|
|
4576
4616
|
return "k"
|
4577
4617
|
|
4578
|
-
c1, w, ftime_, fsize_, ip, at = self._find_from_vpath(svn.realpath, srem)
|
4618
|
+
c1, w, ftime_, fsize_, ip, at, un = self._find_from_vpath(svn.realpath, srem)
|
4579
4619
|
c2 = self.cur.get(dvn.realpath)
|
4580
4620
|
|
4581
4621
|
has_dupes = False
|
@@ -4608,7 +4648,7 @@ class Up2k(object):
|
|
4608
4648
|
w,
|
4609
4649
|
w,
|
4610
4650
|
"",
|
4611
|
-
"",
|
4651
|
+
un or "",
|
4612
4652
|
ip or "",
|
4613
4653
|
at or 0,
|
4614
4654
|
)
|
@@ -4708,13 +4748,14 @@ class Up2k(object):
|
|
4708
4748
|
|
4709
4749
|
|
4710
4750
|
|
4751
|
+
|
4711
4752
|
|
4712
4753
|
cur = self.cur.get(ptop)
|
4713
4754
|
if not cur:
|
4714
|
-
return None, None, None, None, "", None
|
4755
|
+
return None, None, None, None, "", None, ""
|
4715
4756
|
|
4716
4757
|
rd, fn = vsplit(vrem)
|
4717
|
-
q = "select w, mt, sz, ip, at from up where rd=? and fn=? limit 1"
|
4758
|
+
q = "select w, mt, sz, ip, at, un from up where rd=? and fn=? limit 1"
|
4718
4759
|
try:
|
4719
4760
|
c = cur.execute(q, (rd, fn))
|
4720
4761
|
except:
|
@@ -4722,9 +4763,9 @@ class Up2k(object):
|
|
4722
4763
|
|
4723
4764
|
hit = c.fetchone()
|
4724
4765
|
if hit:
|
4725
|
-
wark, ftime, fsize, ip, at = hit
|
4726
|
-
return cur, wark, ftime, fsize, ip, at
|
4727
|
-
return cur, None, None, None, "", None
|
4766
|
+
wark, ftime, fsize, ip, at, un = hit
|
4767
|
+
return cur, wark, ftime, fsize, ip, at, un
|
4768
|
+
return cur, None, None, None, "", None, ""
|
4728
4769
|
|
4729
4770
|
def _forget_file(
|
4730
4771
|
self,
|
copyparty/util.py
CHANGED
@@ -378,6 +378,9 @@ application swf=x-shockwave-flash m3u=vnd.apple.mpegurl db3=vnd.sqlite3 sqlite=v
|
|
378
378
|
text ass=plain ssa=plain
|
379
379
|
image jpg=jpeg xpm=x-xpixmap psd=vnd.adobe.photoshop jpf=jpx tif=tiff ico=x-icon djvu=vnd.djvu
|
380
380
|
image heic=heic-sequence heif=heif-sequence hdr=vnd.radiance svg=svg+xml
|
381
|
+
image arw=x-sony-arw cr2=x-canon-cr2 crw=x-canon-crw dcr=x-kodak-dcr dng=x-adobe-dng erf=x-epson-erf
|
382
|
+
image k25=x-kodak-k25 kdc=x-kodak-kdc mrw=x-minolta-mrw nef=x-nikon-nef orf=x-olympus-orf
|
383
|
+
image pef=x-pentax-pef raf=x-fuji-raf raw=x-panasonic-raw sr2=x-sony-sr2 srf=x-sony-srf x3f=x-sigma-x3f
|
381
384
|
audio caf=x-caf mp3=mpeg m4a=mp4 mid=midi mpc=musepack aif=aiff au=basic qcp=qcelp
|
382
385
|
video mkv=x-matroska mov=quicktime avi=x-msvideo m4v=x-m4v ts=mp2t
|
383
386
|
video asf=x-ms-asf flv=x-flv 3gp=3gpp 3g2=3gpp2 rmvb=vnd.rn-realmedia-vbr
|
@@ -2864,6 +2867,27 @@ def load_ipu(
|
|
2864
2867
|
return ip_u, nm
|
2865
2868
|
|
2866
2869
|
|
2870
|
+
def load_ipr(
|
2871
|
+
log , iprs , defer_mutex = False
|
2872
|
+
) :
|
2873
|
+
ret = {}
|
2874
|
+
for ipr in iprs:
|
2875
|
+
try:
|
2876
|
+
zs, uname = ipr.split("=")
|
2877
|
+
cidrs = zs.split(",")
|
2878
|
+
except:
|
2879
|
+
t = "\n invalid value %r for argument --ipr; must be CIDR[,CIDR[,...]]=UNAME (192.168.0.0/16=amelia)"
|
2880
|
+
raise Exception(t % (ipr,))
|
2881
|
+
try:
|
2882
|
+
nm = NetMap(["::"], cidrs, True, True, defer_mutex)
|
2883
|
+
except Exception as ex:
|
2884
|
+
t = "failed to translate --ipr into netmap, probably due to invalid config: %r"
|
2885
|
+
log("root", t % (ex,), 1)
|
2886
|
+
raise
|
2887
|
+
ret[uname] = nm
|
2888
|
+
return ret
|
2889
|
+
|
2890
|
+
|
2867
2891
|
def yieldfile(fn , bufsz ) :
|
2868
2892
|
readsz = min(bufsz, 128 * 1024)
|
2869
2893
|
with open(fsenc(fn), "rb", bufsz) as f:
|
@@ -3489,7 +3513,7 @@ def runihook(
|
|
3489
3513
|
verbose ,
|
3490
3514
|
cmd ,
|
3491
3515
|
vol ,
|
3492
|
-
ups
|
3516
|
+
ups ,
|
3493
3517
|
) :
|
3494
3518
|
_, chk, fork, jtxt, wait, sp_ka, acmd = _parsehook(log, cmd)
|
3495
3519
|
bcmd = [sfsenc(x) for x in acmd]
|
copyparty/web/baguettebox.js.gz
CHANGED
Binary file
|
copyparty/web/browser.css.gz
CHANGED
Binary file
|
copyparty/web/browser.js.gz
CHANGED
Binary file
|
copyparty/web/rups.js.gz
CHANGED
Binary file
|
copyparty/web/splash.css.gz
CHANGED
Binary file
|
copyparty/web/splash.html
CHANGED
@@ -22,7 +22,7 @@
|
|
22
22
|
<p id="b">howdy stranger <small>(you're not logged in)</small></p>
|
23
23
|
{%- else %}
|
24
24
|
<a id="c" href="{{ r }}/?pw=x" class="logout">logout</a>
|
25
|
-
<p><span id="m">welcome back,</span> <strong>{{ this.uname|e }}</strong></p>
|
25
|
+
<p><span id="m">welcome back,</span> <strong id="un">{{ this.uname|e }}</strong></p>
|
26
26
|
{%- endif %}
|
27
27
|
{%- endif %}
|
28
28
|
|
@@ -168,6 +168,13 @@
|
|
168
168
|
|
169
169
|
<li><a id="af" href="{{ r }}/?ru">show recent uploads</a></li>
|
170
170
|
<li><a id="k" href="{{ r }}/?reset" class="r" onclick="localStorage.clear();return true">reset client settings</a></li>
|
171
|
+
|
172
|
+
{%- if this.uname != '*' %}
|
173
|
+
<li><form method="post" enctype="multipart/form-data">
|
174
|
+
<input type="hidden" name="act" value="logout" />
|
175
|
+
<input type="submit" id="lo" value="logout “{{ this.uname|e }}” everywhere" />
|
176
|
+
</form></li>
|
177
|
+
{% endif %}
|
171
178
|
</ul>
|
172
179
|
|
173
180
|
</div>
|
copyparty/web/splash.js.gz
CHANGED
Binary file
|
copyparty/web/svcs.html
CHANGED
@@ -42,7 +42,7 @@
|
|
42
42
|
|
43
43
|
|
44
44
|
|
45
|
-
{% if args.
|
45
|
+
{% if args.have_idp_hdrs %}
|
46
46
|
<p style="line-height:2em"><b>WARNING:</b> this server is using IdP-based authentication, so this stuff may not work as advertised. Depending on server config, these commands can probably only be used to access areas which don't require authentication, unless you auth using any non-IdP accounts defined in the copyparty config. Please see <a href="https://github.com/9001/copyparty/blob/hovudstraum/docs/idp.md#connecting-webdav-clients">the IdP docs</a></p>
|
47
47
|
{% endif %}
|
48
48
|
|
copyparty/web/up2k.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.19.
|
3
|
+
Version: 1.19.3
|
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
|
@@ -155,7 +155,9 @@ made in Norway 🇳🇴
|
|
155
155
|
* [upload events](#upload-events) - the older, more powerful approach ([examples](./bin/mtag/))
|
156
156
|
* [handlers](#handlers) - redefine behavior with plugins ([examples](./bin/handlers/))
|
157
157
|
* [ip auth](#ip-auth) - autologin based on IP range (CIDR)
|
158
|
+
* [restrict to ip](#restrict-to-ip) - limit a user to certain IP ranges (CIDR)
|
158
159
|
* [identity providers](#identity-providers) - replace copyparty passwords with oauth and such
|
160
|
+
* [generic header auth](#generic-header-auth) - other ways to auth by header
|
159
161
|
* [user-changeable passwords](#user-changeable-passwords) - if permitted, users can change their own passwords
|
160
162
|
* [using the cloud as storage](#using-the-cloud-as-storage) - connecting to an aws s3 bucket and similar
|
161
163
|
* [hiding from google](#hiding-from-google) - tell search engines you don't wanna be indexed
|
@@ -331,6 +333,7 @@ also see [comparison to similar software](./docs/versus.md)
|
|
331
333
|
* ☑ realtime streaming of growing files (logfiles and such)
|
332
334
|
* ☑ [thumbnails](#thumbnails)
|
333
335
|
* ☑ ...of images using Pillow, pyvips, or FFmpeg
|
336
|
+
* ☑ ...of RAW images using rawpy
|
334
337
|
* ☑ ...of videos using FFmpeg
|
335
338
|
* ☑ ...of audio (spectrograms) using FFmpeg
|
336
339
|
* ☑ cache eviction (max-age; maybe max-size eventually)
|
@@ -577,6 +580,8 @@ examples:
|
|
577
580
|
* replacing the `g` permission with `wg` would let anonymous users upload files, but not see the required filekey to access it
|
578
581
|
* replacing the `g` permission with `wG` would let anonymous users upload files, receiving a working direct link in return
|
579
582
|
|
583
|
+
if you want to grant access to all users who are logged in, the group `acct` will always contain all known users, so for example `-v /mnt/music:music:r,@acct`
|
584
|
+
|
580
585
|
anyone trying to bruteforce a password gets banned according to `--ban-pw`; default is 24h ban for 9 failed attempts in 1 hour
|
581
586
|
|
582
587
|
and if you want to use config files instead of commandline args (good!) then here's the same examples as a configfile; save it as `foobar.conf` and use it like this: `python copyparty-sfx.py -c foobar.conf`
|
@@ -602,6 +607,7 @@ and if you want to use config files instead of commandline args (good!) then her
|
|
602
607
|
accs:
|
603
608
|
r: u1, u2 # only these accounts can read,
|
604
609
|
r: @g1 # (exactly the same, just with a group instead)
|
610
|
+
r: @acct # (alternatively, ALL users who are logged in)
|
605
611
|
rw: u3 # and only u3 can read-write
|
606
612
|
|
607
613
|
[/inc]
|
@@ -1957,6 +1963,20 @@ repeat the option to map additional subnets
|
|
1957
1963
|
**be careful with this one!** if you have a reverseproxy, then you definitely want to make sure you have [real-ip](#real-ip) configured correctly, and it's probably a good idea to nullmap the reverseproxy's IP just in case; so if your reverseproxy is sending requests from `172.24.27.9` then that would be `--ipu=172.24.27.9/32=`
|
1958
1964
|
|
1959
1965
|
|
1966
|
+
### restrict to ip
|
1967
|
+
|
1968
|
+
limit a user to certain IP ranges (CIDR) , using the global-option `--ipr`
|
1969
|
+
|
1970
|
+
for example, if the user `spartacus` should get rejected if they're not connecting from an IP that starts with `192.168.123` or `172.16`, then you can either specify `--ipr=192.168.123.0/24,172.16.0.0/16=spartacus` as a commandline option, or put this in a config file:
|
1971
|
+
|
1972
|
+
```yaml
|
1973
|
+
[global]
|
1974
|
+
ipr: 192.168.123.0/24,172.16.0.0/16=spartacus
|
1975
|
+
```
|
1976
|
+
|
1977
|
+
repeat the option to map additional users
|
1978
|
+
|
1979
|
+
|
1960
1980
|
## identity providers
|
1961
1981
|
|
1962
1982
|
replace copyparty passwords with oauth and such
|
@@ -1976,6 +1996,20 @@ a more complete example of the copyparty configuration options [look like this](
|
|
1976
1996
|
but if you just want to let users change their own passwords, then you probably want [user-changeable passwords](#user-changeable-passwords) instead
|
1977
1997
|
|
1978
1998
|
|
1999
|
+
### generic header auth
|
2000
|
+
|
2001
|
+
other ways to auth by header
|
2002
|
+
|
2003
|
+
if you have a middleware which adds a header with a user identifier, for example tailscale's `Tailscale-User-Login: alice.m@forest.net` then you can automatically auth as `alice` by defining that mapping with `--idp-hm-usr '^Tailscale-User-Login^alice.m@forest.net^alice'` or the following config file:
|
2004
|
+
|
2005
|
+
```yaml
|
2006
|
+
[global]
|
2007
|
+
idp-hm-usr: ^Tailscale-User-Login^alice.m@forest.net^alice
|
2008
|
+
```
|
2009
|
+
|
2010
|
+
repeat the whole `idp-hm-usr` option to add more mappings
|
2011
|
+
|
2012
|
+
|
1979
2013
|
## user-changeable passwords
|
1980
2014
|
|
1981
2015
|
if permitted, users can change their own passwords in the control-panel
|
@@ -2857,9 +2891,10 @@ enable [music tags](#metadata-from-audio-files):
|
|
2857
2891
|
enable [thumbnails](#thumbnails) of...
|
2858
2892
|
* **images:** `Pillow` and/or `pyvips` and/or `ffmpeg` (requires py2.7 or py3.5+)
|
2859
2893
|
* **videos/audio:** `ffmpeg` and `ffprobe` somewhere in `$PATH`
|
2860
|
-
* **HEIF pictures:** `pyvips` or `ffmpeg` or `
|
2894
|
+
* **HEIF pictures:** `pyvips` or `ffmpeg` or `pillow-heif`
|
2861
2895
|
* **AVIF pictures:** `pyvips` or `ffmpeg` or `pillow-avif-plugin` or pillow v11.3+
|
2862
2896
|
* **JPEG XL pictures:** `pyvips` or `ffmpeg`
|
2897
|
+
* **RAW images:** `rawpy`, plus one of `pyvips` or `Pillow` (for some formats)
|
2863
2898
|
|
2864
2899
|
enable sending [zeromq messages](#zeromq) from event-hooks: `pyzmq`
|
2865
2900
|
|
@@ -2890,9 +2925,10 @@ set any of the following environment variables to disable its associated optiona
|
|
2890
2925
|
| `PRTY_NO_PIL` | disable all [Pillow](https://pypi.org/project/pillow/)-based thumbnail support; will fallback to libvips or ffmpeg |
|
2891
2926
|
| `PRTY_NO_PILF` | disable Pillow `ImageFont` text rendering, used for folder thumbnails |
|
2892
2927
|
| `PRTY_NO_PIL_AVIF` | disable Pillow avif support (internal and/or [plugin](https://pypi.org/project/pillow-avif-plugin/)) |
|
2893
|
-
| `PRTY_NO_PIL_HEIF` | disable 3rd-party Pillow plugin for [HEIF support](https://pypi.org/project/
|
2928
|
+
| `PRTY_NO_PIL_HEIF` | disable 3rd-party Pillow plugin for [HEIF support](https://pypi.org/project/pillow-heif/) |
|
2894
2929
|
| `PRTY_NO_PIL_WEBP` | disable use of native webp support in Pillow |
|
2895
2930
|
| `PRTY_NO_PSUTIL` | do not use [psutil](https://pypi.org/project/psutil/) for reaping stuck hooks and plugins on Windows |
|
2931
|
+
| `PRTY_NO_RAW` | disable all [rawpy](https://pypi.org/project/rawpy/)-based thumbnail support for RAW images |
|
2896
2932
|
| `PRTY_NO_VIPS` | disable all [libvips](https://pypi.org/project/pyvips/)-based thumbnail support; will fallback to Pillow or ffmpeg |
|
2897
2933
|
|
2898
2934
|
example: `PRTY_NO_PIL=1 python3 copyparty-sfx.py`
|