copyparty 1.17.2__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 +18 -0
- copyparty/__version__.py +3 -3
- copyparty/authsrv.py +93 -17
- copyparty/cfg.py +14 -0
- copyparty/httpcli.py +214 -13
- copyparty/httpconn.py +3 -0
- copyparty/httpsrv.py +16 -0
- copyparty/svchub.py +100 -25
- copyparty/th_srv.py +4 -0
- copyparty/util.py +21 -5
- copyparty/web/browser.css.gz +0 -0
- copyparty/web/browser.js.gz +0 -0
- copyparty/web/deps/marked.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/ui.css.gz +0 -0
- copyparty/web/up2k.js.gz +0 -0
- copyparty/web/util.js.gz +0 -0
- {copyparty-1.17.2.dist-info → copyparty-1.18.1.dist-info}/METADATA +32 -7
- {copyparty-1.17.2.dist-info → copyparty-1.18.1.dist-info}/RECORD +26 -25
- {copyparty-1.17.2.dist-info → copyparty-1.18.1.dist-info}/WHEEL +0 -0
- {copyparty-1.17.2.dist-info → copyparty-1.18.1.dist-info}/entry_points.txt +0 -0
- {copyparty-1.17.2.dist-info → copyparty-1.18.1.dist-info}/licenses/LICENSE +0 -0
- {copyparty-1.17.2.dist-info → copyparty-1.18.1.dist-info}/top_level.txt +0 -0
copyparty/__init__.py
CHANGED
copyparty/__main__.py
CHANGED
@@ -956,6 +956,7 @@ def add_general(ap, nc, srvname):
|
|
956
956
|
ap2.add_argument("--name", metavar="TXT", type=u, default=srvname, help="server name (displayed topleft in browser and in mDNS)")
|
957
957
|
ap2.add_argument("--mime", metavar="EXT=MIME", type=u, action="append", help="map file \033[33mEXT\033[0mension to \033[33mMIME\033[0mtype, for example [\033[32mjpg=image/jpeg\033[0m]")
|
958
958
|
ap2.add_argument("--mimes", action="store_true", help="list default mimetype mapping and exit")
|
959
|
+
ap2.add_argument("--rmagic", action="store_true", help="do expensive analysis to improve accuracy of returned mimetypes; will make file-downloads, rss, and webdav slower (volflag=rmagic)")
|
959
960
|
ap2.add_argument("--license", action="store_true", help="show licenses and exit")
|
960
961
|
ap2.add_argument("--version", action="store_true", help="show versions and exit")
|
961
962
|
|
@@ -1084,12 +1085,16 @@ def add_cert(ap, cert_path):
|
|
1084
1085
|
|
1085
1086
|
|
1086
1087
|
def add_auth(ap):
|
1088
|
+
idp_db = os.path.join(E.cfg, "idp.db")
|
1087
1089
|
ses_db = os.path.join(E.cfg, "sessions.db")
|
1088
1090
|
ap2 = ap.add_argument_group('IdP / identity provider / user authentication options')
|
1089
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")
|
1090
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")
|
1091
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")
|
1092
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)")
|
1093
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")
|
1094
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")
|
1095
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)")
|
@@ -1262,6 +1267,7 @@ def add_optouts(ap):
|
|
1262
1267
|
ap2.add_argument("--no-tarcmp", action="store_true", help="disable download as compressed tar (?tar=gz, ?tar=bz2, ?tar=xz, ?tar=gz:9, ...)")
|
1263
1268
|
ap2.add_argument("--no-lifetime", action="store_true", help="do not allow clients (or server config) to schedule an upload to be deleted after a given time")
|
1264
1269
|
ap2.add_argument("--no-pipe", action="store_true", help="disable race-the-beam (lockstep download of files which are currently being uploaded) (volflag=nopipe)")
|
1270
|
+
ap2.add_argument("--no-tail", action="store_true", help="disable streaming a growing files with ?tail (volflag=notail)")
|
1265
1271
|
ap2.add_argument("--no-db-ip", action="store_true", help="do not write uploader-IP into the database; will also disable unpost, you may want \033[32m--forget-ip\033[0m instead (volflag=no_db_ip)")
|
1266
1272
|
|
1267
1273
|
|
@@ -1391,6 +1397,16 @@ def add_transcoding(ap):
|
|
1391
1397
|
ap2.add_argument("--ac-maxage", metavar="SEC", type=int, default=86400, help="delete cached transcode output after \033[33mSEC\033[0m seconds")
|
1392
1398
|
|
1393
1399
|
|
1400
|
+
def add_tail(ap):
|
1401
|
+
ap2 = ap.add_argument_group('tailing options (realtime streaming of a growing file)')
|
1402
|
+
ap2.add_argument("--tail-who", metavar="LVL", type=int, default=2, help="who can tail? [\033[32m0\033[0m]=nobody, [\033[32m1\033[0m]=admins, [\033[32m2\033[0m]=authenticated-with-read-access, [\033[32m3\033[0m]=everyone-with-read-access (volflag=tail_who)")
|
1403
|
+
ap2.add_argument("--tail-cmax", metavar="N", type=int, default=64, help="do not allow starting a new tail if more than \033[33mN\033[0m active downloads")
|
1404
|
+
ap2.add_argument("--tail-tmax", metavar="SEC", type=float, default=0, help="terminate connection after \033[33mSEC\033[0m seconds; [\033[32m0\033[0m]=never (volflag=tail_tmax)")
|
1405
|
+
ap2.add_argument("--tail-rate", metavar="SEC", type=float, default=0.2, help="check for new data every \033[33mSEC\033[0m seconds (volflag=tail_rate)")
|
1406
|
+
ap2.add_argument("--tail-ka", metavar="SEC", type=float, default=3.0, help="send a zerobyte if connection is idle for \033[33mSEC\033[0m seconds to prevent disconnect")
|
1407
|
+
ap2.add_argument("--tail-fd", metavar="SEC", type=float, default=1.0, help="check if file was replaced (new fd) if idle for \033[33mSEC\033[0m seconds (volflag=tail_fd)")
|
1408
|
+
|
1409
|
+
|
1394
1410
|
def add_rss(ap):
|
1395
1411
|
ap2 = ap.add_argument_group('RSS options')
|
1396
1412
|
ap2.add_argument("--rss", action="store_true", help="enable RSS output (experimental) (volflag=rss)")
|
@@ -1486,6 +1502,7 @@ def add_ui(ap, retry):
|
|
1486
1502
|
ap2.add_argument("--sort", metavar="C,C,C", type=u, default="href", help="default sort order, comma-separated column IDs (see header tooltips), prefix with '-' for descending. Examples: \033[32mhref -href ext sz ts tags/Album tags/.tn\033[0m (volflag=sort)")
|
1487
1503
|
ap2.add_argument("--nsort", action="store_true", help="default-enable natural sort of filenames with leading numbers (volflag=nsort)")
|
1488
1504
|
ap2.add_argument("--hsortn", metavar="N", type=int, default=2, help="number of sorting rules to include in media URLs by default (volflag=hsortn)")
|
1505
|
+
ap2.add_argument("--see-dots", action="store_true", help="default-enable seeing dotfiles; only takes effect if user has the necessary permissions")
|
1489
1506
|
ap2.add_argument("--unlist", metavar="REGEX", type=u, default="", help="don't show files matching \033[33mREGEX\033[0m in file list. Purely cosmetic! Does not affect API calls, just the browser. Example: [\033[32m\\.(js|css)$\033[0m] (volflag=unlist)")
|
1490
1507
|
ap2.add_argument("--favico", metavar="TXT", type=u, default="c 000 none" if retry else "🎉 000 none", help="\033[33mfavicon-text\033[0m [ \033[33mforeground\033[0m [ \033[33mbackground\033[0m ] ], set blank to disable")
|
1491
1508
|
ap2.add_argument("--ext-th", metavar="E=VP", type=u, action="append", help="use thumbnail-image \033[33mVP\033[0m for file-extension \033[33mE\033[0m, example: [\033[32mexe=/.res/exe.png\033[0m] (volflag=ext_th)")
|
@@ -1595,6 +1612,7 @@ def run_argparse(
|
|
1595
1612
|
add_hooks(ap)
|
1596
1613
|
add_stats(ap)
|
1597
1614
|
add_txt(ap)
|
1615
|
+
add_tail(ap)
|
1598
1616
|
add_og(ap)
|
1599
1617
|
add_ui(ap, retry)
|
1600
1618
|
add_admin(ap)
|
copyparty/__version__.py
CHANGED
@@ -1,8 +1,8 @@
|
|
1
1
|
# coding: utf-8
|
2
2
|
|
3
|
-
VERSION = (1,
|
4
|
-
CODENAME = "
|
5
|
-
BUILD_DT = (2025,
|
3
|
+
VERSION = (1, 18, 1)
|
4
|
+
CODENAME = "logtail"
|
5
|
+
BUILD_DT = (2025, 7, 7)
|
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
@@ -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
|
@@ -65,7 +70,9 @@ SSEELOG = " ({})".format(SEE_LOG)
|
|
65
70
|
BAD_CFG = "invalid config; {}".format(SEE_LOG)
|
66
71
|
SBADCFG = " ({})".format(BAD_CFG)
|
67
72
|
|
68
|
-
PTN_U_GRP = re.compile(r"\$\{u%
|
73
|
+
PTN_U_GRP = re.compile(r"\$\{u(%[+-][^}]+)\}")
|
74
|
+
PTN_G_GRP = re.compile(r"\$\{g(%[+-][^}]+)\}")
|
75
|
+
PTN_SIGIL = re.compile(r"(\${[ug][}%])")
|
69
76
|
|
70
77
|
|
71
78
|
class CfgEx(Exception):
|
@@ -926,6 +933,10 @@ class AuthSrv(object):
|
|
926
933
|
return False
|
927
934
|
|
928
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)
|
929
940
|
|
930
941
|
t = "reinitializing due to new user from IdP: [%r:%r]"
|
931
942
|
self.log(t % (uname, gnames), 3)
|
@@ -938,6 +949,21 @@ class AuthSrv(object):
|
|
938
949
|
broker.ask("reload", False, True).get()
|
939
950
|
return True
|
940
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
|
+
|
941
967
|
def _map_volume_idp(
|
942
968
|
self,
|
943
969
|
src ,
|
@@ -958,15 +984,27 @@ class AuthSrv(object):
|
|
958
984
|
un_gn = [("", "")]
|
959
985
|
|
960
986
|
for un, gn in un_gn:
|
961
|
-
|
962
|
-
|
963
|
-
|
964
|
-
|
965
|
-
if req == "+":
|
966
|
-
if not hit:
|
967
|
-
continue
|
968
|
-
elif hit:
|
987
|
+
rejected = False
|
988
|
+
for ptn in [PTN_U_GRP, PTN_G_GRP]:
|
989
|
+
m = ptn.search(dst0)
|
990
|
+
if not m:
|
969
991
|
continue
|
992
|
+
zs = m.group(1)
|
993
|
+
zs = zs.replace(",%+", "\n%+")
|
994
|
+
zs = zs.replace(",%-", "\n%-")
|
995
|
+
for rule in zs.split("\n"):
|
996
|
+
gnc = rule[2:]
|
997
|
+
if ptn == PTN_U_GRP:
|
998
|
+
# is user member of group?
|
999
|
+
hit = gnc in (un_gns.get(un) or [])
|
1000
|
+
else:
|
1001
|
+
# is it this specific group?
|
1002
|
+
hit = gn == gnc
|
1003
|
+
|
1004
|
+
if rule.startswith("%+") != hit:
|
1005
|
+
rejected = True
|
1006
|
+
if rejected:
|
1007
|
+
continue
|
970
1008
|
|
971
1009
|
# if ap/vp has a user/group placeholder, make sure to keep
|
972
1010
|
# track so the same user/group is mapped when setting perms;
|
@@ -981,6 +1019,8 @@ class AuthSrv(object):
|
|
981
1019
|
|
982
1020
|
src = src1.replace("${g}", gn or "\n")
|
983
1021
|
dst = dst1.replace("${g}", gn or "\n")
|
1022
|
+
src = PTN_G_GRP.sub(gn or "\n", src)
|
1023
|
+
dst = PTN_G_GRP.sub(gn or "\n", dst)
|
984
1024
|
if src == src1 and dst == dst1:
|
985
1025
|
gn = ""
|
986
1026
|
|
@@ -1072,6 +1112,7 @@ class AuthSrv(object):
|
|
1072
1112
|
* any non-zero value from IdP group header
|
1073
1113
|
* otherwise take --grps / [groups]
|
1074
1114
|
"""
|
1115
|
+
self.load_idp_db(bool(self.idp_accs))
|
1075
1116
|
ret = {un: gns[:] for un, gns in self.idp_accs.items()}
|
1076
1117
|
ret.update({zs: [""] for zs in acct if zs not in ret})
|
1077
1118
|
for gn, uns in grps.items():
|
@@ -1632,7 +1673,6 @@ class AuthSrv(object):
|
|
1632
1673
|
shr = enshare[1:-1]
|
1633
1674
|
shrs = enshare[1:]
|
1634
1675
|
if enshare:
|
1635
|
-
import sqlite3
|
1636
1676
|
|
1637
1677
|
zsd = {"d2d": True, "tcolor": self.args.tcolor}
|
1638
1678
|
shv = VFS(self.log_func, "", shr, shr, AXS(), zsd)
|
@@ -1855,7 +1895,7 @@ class AuthSrv(object):
|
|
1855
1895
|
is_shr = shr and zv.vpath.split("/")[0] == shr
|
1856
1896
|
if histp and not is_shr and histp in rhisttab:
|
1857
1897
|
zv2 = rhisttab[histp]
|
1858
|
-
t = "invalid config; multiple volumes share the same histpath (database+thumbnails location):\n histpath: %s\n volume 1: /%s [%s]\n volume 2:
|
1898
|
+
t = "invalid config; multiple volumes share the same histpath (database+thumbnails location):\n histpath: %s\n volume 1: /%s [%s]\n volume 2: /%s [%s]"
|
1859
1899
|
t = t % (histp, zv2.vpath, zv2.realpath, zv.vpath, zv.realpath)
|
1860
1900
|
self.log(t, 1)
|
1861
1901
|
raise Exception(t)
|
@@ -1869,7 +1909,7 @@ class AuthSrv(object):
|
|
1869
1909
|
is_shr = shr and zv.vpath.split("/")[0] == shr
|
1870
1910
|
if dbp and not is_shr and dbp in rdbpaths:
|
1871
1911
|
zv2 = rdbpaths[dbp]
|
1872
|
-
t = "invalid config; multiple volumes share the same dbpath (database location):\n dbpath: %s\n volume 1: /%s [%s]\n volume 2:
|
1912
|
+
t = "invalid config; multiple volumes share the same dbpath (database location):\n dbpath: %s\n volume 1: /%s [%s]\n volume 2: /%s [%s]"
|
1873
1913
|
t = t % (dbp, zv2.vpath, zv2.realpath, zv.vpath, zv.realpath)
|
1874
1914
|
self.log(t, 1)
|
1875
1915
|
raise Exception(t)
|
@@ -2052,12 +2092,13 @@ class AuthSrv(object):
|
|
2052
2092
|
if vf not in vol.flags:
|
2053
2093
|
vol.flags[vf] = getattr(self.args, ga)
|
2054
2094
|
|
2055
|
-
zs = "forget_ip nrand u2abort u2ow ups_who zip_who"
|
2095
|
+
zs = "forget_ip nrand tail_who u2abort u2ow ups_who zip_who"
|
2056
2096
|
for k in zs.split():
|
2057
2097
|
if k in vol.flags:
|
2058
2098
|
vol.flags[k] = int(vol.flags[k])
|
2059
2099
|
|
2060
|
-
|
2100
|
+
zs = "convt tail_fd tail_rate tail_tmax"
|
2101
|
+
for k in zs.split():
|
2061
2102
|
if k in vol.flags:
|
2062
2103
|
vol.flags[k] = float(vol.flags[k])
|
2063
2104
|
|
@@ -2386,7 +2427,7 @@ class AuthSrv(object):
|
|
2386
2427
|
idp_vn, _ = vfs.get(idp_vp, "*", False, False)
|
2387
2428
|
idp_vp0 = idp_vn.vpath0
|
2388
2429
|
|
2389
|
-
sigils = set(
|
2430
|
+
sigils = set(PTN_SIGIL.findall(idp_vp0))
|
2390
2431
|
if len(sigils) > 1:
|
2391
2432
|
t = '\nWARNING: IdP-volume "/%s" created by "/%s" has multiple IdP placeholders: %s'
|
2392
2433
|
self.idp_warn.append(t % (idp_vp, idp_vp0, list(sigils)))
|
@@ -2556,6 +2597,7 @@ class AuthSrv(object):
|
|
2556
2597
|
"txt_ext": self.args.textfiles.replace(",", " "),
|
2557
2598
|
"def_hcols": list(vf.get("mth") or []),
|
2558
2599
|
"unlist0": vf.get("unlist") or "",
|
2600
|
+
"see_dots": self.args.see_dots,
|
2559
2601
|
"dgrid": "grid" in vf,
|
2560
2602
|
"dgsel": "gsel" in vf,
|
2561
2603
|
"dnsort": "nsort" in vf,
|
@@ -2595,6 +2637,42 @@ class AuthSrv(object):
|
|
2595
2637
|
zs = str(vol.flags.get("tcolor") or self.args.tcolor)
|
2596
2638
|
vol.flags["tcolor"] = zs.lstrip("#")
|
2597
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
|
+
|
2598
2676
|
def load_sessions(self, quiet=False) :
|
2599
2677
|
# mutex me
|
2600
2678
|
if self.args.no_ses:
|
@@ -2602,7 +2680,6 @@ class AuthSrv(object):
|
|
2602
2680
|
self.sesa = {}
|
2603
2681
|
return
|
2604
2682
|
|
2605
|
-
import sqlite3
|
2606
2683
|
|
2607
2684
|
ases = {}
|
2608
2685
|
blen = (self.args.ses_len // 4) * 4 # 3 bytes in 4 chars
|
@@ -2649,7 +2726,6 @@ class AuthSrv(object):
|
|
2649
2726
|
if self.args.no_ses:
|
2650
2727
|
return
|
2651
2728
|
|
2652
|
-
import sqlite3
|
2653
2729
|
|
2654
2730
|
db = sqlite3.connect(self.args.ses_db)
|
2655
2731
|
cur = db.cursor()
|
copyparty/cfg.py
CHANGED
@@ -22,6 +22,7 @@ def vf_bmap() :
|
|
22
22
|
"no_forget": "noforget",
|
23
23
|
"no_pipe": "nopipe",
|
24
24
|
"no_robots": "norobots",
|
25
|
+
"no_tail": "notail",
|
25
26
|
"no_thumb": "dthumb",
|
26
27
|
"no_vthumb": "dvthumb",
|
27
28
|
"no_athumb": "dathumb",
|
@@ -51,6 +52,7 @@ def vf_bmap() :
|
|
51
52
|
"og_no_head",
|
52
53
|
"og_s_title",
|
53
54
|
"rand",
|
55
|
+
"rmagic",
|
54
56
|
"rss",
|
55
57
|
"wo_up_readme",
|
56
58
|
"xdev",
|
@@ -101,6 +103,10 @@ def vf_vmap() :
|
|
101
103
|
"mv_retry",
|
102
104
|
"rm_retry",
|
103
105
|
"sort",
|
106
|
+
"tail_fd",
|
107
|
+
"tail_rate",
|
108
|
+
"tail_tmax",
|
109
|
+
"tail_who",
|
104
110
|
"tcolor",
|
105
111
|
"unlist",
|
106
112
|
"u2abort",
|
@@ -304,6 +310,13 @@ flagcats = {
|
|
304
310
|
"exp_md": "placeholders to expand in markdown files; see --help",
|
305
311
|
"exp_lg": "placeholders to expand in prologue/epilogue; see --help",
|
306
312
|
},
|
313
|
+
"tailing": {
|
314
|
+
"notail": "disable ?tail (download a growing file continuously)",
|
315
|
+
"tail_fd=1": "check if file was replaced (new fd) every 1 sec",
|
316
|
+
"tail_rate=0.2": "check for new data every 0.2 sec",
|
317
|
+
"tail_tmax=30": "kill connection after 30 sec",
|
318
|
+
"tail_who=2": "restrict ?tail access (1=admins,2=authed,3=everyone)",
|
319
|
+
},
|
307
320
|
"others": {
|
308
321
|
"dots": "allow all users with read-access to\nenable the option to show dotfiles in listings",
|
309
322
|
"fk=8": 'generates per-file accesskeys,\nwhich are then required at the "g" permission;\nkeys are invalidated if filesize or inode changes',
|
@@ -312,6 +325,7 @@ flagcats = {
|
|
312
325
|
"dks": "per-directory accesskeys allow browsing into subdirs",
|
313
326
|
"dky": 'allow seeing files (not folders) inside a specific folder\nwith "g" perm, and does not require a valid dirkey to do so',
|
314
327
|
"rss": "allow '?rss' URL suffix (experimental)",
|
328
|
+
"rmagic": "expensive analysis for mimetype accuracy",
|
315
329
|
"ups_who=2": "restrict viewing the list of recent uploads",
|
316
330
|
"zip_who=2": "restrict access to download-as-zip/tar",
|
317
331
|
"zipmaxn=9k": "reject download-as-zip if more than 9000 files",
|