copyparty 1.18.0__py3-none-any.whl → 1.18.1__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/__init__.py +1 -0
- copyparty/__main__.py +4 -0
- copyparty/__version__.py +2 -2
- copyparty/authsrv.py +61 -3
- copyparty/httpcli.py +44 -6
- copyparty/httpconn.py +3 -0
- copyparty/httpsrv.py +16 -0
- copyparty/svchub.py +100 -25
- copyparty/th_srv.py +4 -0
- copyparty/web/browser.css.gz +0 -0
- copyparty/web/browser.js.gz +0 -0
- copyparty/web/idp.html +55 -0
- copyparty/web/splash.html +4 -0
- copyparty/web/splash.js.gz +0 -0
- copyparty/web/up2k.js.gz +0 -0
- copyparty/web/util.js.gz +0 -0
- {copyparty-1.18.0.dist-info → copyparty-1.18.1.dist-info}/METADATA +3 -4
- {copyparty-1.18.0.dist-info → copyparty-1.18.1.dist-info}/RECORD +22 -21
- {copyparty-1.18.0.dist-info → copyparty-1.18.1.dist-info}/WHEEL +0 -0
- {copyparty-1.18.0.dist-info → copyparty-1.18.1.dist-info}/entry_points.txt +0 -0
- {copyparty-1.18.0.dist-info → copyparty-1.18.1.dist-info}/licenses/LICENSE +0 -0
- {copyparty-1.18.0.dist-info → copyparty-1.18.1.dist-info}/top_level.txt +0 -0
copyparty/__init__.py
CHANGED
copyparty/__main__.py
CHANGED
@@ -1085,12 +1085,16 @@ def add_cert(ap, cert_path):
|
|
1085
1085
|
|
1086
1086
|
|
1087
1087
|
def add_auth(ap):
|
1088
|
+
idp_db = os.path.join(E.cfg, "idp.db")
|
1088
1089
|
ses_db = os.path.join(E.cfg, "sessions.db")
|
1089
1090
|
ap2 = ap.add_argument_group('IdP / identity provider / user authentication options')
|
1090
1091
|
ap2.add_argument("--idp-h-usr", metavar="HN", type=u, default="", help="bypass the copyparty authentication checks if the request-header \033[33mHN\033[0m contains a username to associate the request with (for use with authentik/oauth/...)\n\033[1;31mWARNING:\033[0m if you enable this, make sure clients are unable to specify this header themselves; must be washed away and replaced by a reverse-proxy")
|
1091
1092
|
ap2.add_argument("--idp-h-grp", metavar="HN", type=u, default="", help="assume the request-header \033[33mHN\033[0m contains the groupname of the requesting user; can be referenced in config files for group-based access control")
|
1092
1093
|
ap2.add_argument("--idp-h-key", metavar="HN", type=u, default="", help="optional but recommended safeguard; your reverse-proxy will insert a secret header named \033[33mHN\033[0m into all requests, and the other IdP headers will be ignored if this header is not present")
|
1093
1094
|
ap2.add_argument("--idp-gsep", metavar="RE", type=u, default="|:;+,", help="if there are multiple groups in \033[33m--idp-h-grp\033[0m, they are separated by one of the characters in \033[33mRE\033[0m")
|
1095
|
+
ap2.add_argument("--idp-db", metavar="PATH", type=u, default=idp_db, help="where to store the known IdP users/groups (if you run multiple copyparty instances, make sure they use different DBs)")
|
1096
|
+
ap2.add_argument("--idp-store", metavar="N", type=int, default=1, help="how to use \033[33m--idp-db\033[0m; [\033[32m0\033[0m] = entirely disable, [\033[32m1\033[0m] = write-only (effectively disabled), [\033[32m2\033[0m] = remember users, [\033[32m3\033[0m] = remember users and groups.\nNOTE: Will remember and restore the IdP-volumes of all users for all eternity if set to 2 or 3, even when user is deleted from your IdP")
|
1097
|
+
ap2.add_argument("--idp-adm", metavar="U,U", type=u, default="", help="comma-separated list of users allowed to use /?idp (the cache management UI)")
|
1094
1098
|
ap2.add_argument("--no-bauth", action="store_true", help="disable basic-authentication support; do not accept passwords from the 'Authenticate' header at all. NOTE: This breaks support for the android app")
|
1095
1099
|
ap2.add_argument("--bauth-last", action="store_true", help="keeps basic-authentication enabled, but only as a last-resort; if a cookie is also provided then the cookie wins")
|
1096
1100
|
ap2.add_argument("--ses-db", metavar="PATH", type=u, default=ses_db, help="where to store the sessions database (if you run multiple copyparty instances, make sure they use different DBs)")
|
copyparty/__version__.py
CHANGED
copyparty/authsrv.py
CHANGED
@@ -21,6 +21,7 @@ from .util import (
|
|
21
21
|
DEF_MTE,
|
22
22
|
DEF_MTH,
|
23
23
|
EXTS,
|
24
|
+
HAVE_SQLITE3,
|
24
25
|
IMPLICATIONS,
|
25
26
|
MIMES,
|
26
27
|
SQLITE_VER,
|
@@ -32,6 +33,7 @@ from .util import (
|
|
32
33
|
afsenc,
|
33
34
|
get_df,
|
34
35
|
humansize,
|
36
|
+
min_ex,
|
35
37
|
odfusion,
|
36
38
|
read_utf8,
|
37
39
|
relchk,
|
@@ -44,6 +46,9 @@ from .util import (
|
|
44
46
|
vsplit,
|
45
47
|
)
|
46
48
|
|
49
|
+
if HAVE_SQLITE3:
|
50
|
+
import sqlite3
|
51
|
+
|
47
52
|
if TYPE_CHECKING:
|
48
53
|
from .broker_mp import BrokerMp
|
49
54
|
from .broker_thr import BrokerThr
|
@@ -928,6 +933,10 @@ class AuthSrv(object):
|
|
928
933
|
return False
|
929
934
|
|
930
935
|
self.idp_accs[uname] = gnames
|
936
|
+
try:
|
937
|
+
self._update_idp_db(uname, gname)
|
938
|
+
except:
|
939
|
+
self.log("failed to update the --idp-db:\n%s" % (min_ex(),), 3)
|
931
940
|
|
932
941
|
t = "reinitializing due to new user from IdP: [%r:%r]"
|
933
942
|
self.log(t % (uname, gnames), 3)
|
@@ -940,6 +949,21 @@ class AuthSrv(object):
|
|
940
949
|
broker.ask("reload", False, True).get()
|
941
950
|
return True
|
942
951
|
|
952
|
+
def _update_idp_db(self, uname , gname ) :
|
953
|
+
if not self.args.idp_store:
|
954
|
+
return
|
955
|
+
|
956
|
+
|
957
|
+
db = sqlite3.connect(self.args.idp_db)
|
958
|
+
cur = db.cursor()
|
959
|
+
|
960
|
+
cur.execute("delete from us where un = ?", (uname,))
|
961
|
+
cur.execute("insert into us values (?,?)", (uname, gname))
|
962
|
+
|
963
|
+
db.commit()
|
964
|
+
cur.close()
|
965
|
+
db.close()
|
966
|
+
|
943
967
|
def _map_volume_idp(
|
944
968
|
self,
|
945
969
|
src ,
|
@@ -1088,6 +1112,7 @@ class AuthSrv(object):
|
|
1088
1112
|
* any non-zero value from IdP group header
|
1089
1113
|
* otherwise take --grps / [groups]
|
1090
1114
|
"""
|
1115
|
+
self.load_idp_db(bool(self.idp_accs))
|
1091
1116
|
ret = {un: gns[:] for un, gns in self.idp_accs.items()}
|
1092
1117
|
ret.update({zs: [""] for zs in acct if zs not in ret})
|
1093
1118
|
for gn, uns in grps.items():
|
@@ -1648,7 +1673,6 @@ class AuthSrv(object):
|
|
1648
1673
|
shr = enshare[1:-1]
|
1649
1674
|
shrs = enshare[1:]
|
1650
1675
|
if enshare:
|
1651
|
-
import sqlite3
|
1652
1676
|
|
1653
1677
|
zsd = {"d2d": True, "tcolor": self.args.tcolor}
|
1654
1678
|
shv = VFS(self.log_func, "", shr, shr, AXS(), zsd)
|
@@ -2613,6 +2637,42 @@ class AuthSrv(object):
|
|
2613
2637
|
zs = str(vol.flags.get("tcolor") or self.args.tcolor)
|
2614
2638
|
vol.flags["tcolor"] = zs.lstrip("#")
|
2615
2639
|
|
2640
|
+
def load_idp_db(self, quiet=False) :
|
2641
|
+
# mutex me
|
2642
|
+
level = self.args.idp_store
|
2643
|
+
if level < 2 or not self.args.idp_h_usr:
|
2644
|
+
return
|
2645
|
+
|
2646
|
+
|
2647
|
+
db = sqlite3.connect(self.args.idp_db)
|
2648
|
+
cur = db.cursor()
|
2649
|
+
from_cache = cur.execute("select un, gs from us").fetchall()
|
2650
|
+
cur.close()
|
2651
|
+
db.close()
|
2652
|
+
|
2653
|
+
self.idp_accs.clear()
|
2654
|
+
self.idp_usr_gh.clear()
|
2655
|
+
|
2656
|
+
gsep = self.args.idp_gsep
|
2657
|
+
n = []
|
2658
|
+
for uname, gname in from_cache:
|
2659
|
+
if level < 3:
|
2660
|
+
if uname in self.idp_accs:
|
2661
|
+
continue
|
2662
|
+
gname = ""
|
2663
|
+
gnames = [x.strip() for x in gsep.split(gname)]
|
2664
|
+
gnames.sort()
|
2665
|
+
|
2666
|
+
# self.idp_usr_gh[uname] = gname
|
2667
|
+
self.idp_accs[uname] = gnames
|
2668
|
+
n.append(uname)
|
2669
|
+
|
2670
|
+
if n and not quiet:
|
2671
|
+
t = ", ".join(n[:9])
|
2672
|
+
if len(n) > 9:
|
2673
|
+
t += "..."
|
2674
|
+
self.log("found %d IdP users in db (%s)" % (len(n), t))
|
2675
|
+
|
2616
2676
|
def load_sessions(self, quiet=False) :
|
2617
2677
|
# mutex me
|
2618
2678
|
if self.args.no_ses:
|
@@ -2620,7 +2680,6 @@ class AuthSrv(object):
|
|
2620
2680
|
self.sesa = {}
|
2621
2681
|
return
|
2622
2682
|
|
2623
|
-
import sqlite3
|
2624
2683
|
|
2625
2684
|
ases = {}
|
2626
2685
|
blen = (self.args.ses_len // 4) * 4 # 3 bytes in 4 chars
|
@@ -2667,7 +2726,6 @@ class AuthSrv(object):
|
|
2667
2726
|
if self.args.no_ses:
|
2668
2727
|
return
|
2669
2728
|
|
2670
|
-
import sqlite3
|
2671
2729
|
|
2672
2730
|
db = sqlite3.connect(self.args.ses_db)
|
2673
2731
|
cur = db.cursor()
|
copyparty/httpcli.py
CHANGED
@@ -1294,6 +1294,9 @@ class HttpCli(object):
|
|
1294
1294
|
if "ru" in self.uparam:
|
1295
1295
|
return self.tx_rups()
|
1296
1296
|
|
1297
|
+
if "idp" in self.uparam:
|
1298
|
+
return self.tx_idp()
|
1299
|
+
|
1297
1300
|
if "h" in self.uparam:
|
1298
1301
|
return self.tx_mounts()
|
1299
1302
|
|
@@ -5077,15 +5080,24 @@ class HttpCli(object):
|
|
5077
5080
|
return "" # unhandled / fallthrough
|
5078
5081
|
|
5079
5082
|
def scanvol(self) :
|
5080
|
-
if not self.can_admin:
|
5081
|
-
raise Pebkac(403, "'scanvol' not allowed for user " + self.uname)
|
5082
|
-
|
5083
5083
|
if self.args.no_rescan:
|
5084
5084
|
raise Pebkac(403, "the rescan feature is disabled in server config")
|
5085
5085
|
|
5086
|
-
|
5086
|
+
vpaths = self.uparam["scan"].split(",/")
|
5087
|
+
if vpaths == [""]:
|
5088
|
+
vpaths = [self.vpath]
|
5089
|
+
|
5090
|
+
vols = []
|
5091
|
+
for vpath in vpaths:
|
5092
|
+
vn, _ = self.asrv.vfs.get(vpath, self.uname, True, True)
|
5093
|
+
vols.append(vn.vpath)
|
5094
|
+
if self.uname not in vn.axs.uadmin:
|
5095
|
+
self.log("rejected scanning [%s] => [%s];" % (vpath, vn.vpath), 3)
|
5096
|
+
raise Pebkac(403, "'scanvol' not allowed for user " + self.uname)
|
5097
|
+
|
5098
|
+
self.log("trying to rescan %d volumes: %r" % (len(vols), vols))
|
5087
5099
|
|
5088
|
-
args = [self.asrv.vfs.all_vols,
|
5100
|
+
args = [self.asrv.vfs.all_vols, vols, False, True]
|
5089
5101
|
|
5090
5102
|
x = self.conn.hsrv.broker.ask("up2k.rescan", *args)
|
5091
5103
|
err = x.get()
|
@@ -5504,6 +5516,32 @@ class HttpCli(object):
|
|
5504
5516
|
self.reply(html.encode("utf-8"), status=200)
|
5505
5517
|
return True
|
5506
5518
|
|
5519
|
+
def tx_idp(self) :
|
5520
|
+
if self.uname.lower() not in self.args.idp_adm_set:
|
5521
|
+
raise Pebkac(403, "'idp' not allowed for user " + self.uname)
|
5522
|
+
|
5523
|
+
cmd = self.uparam["idp"]
|
5524
|
+
if cmd.startswith("rm="):
|
5525
|
+
import sqlite3
|
5526
|
+
|
5527
|
+
db = sqlite3.connect(self.args.idp_db)
|
5528
|
+
db.execute("delete from us where un=?", (cmd[3:],))
|
5529
|
+
db.commit()
|
5530
|
+
db.close()
|
5531
|
+
|
5532
|
+
self.conn.hsrv.broker.ask("reload", False, False).get()
|
5533
|
+
|
5534
|
+
self.redirect("", "?idp")
|
5535
|
+
return True
|
5536
|
+
|
5537
|
+
rows = [
|
5538
|
+
[k, "[%s]" % ("], [".join(v))]
|
5539
|
+
for k, v in sorted(self.asrv.idp_accs.items())
|
5540
|
+
]
|
5541
|
+
html = self.j2s("idp", this=self, rows=rows, now=int(time.time()))
|
5542
|
+
self.reply(html.encode("utf-8"), status=200)
|
5543
|
+
return True
|
5544
|
+
|
5507
5545
|
def tx_shares(self) :
|
5508
5546
|
if self.uname == "*":
|
5509
5547
|
self.loud_reply("you're not logged in")
|
@@ -5578,7 +5616,7 @@ class HttpCli(object):
|
|
5578
5616
|
self.conn.hsrv.broker.ask("reload", False, False).get()
|
5579
5617
|
self.conn.hsrv.broker.ask("up2k.wake_rescanner").get()
|
5580
5618
|
|
5581
|
-
self.redirect(
|
5619
|
+
self.redirect("", "?shares")
|
5582
5620
|
return True
|
5583
5621
|
|
5584
5622
|
def handle_share(self, req ) :
|
copyparty/httpconn.py
CHANGED
copyparty/httpsrv.py
CHANGED
@@ -171,6 +171,7 @@ class HttpSrv(object):
|
|
171
171
|
"browser",
|
172
172
|
"browser2",
|
173
173
|
"cf",
|
174
|
+
"idp",
|
174
175
|
"md",
|
175
176
|
"mde",
|
176
177
|
"msg",
|
@@ -308,6 +309,8 @@ class HttpSrv(object):
|
|
308
309
|
|
309
310
|
Daemon(self.broker.say, "sig-hsrv-up1", ("cb_httpsrv_up",))
|
310
311
|
|
312
|
+
saddr = ("", 0) # fwd-decl for `except TypeError as ex:`
|
313
|
+
|
311
314
|
while not self.stopping:
|
312
315
|
if self.args.log_conn:
|
313
316
|
self.log(self.name, "|%sC-ncli" % ("-" * 1,), c="90")
|
@@ -389,6 +392,19 @@ class HttpSrv(object):
|
|
389
392
|
self.log(self.name, "accept({}): {}".format(fno, ex), c=6)
|
390
393
|
time.sleep(0.02)
|
391
394
|
continue
|
395
|
+
except TypeError as ex:
|
396
|
+
# on macOS, accept() may return a None saddr if blocked by LittleSnitch;
|
397
|
+
# unicode(saddr[0]) ==> TypeError: 'NoneType' object is not subscriptable
|
398
|
+
if tcp and not saddr:
|
399
|
+
t = "accept(%s): failed to accept connection from client due to firewall or network issue"
|
400
|
+
self.log(self.name, t % (fno,), c=3)
|
401
|
+
try:
|
402
|
+
sck.close() # type: ignore
|
403
|
+
except:
|
404
|
+
pass
|
405
|
+
time.sleep(0.02)
|
406
|
+
continue
|
407
|
+
raise
|
392
408
|
|
393
409
|
if self.args.log_conn:
|
394
410
|
t = "|{}C-acc2 \033[0;36m{} \033[3{}m{}".format(
|
copyparty/svchub.py
CHANGED
@@ -82,6 +82,7 @@ if PY2:
|
|
82
82
|
range = xrange # type: ignore
|
83
83
|
|
84
84
|
|
85
|
+
VER_IDP_DB = 1
|
85
86
|
VER_SESSION_DB = 1
|
86
87
|
VER_SHARES_DB = 2
|
87
88
|
|
@@ -252,11 +253,15 @@ class SvcHub(object):
|
|
252
253
|
self.log("root", "effective %s is %s" % (zs, getattr(args, zs)))
|
253
254
|
|
254
255
|
if args.ah_cli or args.ah_gen:
|
256
|
+
args.idp_store = 0
|
255
257
|
args.no_ses = True
|
256
258
|
args.shr = ""
|
257
259
|
|
260
|
+
if args.idp_store and args.idp_h_usr:
|
261
|
+
self.setup_db("idp")
|
262
|
+
|
258
263
|
if not self.args.no_ses:
|
259
|
-
self.
|
264
|
+
self.setup_db("ses")
|
260
265
|
|
261
266
|
args.shr1 = ""
|
262
267
|
if args.shr:
|
@@ -415,25 +420,57 @@ class SvcHub(object):
|
|
415
420
|
except:
|
416
421
|
pass
|
417
422
|
|
418
|
-
def
|
423
|
+
def _db_onfail_ses(self) :
|
424
|
+
self.args.no_ses = True
|
425
|
+
|
426
|
+
def _db_onfail_idp(self) :
|
427
|
+
self.args.idp_store = 0
|
428
|
+
|
429
|
+
def setup_db(self, which ) :
|
430
|
+
"""
|
431
|
+
the "non-mission-critical" databases; if something looks broken then just nuke it
|
432
|
+
"""
|
433
|
+
if which == "ses":
|
434
|
+
native_ver = VER_SESSION_DB
|
435
|
+
db_path = self.args.ses_db
|
436
|
+
desc = "sessions-db"
|
437
|
+
pathopt = "ses-db"
|
438
|
+
sanchk_q = "select count(*) from us"
|
439
|
+
createfun = self._create_session_db
|
440
|
+
failfun = self._db_onfail_ses
|
441
|
+
elif which == "idp":
|
442
|
+
native_ver = VER_IDP_DB
|
443
|
+
db_path = self.args.idp_db
|
444
|
+
desc = "idp-db"
|
445
|
+
pathopt = "idp-db"
|
446
|
+
sanchk_q = "select count(*) from us"
|
447
|
+
createfun = self._create_idp_db
|
448
|
+
failfun = self._db_onfail_idp
|
449
|
+
else:
|
450
|
+
raise Exception("unknown cachetype")
|
451
|
+
|
452
|
+
if not db_path.endswith(".db"):
|
453
|
+
zs = "config option --%s (the %s) was configured to [%s] which is invalid; must be a filepath ending with .db"
|
454
|
+
self.log("root", zs % (pathopt, desc, db_path), 1)
|
455
|
+
raise Exception(BAD_CFG)
|
456
|
+
|
419
457
|
if not HAVE_SQLITE3:
|
420
|
-
|
421
|
-
|
422
|
-
|
458
|
+
failfun()
|
459
|
+
if which == "ses":
|
460
|
+
zs = "disabling sessions, will use plaintext passwords in cookies"
|
461
|
+
elif which == "idp":
|
462
|
+
zs = "disabling idp-db, will be unable to remember IdP-volumes after a restart"
|
463
|
+
self.log("root", "WARNING: sqlite3 not available; %s" % (zs,), 3)
|
423
464
|
return
|
424
465
|
|
425
466
|
|
426
|
-
# policy:
|
427
|
-
# the sessions-db is whatever, if something looks broken then just nuke it
|
428
|
-
|
429
|
-
db_path = self.args.ses_db
|
430
467
|
db_lock = db_path + ".lock"
|
431
468
|
try:
|
432
469
|
create = not os.path.getsize(db_path)
|
433
470
|
except:
|
434
471
|
create = True
|
435
472
|
zs = "creating new" if create else "opening"
|
436
|
-
self.log("root", "%s
|
473
|
+
self.log("root", "%s %s %s" % (zs, desc, db_path))
|
437
474
|
|
438
475
|
for tries in range(2):
|
439
476
|
sver = 0
|
@@ -443,17 +480,19 @@ class SvcHub(object):
|
|
443
480
|
try:
|
444
481
|
zs = "select v from kv where k='sver'"
|
445
482
|
sver = cur.execute(zs).fetchall()[0][0]
|
446
|
-
if sver >
|
447
|
-
zs = "this version of copyparty only understands
|
448
|
-
raise Exception(zs % (
|
483
|
+
if sver > native_ver:
|
484
|
+
zs = "this version of copyparty only understands %s v%d and older; the db is v%d"
|
485
|
+
raise Exception(zs % (desc, native_ver, sver))
|
449
486
|
|
450
|
-
cur.execute(
|
487
|
+
cur.execute(sanchk_q).fetchone()
|
451
488
|
except:
|
452
489
|
if sver:
|
453
490
|
raise
|
454
|
-
sver =
|
455
|
-
|
456
|
-
err = self.
|
491
|
+
sver = createfun(cur)
|
492
|
+
|
493
|
+
err = self._verify_db(
|
494
|
+
cur, which, pathopt, db_path, desc, sver, native_ver
|
495
|
+
)
|
457
496
|
if err:
|
458
497
|
tries = 99
|
459
498
|
self.args.no_ses = True
|
@@ -461,10 +500,10 @@ class SvcHub(object):
|
|
461
500
|
break
|
462
501
|
|
463
502
|
except Exception as ex:
|
464
|
-
if tries or sver >
|
503
|
+
if tries or sver > native_ver:
|
465
504
|
raise
|
466
|
-
t = "
|
467
|
-
self.log("root", t % (ex
|
505
|
+
t = "%s is unusable; deleting and recreating: %r"
|
506
|
+
self.log("root", t % (desc, ex), 3)
|
468
507
|
try:
|
469
508
|
cur.close() # type: ignore
|
470
509
|
except:
|
@@ -492,8 +531,31 @@ class SvcHub(object):
|
|
492
531
|
for cmd in sch:
|
493
532
|
cur.execute(cmd)
|
494
533
|
self.log("root", "created new sessions-db")
|
534
|
+
return 1
|
495
535
|
|
496
|
-
def
|
536
|
+
def _create_idp_db(self, cur ) :
|
537
|
+
sch = [
|
538
|
+
r"create table kv (k text, v int)",
|
539
|
+
r"create table us (un text, gs text)",
|
540
|
+
# username, groups
|
541
|
+
r"create index us_un on us(un)",
|
542
|
+
r"insert into kv values ('sver', 1)",
|
543
|
+
]
|
544
|
+
for cmd in sch:
|
545
|
+
cur.execute(cmd)
|
546
|
+
self.log("root", "created new idp-db")
|
547
|
+
return 1
|
548
|
+
|
549
|
+
def _verify_db(
|
550
|
+
self,
|
551
|
+
cur ,
|
552
|
+
which ,
|
553
|
+
pathopt ,
|
554
|
+
db_path ,
|
555
|
+
desc ,
|
556
|
+
sver ,
|
557
|
+
native_ver ,
|
558
|
+
) :
|
497
559
|
# ensure writable (maybe owned by other user)
|
498
560
|
db = cur.connection
|
499
561
|
|
@@ -505,9 +567,16 @@ class SvcHub(object):
|
|
505
567
|
except:
|
506
568
|
owner = 0
|
507
569
|
|
570
|
+
if which == "ses":
|
571
|
+
cons = "Will now disable sessions and instead use plaintext passwords in cookies."
|
572
|
+
elif which == "idp":
|
573
|
+
cons = "Each IdP-volume will not become available until its associated user sends their first request."
|
574
|
+
else:
|
575
|
+
raise Exception()
|
576
|
+
|
508
577
|
if not lock_file(db_path + ".lock"):
|
509
|
-
t = "the
|
510
|
-
return t % (db_path, owner)
|
578
|
+
t = "the %s [%s] is already in use by another copyparty instance (pid:%d). This is not supported; please provide another database with --%s or give this copyparty-instance its entirely separate config-folder by setting another path in the XDG_CONFIG_HOME env-var. You can also disable this safeguard by setting env-var PRTY_NO_DB_LOCK=1. %s"
|
579
|
+
return t % (desc, db_path, owner, pathopt, cons)
|
511
580
|
|
512
581
|
vars = (("pid", os.getpid()), ("ts", int(time.time() * 1000)))
|
513
582
|
if owner:
|
@@ -519,9 +588,9 @@ class SvcHub(object):
|
|
519
588
|
for k, v in vars:
|
520
589
|
cur.execute("insert into kv values(?, ?)", (k, v))
|
521
590
|
|
522
|
-
if sver <
|
591
|
+
if sver < native_ver:
|
523
592
|
cur.execute("delete from kv where k='sver'")
|
524
|
-
cur.execute("insert into kv values('sver',?)", (
|
593
|
+
cur.execute("insert into kv values('sver',?)", (native_ver,))
|
525
594
|
|
526
595
|
db.commit()
|
527
596
|
cur.close()
|
@@ -870,6 +939,12 @@ class SvcHub(object):
|
|
870
939
|
vs = os.path.expandvars(os.path.expanduser(vs))
|
871
940
|
setattr(al, k, vs)
|
872
941
|
|
942
|
+
for k in "idp_adm".split(" "):
|
943
|
+
vs = getattr(al, k)
|
944
|
+
vsa = [x.strip() for x in vs.split(",")]
|
945
|
+
vsa = [x.lower() for x in vsa if x]
|
946
|
+
setattr(al, k + "_set", set(vsa))
|
947
|
+
|
873
948
|
zs = "dav_ua1 sus_urls nonsus_urls ua_nodoc ua_nozip"
|
874
949
|
for k in zs.split(" "):
|
875
950
|
vs = getattr(al, k)
|
copyparty/th_srv.py
CHANGED
@@ -93,6 +93,10 @@ try:
|
|
93
93
|
if os.environ.get("PRTY_NO_PIL_AVIF"):
|
94
94
|
raise Exception()
|
95
95
|
|
96
|
+
if ".avif" in Image.registered_extensions():
|
97
|
+
HAVE_AVIF = True
|
98
|
+
raise Exception()
|
99
|
+
|
96
100
|
import pillow_avif # noqa: F401 # pylint: disable=unused-import
|
97
101
|
|
98
102
|
HAVE_AVIF = True
|
copyparty/web/browser.css.gz
CHANGED
Binary file
|
copyparty/web/browser.js.gz
CHANGED
Binary file
|
copyparty/web/idp.html
ADDED
@@ -0,0 +1,55 @@
|
|
1
|
+
<!DOCTYPE html>
|
2
|
+
<html lang="en">
|
3
|
+
|
4
|
+
<head>
|
5
|
+
<meta charset="utf-8">
|
6
|
+
<title>{{ s_doctitle }}</title>
|
7
|
+
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
8
|
+
<meta name="viewport" content="width=device-width, initial-scale=0.8">
|
9
|
+
<meta name="robots" content="noindex, nofollow">
|
10
|
+
<meta name="theme-color" content="#{{ tcolor }}">
|
11
|
+
<link rel="stylesheet" media="screen" href="{{ r }}/.cpr/shares.css?_={{ ts }}">
|
12
|
+
<link rel="stylesheet" media="screen" href="{{ r }}/.cpr/ui.css?_={{ ts }}">
|
13
|
+
{{ html_head }}
|
14
|
+
</head>
|
15
|
+
|
16
|
+
<body>
|
17
|
+
<div id="wrap">
|
18
|
+
<a href="{{ r }}/?idp">refresh</a>
|
19
|
+
<a href="{{ r }}/?h">control-panel</a>
|
20
|
+
|
21
|
+
<table id="tab"><thead><tr>
|
22
|
+
<th>forget</th>
|
23
|
+
<th>user</th>
|
24
|
+
<th>groups</th>
|
25
|
+
</tr></thead><tbody>
|
26
|
+
{% for un, gn in rows %}
|
27
|
+
<tr>
|
28
|
+
<td><a href="{{ r }}/?idp=rm={{ un|e }}">forget</a></td>
|
29
|
+
<td>{{ un|e }}</td>
|
30
|
+
<td>{{ gn|e }}</td>
|
31
|
+
</tr>
|
32
|
+
{% endfor %}
|
33
|
+
</tbody></table>
|
34
|
+
{% if not rows %}
|
35
|
+
(there are no IdP users in the cache)
|
36
|
+
{% endif %}
|
37
|
+
</div>
|
38
|
+
<a href="#" id="repl">π</a>
|
39
|
+
<script>
|
40
|
+
|
41
|
+
var SR="{{ r }}",
|
42
|
+
lang="{{ lang }}",
|
43
|
+
dfavico="{{ favico }}";
|
44
|
+
|
45
|
+
var STG = window.localStorage;
|
46
|
+
document.documentElement.className = (STG && STG.cpp_thm) || "{{ this.args.theme }}";
|
47
|
+
|
48
|
+
</script>
|
49
|
+
<script src="{{ r }}/.cpr/util.js?_={{ ts }}"></script>
|
50
|
+
{%- if js %}
|
51
|
+
<script src="{{ js }}_={{ ts }}"></script>
|
52
|
+
{%- endif %}
|
53
|
+
</body>
|
54
|
+
</html>
|
55
|
+
|
copyparty/web/splash.html
CHANGED
@@ -135,6 +135,10 @@
|
|
135
135
|
|
136
136
|
<h1 id="cc">other stuff:</h1>
|
137
137
|
<ul>
|
138
|
+
{%- if this.uname in this.args.idp_adm_set %}
|
139
|
+
<li><a id="ag" href="{{ r }}/?idp">view idp cache</a></li>
|
140
|
+
{% endif %}
|
141
|
+
|
138
142
|
{%- if this.uname != '*' and this.args.shr %}
|
139
143
|
<li><a id="y" href="{{ r }}/?shares">edit shares</a></li>
|
140
144
|
{% endif %}
|
copyparty/web/splash.js.gz
CHANGED
Binary file
|
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.18.
|
3
|
+
Version: 1.18.1
|
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
|
@@ -1559,7 +1559,6 @@ the same arguments can be set as volflags, in addition to `d2d`, `d2ds`, `d2t`,
|
|
1559
1559
|
note:
|
1560
1560
|
* upload-times can be displayed in the file listing by enabling the `.up_at` metadata key, either globally with `-e2d -mte +.up_at` or per-volume with volflags `e2d,mte=+.up_at` (will have a ~17% performance impact on directory listings)
|
1561
1561
|
* `e2tsr` is probably always overkill, since `e2ds`/`e2dsa` would pick up any file modifications and `e2ts` would then reindex those, unless there is a new copyparty version with new parsers and the release note says otherwise
|
1562
|
-
* the rescan button in the admin panel has no effect unless the volume has `-e2ds` or higher
|
1563
1562
|
|
1564
1563
|
config file example (these options are recommended btw):
|
1565
1564
|
|
@@ -2786,7 +2785,7 @@ enable [thumbnails](#thumbnails) of...
|
|
2786
2785
|
* **images:** `Pillow` and/or `pyvips` and/or `ffmpeg` (requires py2.7 or py3.5+)
|
2787
2786
|
* **videos/audio:** `ffmpeg` and `ffprobe` somewhere in `$PATH`
|
2788
2787
|
* **HEIF pictures:** `pyvips` or `ffmpeg` or `pyheif-pillow-opener` (requires Linux or a C compiler)
|
2789
|
-
* **AVIF pictures:** `pyvips` or `ffmpeg` or `pillow-avif-plugin`
|
2788
|
+
* **AVIF pictures:** `pyvips` or `ffmpeg` or `pillow-avif-plugin` or pillow v11.3+
|
2790
2789
|
* **JPEG XL pictures:** `pyvips` or `ffmpeg`
|
2791
2790
|
|
2792
2791
|
enable sending [zeromq messages](#zeromq) from event-hooks: `pyzmq`
|
@@ -2817,7 +2816,7 @@ set any of the following environment variables to disable its associated optiona
|
|
2817
2816
|
| `PRTY_NO_MUTAGEN` | do not use [mutagen](https://pypi.org/project/mutagen/) for reading metadata from media files; will fallback to ffprobe |
|
2818
2817
|
| `PRTY_NO_PIL` | disable all [Pillow](https://pypi.org/project/pillow/)-based thumbnail support; will fallback to libvips or ffmpeg |
|
2819
2818
|
| `PRTY_NO_PILF` | disable Pillow `ImageFont` text rendering, used for folder thumbnails |
|
2820
|
-
| `PRTY_NO_PIL_AVIF` | disable
|
2819
|
+
| `PRTY_NO_PIL_AVIF` | disable Pillow avif support (internal and/or [plugin](https://pypi.org/project/pillow-avif-plugin/)) |
|
2821
2820
|
| `PRTY_NO_PIL_HEIF` | disable 3rd-party Pillow plugin for [HEIF support](https://pypi.org/project/pyheif-pillow-opener/) |
|
2822
2821
|
| `PRTY_NO_PIL_WEBP` | disable use of native webp support in Pillow |
|
2823
2822
|
| `PRTY_NO_PSUTIL` | do not use [psutil](https://pypi.org/project/psutil/) for reaping stuck hooks and plugins on Windows |
|
@@ -1,7 +1,7 @@
|
|
1
|
-
copyparty/__init__.py,sha256=
|
2
|
-
copyparty/__main__.py,sha256=
|
3
|
-
copyparty/__version__.py,sha256=
|
4
|
-
copyparty/authsrv.py,sha256=
|
1
|
+
copyparty/__init__.py,sha256=4aJw_Mt3eSNMV8sJ95Nh4ris-tBUYhCOV094Rnxa5Xo,2651
|
2
|
+
copyparty/__main__.py,sha256=9dif5oV-BdPEeTnuiEHLSTxqDoYHJkFyecnJ94N5IRA,123786
|
3
|
+
copyparty/__version__.py,sha256=ccuRyetxDT3Kz5z0Vg4CMZH0x07iFUmVRTMc3FX0Td4,248
|
4
|
+
copyparty/authsrv.py,sha256=0ZNfH6_9Br2cSe-vAgf_Vp6PFakeao-ylhlqNYvEfvo,116493
|
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
|
@@ -11,9 +11,9 @@ copyparty/cfg.py,sha256=6o6aLzLxZ59lusAn_PMGgldc3rEb9yyGnUnGIP5D9M8,15077
|
|
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=G7PApVIFeSzRo4-D-9uRb8NxYgz6nFwTEbrOk1ErYCU,17969
|
14
|
-
copyparty/httpcli.py,sha256=
|
15
|
-
copyparty/httpconn.py,sha256=
|
16
|
-
copyparty/httpsrv.py,sha256=
|
14
|
+
copyparty/httpcli.py,sha256=ZeSkAhDGiu6K6k68DGnqH2u3wR0FqGzKCmcgIwQC6bU,229421
|
15
|
+
copyparty/httpconn.py,sha256=IA9fdCjigawZ4kWhgvVN3nSiy5pb3W2qaE6rFqUYdq0,6943
|
16
|
+
copyparty/httpsrv.py,sha256=x6dl6ZjpwYREbm-eJZYnwdkhDeCA58hw_iwUMCD1Wz8,18819
|
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
|
@@ -24,12 +24,12 @@ copyparty/smbd.py,sha256=dixFl2wlWymq_Cycc8a4cVB4gY8RSg2e3tE7Xr-aDa0,14614
|
|
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=
|
27
|
+
copyparty/svchub.py,sha256=YbYJd5X0pXAyC-C2nt1rVwnwd56b8VEU1zvGkijgNeU,48921
|
28
28
|
copyparty/szip.py,sha256=9srQzjsTBrBadf6QMh4YRAL70rkZLevAOHqXWK5jvr8,8846
|
29
29
|
copyparty/tcpsrv.py,sha256=F5K4Qr4eBLfhdLT_39yDf6ftrhWuGTrd6DSqqp_6e-Q,20480
|
30
30
|
copyparty/tftpd.py,sha256=tbnxUsilwyusrAUCVVjJUZnR9TIHDkE-99WLsUxAIGA,14029
|
31
31
|
copyparty/th_cli.py,sha256=IEX5tCb0gw9Z2aRIDL9bwdvJ6g5jhWZ8OEAAz16_xN4,5426
|
32
|
-
copyparty/th_srv.py,sha256=
|
32
|
+
copyparty/th_srv.py,sha256=6JXHthaZtDreWHmyRxfxN_EyNC2aQOQS5wUFYxxX-3Y,32669
|
33
33
|
copyparty/u2idx.py,sha256=4Y5OOPyVkc-pS0z6e3p4StXAMnjHobSOMmMsvNUTD34,13674
|
34
34
|
copyparty/up2k.py,sha256=nnR_ZKaopSNBuAjSN3Q5G_UVe6GmYD1NkxJt5QQf02o,178079
|
35
35
|
copyparty/util.py,sha256=S-dEme_1rKf3qYgxWWahEUQUzgq_kpoO_nPbuKCwLsY,103948
|
@@ -55,12 +55,13 @@ copyparty/stolen/ifaddr/_posix.py,sha256=-67NdfGrCktfQPakT2fLbjl2U00QMvyBGkSvrUu
|
|
55
55
|
copyparty/stolen/ifaddr/_shared.py,sha256=uNC4SdEIgdSLKvuUzsf1aM-H1Xrc_9mpLoOT43YukGs,6206
|
56
56
|
copyparty/stolen/ifaddr/_win32.py,sha256=EE-QyoBgeB7lYQ6z62VjXNaRozaYfCkaJBHGNA8QtZM,4026
|
57
57
|
copyparty/web/baguettebox.js.gz,sha256=r2c_hOZV_RTyl4CqWWX14FDWP8nnDVwGkDl4Sfk0rU4,8239
|
58
|
-
copyparty/web/browser.css.gz,sha256=
|
58
|
+
copyparty/web/browser.css.gz,sha256=QRTGDf5GmNGCcly_pvxf0sKRCU9T9sQdhJB39_EoYkA,11789
|
59
59
|
copyparty/web/browser.html,sha256=auvhLVE_t0aIN0q-nk0zOWFqITgDhroMAAviBNLoFfc,4788
|
60
|
-
copyparty/web/browser.js.gz,sha256=
|
60
|
+
copyparty/web/browser.js.gz,sha256=1wAt4IULmQM0Mwn0NkbDgypXPumY28C97ViB-PWgAsI,96508
|
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
|
64
|
+
copyparty/web/idp.html,sha256=qOjjvZz6fVk0W8cXiP8fXeTp5KMa_dDV7BRzJNUModo,1481
|
64
65
|
copyparty/web/md.css.gz,sha256=UZpN0J7ubVM05CZkbZYkQRJeGgJt_GNDEzKTGSQd8h4,2032
|
65
66
|
copyparty/web/md.html,sha256=hz-xJVfKtaeTUQn3tGh7ebIMvLbOjVKkrMhsCTr3lGM,4200
|
66
67
|
copyparty/web/md.js.gz,sha256=m5dpIskZZ8FD9X-L0EWpoZP-yLOo-PCWJ7j4AFtHVRI,4163
|
@@ -78,13 +79,13 @@ copyparty/web/shares.css.gz,sha256=SdPlZCBwz9tkPkgEo5pSPDOZSI079njxEfkJ64-iW3c,5
|
|
78
79
|
copyparty/web/shares.html,sha256=YctvUrKuBYu42kxVylyW2_DEHm7Ik6uHqzfzVZ4N0ac,2545
|
79
80
|
copyparty/web/shares.js.gz,sha256=emeY2-wjkh8x1JgaW6ny5fcC7XpZzZzfE1f-sEyntQ4,940
|
80
81
|
copyparty/web/splash.css.gz,sha256=S8_A7JJl71xACRBYGzafeaD82OacW6Fa7oKPiNyrhAs,1087
|
81
|
-
copyparty/web/splash.html,sha256=
|
82
|
-
copyparty/web/splash.js.gz,sha256=
|
82
|
+
copyparty/web/splash.html,sha256=0MvDe1lKfGqczi7d4nKjWjG0cRVyvs8J6sDEj3DCPSI,6376
|
83
|
+
copyparty/web/splash.js.gz,sha256=xMl4Rly-ykhTx7LCI2MK1DpCblFWmFU9uA1rgivgen8,2771
|
83
84
|
copyparty/web/svcs.html,sha256=cxgrhX9wD0Z_kvidry3aS9ubuGXYDj2f4ehq1X8T1EA,14227
|
84
85
|
copyparty/web/svcs.js.gz,sha256=lMXEP9W-VlXyANlva4q0ASSxvvHYlE2CrmxGgZXZop0,713
|
85
86
|
copyparty/web/ui.css.gz,sha256=e3iIflzddmjoyPrun_1jsu9j7fbdonNQLyhEE2oKKOQ,2819
|
86
|
-
copyparty/web/up2k.js.gz,sha256=
|
87
|
-
copyparty/web/util.js.gz,sha256=
|
87
|
+
copyparty/web/up2k.js.gz,sha256=_uOZzORAFO91SG3TUHd9xhKhAIXwL3fUFBNEUKnEVHY,24812
|
88
|
+
copyparty/web/util.js.gz,sha256=qa1B5w3bW7NNOTtuiiiL1ZWboqD9YVNZMKn3y1mf-oU,15247
|
88
89
|
copyparty/web/w.hash.js.gz,sha256=cFH6Xo4YRgH9Wr7RmHMSEfpuTmmIvEmzmSvv4RLmyPU,1193
|
89
90
|
copyparty/web/a/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
90
91
|
copyparty/web/a/partyfuse.py,sha256=9p5Hpg_IBiSimv7j9kmPhCGpy-FLXSRUOYnLjJ5JifU,28049
|
@@ -109,9 +110,9 @@ copyparty/web/deps/prismd.css.gz,sha256=ObUlksQVr-OuYlTz-I4B23TeBg2QDVVGRnWBz8cV
|
|
109
110
|
copyparty/web/deps/scp.woff2,sha256=w99BDU5i8MukkMEL-iW0YO9H4vFFZSPWxbkH70ytaAg,8612
|
110
111
|
copyparty/web/deps/sha512.ac.js.gz,sha256=lFZaCLumgWxrvEuDr4bqdKHsqjX82AbVAb7_F45Yk88,7033
|
111
112
|
copyparty/web/deps/sha512.hw.js.gz,sha256=UAed2_ocklZCnIzcSYz2h4P1ycztlCLj-ewsRTud2lU,7939
|
112
|
-
copyparty-1.18.
|
113
|
-
copyparty-1.18.
|
114
|
-
copyparty-1.18.
|
115
|
-
copyparty-1.18.
|
116
|
-
copyparty-1.18.
|
117
|
-
copyparty-1.18.
|
113
|
+
copyparty-1.18.1.dist-info/licenses/LICENSE,sha256=gOr4h33pCsBEg9uIy9AYmb7qlocL4V9t2uPJS5wllr0,1072
|
114
|
+
copyparty-1.18.1.dist-info/METADATA,sha256=kkkHwOVLPOVY9wUEQvNBoG2ZxxtGv0UmFsx1IIPeX1s,165791
|
115
|
+
copyparty-1.18.1.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
116
|
+
copyparty-1.18.1.dist-info/entry_points.txt,sha256=4zw6a3rqASywQomiYLObjjlxybaI65LYYOTJwgKz7b0,128
|
117
|
+
copyparty-1.18.1.dist-info/top_level.txt,sha256=LnYUPsDyk-8kFgM6YJLG4h820DQekn81cObKSu9g-sI,10
|
118
|
+
copyparty-1.18.1.dist-info/RECORD,,
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|