copyparty 1.18.10__py3-none-any.whl → 1.19.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/__main__.py +82 -68
- copyparty/__version__.py +3 -3
- copyparty/authsrv.py +23 -0
- copyparty/cfg.py +2 -0
- copyparty/ftpd.py +7 -2
- copyparty/httpcli.py +76 -23
- copyparty/mdns.py +2 -1
- copyparty/multicast.py +1 -5
- copyparty/pwhash.py +4 -0
- copyparty/svchub.py +2 -11
- copyparty/tcpsrv.py +14 -3
- copyparty/tftpd.py +1 -1
- copyparty/up2k.py +3 -2
- copyparty/util.py +11 -0
- copyparty/web/browser.css.gz +0 -0
- copyparty/web/browser.js.gz +0 -0
- copyparty/web/md2.js.gz +0 -0
- copyparty/web/mde.js.gz +0 -0
- copyparty/web/rups.html +1 -8
- copyparty/web/rups.js.gz +0 -0
- copyparty/web/shares.js.gz +0 -0
- copyparty/web/splash.html +6 -1
- copyparty/web/splash.js.gz +0 -0
- copyparty/web/svcs.html +1 -0
- copyparty/web/svcs.js.gz +0 -0
- copyparty/web/up2k.js.gz +0 -0
- copyparty/web/util.js.gz +0 -0
- {copyparty-1.18.10.dist-info → copyparty-1.19.1.dist-info}/METADATA +22 -8
- {copyparty-1.18.10.dist-info → copyparty-1.19.1.dist-info}/RECORD +33 -33
- {copyparty-1.18.10.dist-info → copyparty-1.19.1.dist-info}/WHEEL +0 -0
- {copyparty-1.18.10.dist-info → copyparty-1.19.1.dist-info}/entry_points.txt +0 -0
- {copyparty-1.18.10.dist-info → copyparty-1.19.1.dist-info}/licenses/LICENSE +0 -0
- {copyparty-1.18.10.dist-info → copyparty-1.19.1.dist-info}/top_level.txt +0 -0
copyparty/__main__.py
CHANGED
@@ -528,7 +528,7 @@ def get_sects():
|
|
528
528
|
dedent(
|
529
529
|
"""
|
530
530
|
\033[33m-i\033[0m takes a comma-separated list of interfaces to listen on;
|
531
|
-
IP-addresses and/or
|
531
|
+
IP-addresses, unix-sockets, and/or open file descriptors
|
532
532
|
|
533
533
|
the default (\033[32m-i ::\033[0m) means all IPv4 and IPv6 addresses
|
534
534
|
|
@@ -554,7 +554,9 @@ def get_sects():
|
|
554
554
|
\033[32m-i unix:\033[33m/dev/shm/party.sock\033[0m keeps umask-defined permission
|
555
555
|
(usually \033[33m0600\033[0m) and the same user/group as copyparty
|
556
556
|
|
557
|
-
\033[
|
557
|
+
\033[32m-i fd:\033[33m3\033[0m uses the socket passed to copyparty on file descriptor 3
|
558
|
+
|
559
|
+
\033[33m-p\033[0m (tcp ports) is ignored for unix-sockets and FDs
|
558
560
|
"""
|
559
561
|
),
|
560
562
|
],
|
@@ -908,6 +910,9 @@ def get_sects():
|
|
908
910
|
copyparty will also hash and print any passwords that are non-hashed
|
909
911
|
(password which do not start with '+') and then terminate afterwards
|
910
912
|
|
913
|
+
if you have enabled --usernames then the password
|
914
|
+
must be provided as username:password for hashing
|
915
|
+
|
911
916
|
\033[36m--ah-alg\033[0m specifies the hashing algorithm and a
|
912
917
|
list of optional comma-separated arguments:
|
913
918
|
|
@@ -985,18 +990,19 @@ def build_flags_desc():
|
|
985
990
|
|
986
991
|
|
987
992
|
def add_general(ap, nc, srvname):
|
988
|
-
ap2 = ap.add_argument_group(
|
989
|
-
ap2.add_argument("-c", metavar="PATH", type=u, default=CFG_DEF, action="append", help="add config file")
|
993
|
+
ap2 = ap.add_argument_group("general options")
|
994
|
+
ap2.add_argument("-c", metavar="PATH", type=u, default=CFG_DEF, action="append", help="\033[34mREPEATABLE:\033[0m add config file")
|
990
995
|
ap2.add_argument("-nc", metavar="NUM", type=int, default=nc, help="max num clients")
|
991
996
|
ap2.add_argument("-j", metavar="CORES", type=int, default=1, help="max num cpu cores, 0=all")
|
992
|
-
ap2.add_argument("-a", metavar="ACCT", type=u, action="append", help="add account, \033[33mUSER\033[0m:\033[33mPASS\033[0m; example [\033[32med:wark\033[0m]")
|
993
|
-
ap2.add_argument("-v", metavar="VOL", type=u, action="append", help="add volume, \033[33mSRC\033[0m:\033[33mDST\033[0m:\033[33mFLAG\033[0m; examples [\033[32m.::r\033[0m], [\033[32m/mnt/nas/music:/music:r:aed\033[0m], see --help-accounts")
|
994
|
-
ap2.add_argument("--grp", metavar="G:N,N", type=u, action="append", help="add group, \033[33mNAME\033[0m:\033[33mUSER1\033[0m,\033[33mUSER2\033[0m,\033[33m...\033[0m; example [\033[32madmins:ed,foo,bar\033[0m]")
|
997
|
+
ap2.add_argument("-a", metavar="ACCT", type=u, action="append", help="\033[34mREPEATABLE:\033[0m add account, \033[33mUSER\033[0m:\033[33mPASS\033[0m; example [\033[32med:wark\033[0m]")
|
998
|
+
ap2.add_argument("-v", metavar="VOL", type=u, action="append", help="\033[34mREPEATABLE:\033[0m add volume, \033[33mSRC\033[0m:\033[33mDST\033[0m:\033[33mFLAG\033[0m; examples [\033[32m.::r\033[0m], [\033[32m/mnt/nas/music:/music:r:aed\033[0m], see --help-accounts")
|
999
|
+
ap2.add_argument("--grp", metavar="G:N,N", type=u, action="append", help="\033[34mREPEATABLE:\033[0m add group, \033[33mNAME\033[0m:\033[33mUSER1\033[0m,\033[33mUSER2\033[0m,\033[33m...\033[0m; example [\033[32madmins:ed,foo,bar\033[0m]")
|
1000
|
+
ap2.add_argument("--usernames", action="store_true", help="require username and password for login; default is just password")
|
995
1001
|
ap2.add_argument("-ed", action="store_true", help="enable the ?dots url parameter / client option which allows clients to see dotfiles / hidden files (volflag=dots)")
|
996
1002
|
ap2.add_argument("--urlform", metavar="MODE", type=u, default="print,xm", help="how to handle url-form POSTs; see \033[33m--help-urlform\033[0m")
|
997
1003
|
ap2.add_argument("--wintitle", metavar="TXT", type=u, default="cpp @ $pub", help="server terminal title, for example [\033[32m$ip-10.1.2.\033[0m] or [\033[32m$ip-]")
|
998
1004
|
ap2.add_argument("--name", metavar="TXT", type=u, default=srvname, help="server name (displayed topleft in browser and in mDNS)")
|
999
|
-
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]")
|
1005
|
+
ap2.add_argument("--mime", metavar="EXT=MIME", type=u, action="append", help="\033[34mREPEATABLE:\033[0m map file \033[33mEXT\033[0mension to \033[33mMIME\033[0mtype, for example [\033[32mjpg=image/jpeg\033[0m]")
|
1000
1006
|
ap2.add_argument("--mimes", action="store_true", help="list default mimetype mapping and exit")
|
1001
1007
|
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)")
|
1002
1008
|
ap2.add_argument("--license", action="store_true", help="show licenses and exit")
|
@@ -1004,7 +1010,7 @@ def add_general(ap, nc, srvname):
|
|
1004
1010
|
|
1005
1011
|
|
1006
1012
|
def add_qr(ap, tty):
|
1007
|
-
ap2 = ap.add_argument_group(
|
1013
|
+
ap2 = ap.add_argument_group("qr options")
|
1008
1014
|
ap2.add_argument("--qr", action="store_true", help="show http:// QR-code on startup")
|
1009
1015
|
ap2.add_argument("--qrs", action="store_true", help="show https:// QR-code on startup")
|
1010
1016
|
ap2.add_argument("--qrl", metavar="PATH", type=u, default="", help="location to include in the url, for example [\033[32mpriv/?pw=hunter2\033[0m]")
|
@@ -1026,7 +1032,7 @@ def add_fs(ap):
|
|
1026
1032
|
|
1027
1033
|
def add_share(ap):
|
1028
1034
|
db_path = os.path.join(E.cfg, "shares.db")
|
1029
|
-
ap2 = ap.add_argument_group(
|
1035
|
+
ap2 = ap.add_argument_group("share-url options")
|
1030
1036
|
ap2.add_argument("--shr", metavar="DIR", type=u, default="", help="toplevel virtual folder for shared files/folders, for example [\033[32m/share\033[0m]")
|
1031
1037
|
ap2.add_argument("--shr-db", metavar="FILE", type=u, default=db_path, help="database to store shares in")
|
1032
1038
|
ap2.add_argument("--shr-adm", metavar="U,U", type=u, default="", help="comma-separated list of users allowed to view/delete any share")
|
@@ -1035,7 +1041,7 @@ def add_share(ap):
|
|
1035
1041
|
|
1036
1042
|
|
1037
1043
|
def add_upload(ap):
|
1038
|
-
ap2 = ap.add_argument_group(
|
1044
|
+
ap2 = ap.add_argument_group("upload options")
|
1039
1045
|
ap2.add_argument("--dotpart", action="store_true", help="dotfile incomplete uploads, hiding them from clients unless \033[33m-ed\033[0m")
|
1040
1046
|
ap2.add_argument("--plain-ip", action="store_true", help="when avoiding filename collisions by appending the uploader's ip to the filename: append the plaintext ip instead of salting and hashing the ip")
|
1041
1047
|
ap2.add_argument("--put-name", metavar="TXT", type=u, default="put-{now.6f}-{cip}.bin", help="filename for nameless uploads (when uploader doesn't provide a name); default is [\033[32mput-UNIXTIME-IP.bin\033[0m] (the \033[32m.6f\033[0m means six decimal places) (volflag=put_name)")
|
@@ -1077,14 +1083,14 @@ def add_upload(ap):
|
|
1077
1083
|
|
1078
1084
|
|
1079
1085
|
def add_network(ap):
|
1080
|
-
ap2 = ap.add_argument_group(
|
1081
|
-
ap2.add_argument("-i", metavar="IP", type=u, default="::", help="IPs and/or unix-sockets to listen on (see \033[33m--help-bind\033[0m). Default: all IPv4 and IPv6")
|
1086
|
+
ap2 = ap.add_argument_group("network options")
|
1087
|
+
ap2.add_argument("-i", metavar="IP", type=u, default="::", help="IPs and/or unix-sockets to listen on (comma-separated list; see \033[33m--help-bind\033[0m). Default: all IPv4 and IPv6")
|
1082
1088
|
ap2.add_argument("-p", metavar="PORT", type=u, default="3923", help="ports to listen on (comma/range); ignored for unix-sockets")
|
1083
1089
|
ap2.add_argument("--ll", action="store_true", help="include link-local IPv4/IPv6 in mDNS replies, even if the NIC has routable IPs (breaks some mDNS clients)")
|
1084
|
-
ap2.add_argument("--rproxy", metavar="DEPTH", type=int, default=
|
1090
|
+
ap2.add_argument("--rproxy", metavar="DEPTH", type=int, default=9999999, help="which ip to associate clients with; [\033[32m0\033[0m]=tcp, [\033[32m1\033[0m]=origin (first x-fwd, unsafe), [\033[32m-1\033[0m]=closest-proxy, [\033[32m-2\033[0m]=second-hop, [\033[32m-3\033[0m]=third-hop")
|
1085
1091
|
ap2.add_argument("--xff-hdr", metavar="NAME", type=u, default="x-forwarded-for", help="if reverse-proxied, which http header to read the client's real ip from")
|
1086
|
-
ap2.add_argument("--xff-src", metavar="CIDR", type=u, default="127.0.0.0/8, ::1/128", help="
|
1087
|
-
ap2.add_argument("--ipa", metavar="CIDR", type=u, default="", help="only accept connections from IP-addresses inside \033[33mCIDR\033[0m; examples: [\033[32mlan\033[0m] or [\033[32m10.89.0.0/16, 192.168.33.0/24\033[0m]")
|
1092
|
+
ap2.add_argument("--xff-src", metavar="CIDR", type=u, default="127.0.0.0/8, ::1/128", help="list of trusted reverse-proxy CIDRs (comma-separated); only accept the real-ip header (\033[33m--xff-hdr\033[0m) and IdP headers if the incoming connection is from an IP within either of these subnets. Specify [\033[32mlan\033[0m] to allow all LAN / private / non-internet IPs. Can be disabled with [\033[32many\033[0m] if you are behind cloudflare (or similar) and are using \033[32m--xff-hdr=cf-connecting-ip\033[0m (or similar)")
|
1093
|
+
ap2.add_argument("--ipa", metavar="CIDR", type=u, default="", help="only accept connections from IP-addresses inside \033[33mCIDR\033[0m (comma-separated); examples: [\033[32mlan\033[0m] or [\033[32m10.89.0.0/16, 192.168.33.0/24\033[0m]")
|
1088
1094
|
ap2.add_argument("--rp-loc", metavar="PATH", type=u, default="", help="if reverse-proxying on a location instead of a dedicated domain/subdomain, provide the base location here; example: [\033[32m/foo/bar\033[0m]")
|
1089
1095
|
if ANYWIN:
|
1090
1096
|
ap2.add_argument("--reuseaddr", action="store_true", help="set reuseaddr on listening sockets on windows; allows rapid restart of copyparty at the expense of being able to accidentally start multiple instances")
|
@@ -1102,7 +1108,7 @@ def add_network(ap):
|
|
1102
1108
|
|
1103
1109
|
|
1104
1110
|
def add_tls(ap, cert_path):
|
1105
|
-
ap2 = ap.add_argument_group(
|
1111
|
+
ap2 = ap.add_argument_group("SSL/TLS options")
|
1106
1112
|
ap2.add_argument("--http-only", action="store_true", help="disable ssl/tls -- force plaintext")
|
1107
1113
|
ap2.add_argument("--https-only", action="store_true", help="disable plaintext -- force tls")
|
1108
1114
|
ap2.add_argument("--cert", metavar="PATH", type=u, default=cert_path, help="path to file containing a concatenation of TLS key and certificate chain")
|
@@ -1114,7 +1120,7 @@ def add_tls(ap, cert_path):
|
|
1114
1120
|
|
1115
1121
|
def add_cert(ap, cert_path):
|
1116
1122
|
cert_dir = os.path.dirname(cert_path)
|
1117
|
-
ap2 = ap.add_argument_group(
|
1123
|
+
ap2 = ap.add_argument_group("TLS certificate generator options")
|
1118
1124
|
ap2.add_argument("--no-crt", action="store_true", help="disable automatic certificate creation")
|
1119
1125
|
ap2.add_argument("--crt-ns", metavar="N,N", type=u, default="", help="comma-separated list of FQDNs (domains) to add into the certificate")
|
1120
1126
|
ap2.add_argument("--crt-exact", action="store_true", help="do not add wildcard entries for each \033[33m--crt-ns\033[0m")
|
@@ -1134,7 +1140,7 @@ def add_cert(ap, cert_path):
|
|
1134
1140
|
def add_auth(ap):
|
1135
1141
|
idp_db = os.path.join(E.cfg, "idp.db")
|
1136
1142
|
ses_db = os.path.join(E.cfg, "sessions.db")
|
1137
|
-
ap2 = ap.add_argument_group(
|
1143
|
+
ap2 = ap.add_argument_group("IdP / identity provider / user authentication options")
|
1138
1144
|
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")
|
1139
1145
|
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")
|
1140
1146
|
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")
|
@@ -1148,14 +1154,14 @@ def add_auth(ap):
|
|
1148
1154
|
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)")
|
1149
1155
|
ap2.add_argument("--ses-len", metavar="CHARS", type=int, default=20, help="session key length; default is 120 bits ((20//4)*4*6)")
|
1150
1156
|
ap2.add_argument("--no-ses", action="store_true", help="disable sessions; use plaintext passwords in cookies")
|
1151
|
-
ap2.add_argument("--ipu", metavar="CIDR=USR", type=u, action="append", help="users with IP matching \033[33mCIDR\033[0m are auto-authenticated as username \033[33mUSR\033[0m; example: [\033[32m172.16.24.0/24=dave]")
|
1157
|
+
ap2.add_argument("--ipu", metavar="CIDR=USR", type=u, action="append", help="\033[34mREPEATABLE:\033[0m users with IP matching \033[33mCIDR\033[0m are auto-authenticated as username \033[33mUSR\033[0m; example: [\033[32m172.16.24.0/24=dave]")
|
1152
1158
|
|
1153
1159
|
|
1154
1160
|
def add_chpw(ap):
|
1155
1161
|
db_path = os.path.join(E.cfg, "chpw.json")
|
1156
|
-
ap2 = ap.add_argument_group(
|
1162
|
+
ap2 = ap.add_argument_group("user-changeable passwords options")
|
1157
1163
|
ap2.add_argument("--chpw", action="store_true", help="allow users to change their own passwords")
|
1158
|
-
ap2.add_argument("--chpw-no", metavar="U,U,U", type=u, action="append", help="do not allow password-changes for this comma-separated list of usernames")
|
1164
|
+
ap2.add_argument("--chpw-no", metavar="U,U,U", type=u, action="append", help="\033[34mREPEATABLE:\033[0m do not allow password-changes for this comma-separated list of usernames")
|
1159
1165
|
ap2.add_argument("--chpw-db", metavar="PATH", type=u, default=db_path, help="where to store the passwords database (if you run multiple copyparty instances, make sure they use different DBs)")
|
1160
1166
|
ap2.add_argument("--chpw-len", metavar="N", type=int, default=8, help="minimum password length")
|
1161
1167
|
ap2.add_argument("--chpw-v", metavar="LVL", type=int, default=2, help="verbosity of summary on config load [\033[32m0\033[0m] = nothing at all, [\033[32m1\033[0m] = number of users, [\033[32m2\033[0m] = list users with default-pw, [\033[32m3\033[0m] = list all users")
|
@@ -1187,6 +1193,7 @@ def add_zc_mdns(ap):
|
|
1187
1193
|
ap2.add_argument("--zm-lh", metavar="PATH", type=u, default="", help="link a specific folder for http shares")
|
1188
1194
|
ap2.add_argument("--zm-lf", metavar="PATH", type=u, default="", help="link a specific folder for ftp shares")
|
1189
1195
|
ap2.add_argument("--zm-ls", metavar="PATH", type=u, default="", help="link a specific folder for smb shares")
|
1196
|
+
ap2.add_argument("--zm-fqdn", metavar="FQDN", type=u, default="--name.local", help="the domain to announce; NOTE: using anything other than .local is nonstandard and could cause problems")
|
1190
1197
|
ap2.add_argument("--zm-mnic", action="store_true", help="merge NICs which share subnets; assume that same subnet means same network")
|
1191
1198
|
ap2.add_argument("--zm-msub", action="store_true", help="merge subnets on each NIC -- always enabled for ipv6 -- reduces network load, but gnome-gvfs clients may stop working, and clients cannot be in subnets that the server is not")
|
1192
1199
|
ap2.add_argument("--zm-noneg", action="store_true", help="disable NSEC replies -- try this if some clients don't see copyparty")
|
@@ -1204,12 +1211,12 @@ def add_zc_ssdp(ap):
|
|
1204
1211
|
|
1205
1212
|
|
1206
1213
|
def add_ftp(ap):
|
1207
|
-
ap2 = ap.add_argument_group(
|
1214
|
+
ap2 = ap.add_argument_group("FTP options (TCP only)")
|
1208
1215
|
ap2.add_argument("--ftp", metavar="PORT", type=int, default=0, help="enable FTP server on \033[33mPORT\033[0m, for example \033[32m3921")
|
1209
1216
|
ap2.add_argument("--ftps", metavar="PORT", type=int, default=0, help="enable FTPS server on \033[33mPORT\033[0m, for example \033[32m3990")
|
1210
1217
|
ap2.add_argument("--ftpv", action="store_true", help="verbose")
|
1211
1218
|
ap2.add_argument("--ftp4", action="store_true", help="only listen on IPv4")
|
1212
|
-
ap2.add_argument("--ftp-ipa", metavar="CIDR", type=u, default="", help="only accept connections from IP-addresses inside \033[33mCIDR\033[0m; specify [\033[32many\033[0m] to disable inheriting \033[33m--ipa\033[0m. Examples: [\033[32mlan\033[0m] or [\033[32m10.89.0.0/16, 192.168.33.0/24\033[0m]")
|
1219
|
+
ap2.add_argument("--ftp-ipa", metavar="CIDR", type=u, default="", help="only accept connections from IP-addresses inside \033[33mCIDR\033[0m (comma-separated); specify [\033[32many\033[0m] to disable inheriting \033[33m--ipa\033[0m. Examples: [\033[32mlan\033[0m] or [\033[32m10.89.0.0/16, 192.168.33.0/24\033[0m]")
|
1213
1220
|
ap2.add_argument("--ftp-no-ow", action="store_true", help="if target file exists, reject upload instead of overwrite")
|
1214
1221
|
ap2.add_argument("--ftp-wt", metavar="SEC", type=int, default=7, help="grace period for resuming interrupted uploads (any client can write to any file last-modified more recently than \033[33mSEC\033[0m seconds ago)")
|
1215
1222
|
ap2.add_argument("--ftp-nat", metavar="ADDR", type=u, default="", help="the NAT address to use for passive connections")
|
@@ -1217,7 +1224,7 @@ def add_ftp(ap):
|
|
1217
1224
|
|
1218
1225
|
|
1219
1226
|
def add_webdav(ap):
|
1220
|
-
ap2 = ap.add_argument_group(
|
1227
|
+
ap2 = ap.add_argument_group("WebDAV options")
|
1221
1228
|
ap2.add_argument("--daw", action="store_true", help="enable full write support, even if client may not be webdav. \033[1;31mWARNING:\033[0m This has side-effects -- PUT-operations will now \033[1;31mOVERWRITE\033[0m existing files, rather than inventing new filenames to avoid loss of data. You might want to instead set this as a volflag where needed. By not setting this flag, uploaded files can get written to a filename which the client does not expect (which might be okay, depending on client)")
|
1222
1229
|
ap2.add_argument("--dav-inf", action="store_true", help="allow depth:infinite requests (recursive file listing); extremely server-heavy but required for spec compliance -- luckily few clients rely on this")
|
1223
1230
|
ap2.add_argument("--dav-mac", action="store_true", help="disable apple-garbage filter -- allow macos to create junk files (._* and .DS_Store, .Spotlight-*, .fseventsd, .Trashes, .AppleDouble, __MACOS)")
|
@@ -1227,7 +1234,7 @@ def add_webdav(ap):
|
|
1227
1234
|
|
1228
1235
|
|
1229
1236
|
def add_tftp(ap):
|
1230
|
-
ap2 = ap.add_argument_group(
|
1237
|
+
ap2 = ap.add_argument_group("TFTP options (UDP only)")
|
1231
1238
|
ap2.add_argument("--tftp", metavar="PORT", type=int, default=0, help="enable TFTP server on \033[33mPORT\033[0m, for example \033[32m69 \033[0mor \033[32m3969")
|
1232
1239
|
ap2.add_argument("--tftp4", action="store_true", help="only listen on IPv4")
|
1233
1240
|
ap2.add_argument("--tftpv", action="store_true", help="verbose")
|
@@ -1235,12 +1242,12 @@ def add_tftp(ap):
|
|
1235
1242
|
ap2.add_argument("--tftp-no-fast", action="store_true", help="debug: disable optimizations")
|
1236
1243
|
ap2.add_argument("--tftp-lsf", metavar="PTN", type=u, default="\\.?(dir|ls)(\\.txt)?", help="return a directory listing if a file with this name is requested and it does not exist; defaults matches .ls, dir, .dir.txt, ls.txt, ...")
|
1237
1244
|
ap2.add_argument("--tftp-nols", action="store_true", help="if someone tries to download a directory, return an error instead of showing its directory listing")
|
1238
|
-
ap2.add_argument("--tftp-ipa", metavar="CIDR", type=u, default="", help="only accept connections from IP-addresses inside \033[33mCIDR\033[0m; specify [\033[32many\033[0m] to disable inheriting \033[33m--ipa\033[0m. Examples: [\033[32mlan\033[0m] or [\033[32m10.89.0.0/16, 192.168.33.0/24\033[0m]")
|
1245
|
+
ap2.add_argument("--tftp-ipa", metavar="CIDR", type=u, default="", help="only accept connections from IP-addresses inside \033[33mCIDR\033[0m (comma-separated); specify [\033[32many\033[0m] to disable inheriting \033[33m--ipa\033[0m. Examples: [\033[32mlan\033[0m] or [\033[32m10.89.0.0/16, 192.168.33.0/24\033[0m]")
|
1239
1246
|
ap2.add_argument("--tftp-pr", metavar="P-P", type=u, default="", help="the range of UDP ports to use for data transfer, for example \033[32m12000-13000")
|
1240
1247
|
|
1241
1248
|
|
1242
1249
|
def add_smb(ap):
|
1243
|
-
ap2 = ap.add_argument_group(
|
1250
|
+
ap2 = ap.add_argument_group("SMB/CIFS options")
|
1244
1251
|
ap2.add_argument("--smb", action="store_true", help="enable smb (read-only) -- this requires running copyparty as root on linux and macos unless \033[33m--smb-port\033[0m is set above 1024 and your OS does port-forwarding from 445 to that.\n\033[1;31mWARNING:\033[0m this protocol is DANGEROUS and buggy! Never expose to the internet!")
|
1245
1252
|
ap2.add_argument("--smbw", action="store_true", help="enable write support (please dont)")
|
1246
1253
|
ap2.add_argument("--smb1", action="store_true", help="disable SMBv2, only enable SMBv1 (CIFS)")
|
@@ -1254,30 +1261,30 @@ def add_smb(ap):
|
|
1254
1261
|
|
1255
1262
|
|
1256
1263
|
def add_handlers(ap):
|
1257
|
-
ap2 = ap.add_argument_group(
|
1258
|
-
ap2.add_argument("--on404", metavar="PY", type=u, action="append", help="handle 404s by executing \033[33mPY\033[0m file")
|
1259
|
-
ap2.add_argument("--on403", metavar="PY", type=u, action="append", help="handle 403s by executing \033[33mPY\033[0m file")
|
1264
|
+
ap2 = ap.add_argument_group("handlers (see --help-handlers)")
|
1265
|
+
ap2.add_argument("--on404", metavar="PY", type=u, action="append", help="\033[34mREPEATABLE:\033[0m handle 404s by executing \033[33mPY\033[0m file")
|
1266
|
+
ap2.add_argument("--on403", metavar="PY", type=u, action="append", help="\033[34mREPEATABLE:\033[0m handle 403s by executing \033[33mPY\033[0m file")
|
1260
1267
|
ap2.add_argument("--hot-handlers", action="store_true", help="recompile handlers on each request -- expensive but convenient when hacking on stuff")
|
1261
1268
|
|
1262
1269
|
|
1263
1270
|
def add_hooks(ap):
|
1264
|
-
ap2 = ap.add_argument_group(
|
1265
|
-
ap2.add_argument("--xbu", metavar="CMD", type=u, action="append", help="execute \033[33mCMD\033[0m before a file upload starts")
|
1266
|
-
ap2.add_argument("--xau", metavar="CMD", type=u, action="append", help="execute \033[33mCMD\033[0m after a file upload finishes")
|
1267
|
-
ap2.add_argument("--xiu", metavar="CMD", type=u, action="append", help="execute \033[33mCMD\033[0m after all uploads finish and volume is idle")
|
1268
|
-
ap2.add_argument("--xbc", metavar="CMD", type=u, action="append", help="execute \033[33mCMD\033[0m before a file copy")
|
1269
|
-
ap2.add_argument("--xac", metavar="CMD", type=u, action="append", help="execute \033[33mCMD\033[0m after a file copy")
|
1270
|
-
ap2.add_argument("--xbr", metavar="CMD", type=u, action="append", help="execute \033[33mCMD\033[0m before a file move/rename")
|
1271
|
-
ap2.add_argument("--xar", metavar="CMD", type=u, action="append", help="execute \033[33mCMD\033[0m after a file move/rename")
|
1272
|
-
ap2.add_argument("--xbd", metavar="CMD", type=u, action="append", help="execute \033[33mCMD\033[0m before a file delete")
|
1273
|
-
ap2.add_argument("--xad", metavar="CMD", type=u, action="append", help="execute \033[33mCMD\033[0m after a file delete")
|
1274
|
-
ap2.add_argument("--xm", metavar="CMD", type=u, action="append", help="execute \033[33mCMD\033[0m on message")
|
1275
|
-
ap2.add_argument("--xban", metavar="CMD", type=u, action="append", help="execute \033[33mCMD\033[0m if someone gets banned (pw/404/403/url)")
|
1271
|
+
ap2 = ap.add_argument_group("event hooks (see --help-hooks)")
|
1272
|
+
ap2.add_argument("--xbu", metavar="CMD", type=u, action="append", help="\033[34mREPEATABLE:\033[0m execute \033[33mCMD\033[0m before a file upload starts")
|
1273
|
+
ap2.add_argument("--xau", metavar="CMD", type=u, action="append", help="\033[34mREPEATABLE:\033[0m execute \033[33mCMD\033[0m after a file upload finishes")
|
1274
|
+
ap2.add_argument("--xiu", metavar="CMD", type=u, action="append", help="\033[34mREPEATABLE:\033[0m execute \033[33mCMD\033[0m after all uploads finish and volume is idle")
|
1275
|
+
ap2.add_argument("--xbc", metavar="CMD", type=u, action="append", help="\033[34mREPEATABLE:\033[0m execute \033[33mCMD\033[0m before a file copy")
|
1276
|
+
ap2.add_argument("--xac", metavar="CMD", type=u, action="append", help="\033[34mREPEATABLE:\033[0m execute \033[33mCMD\033[0m after a file copy")
|
1277
|
+
ap2.add_argument("--xbr", metavar="CMD", type=u, action="append", help="\033[34mREPEATABLE:\033[0m execute \033[33mCMD\033[0m before a file move/rename")
|
1278
|
+
ap2.add_argument("--xar", metavar="CMD", type=u, action="append", help="\033[34mREPEATABLE:\033[0m execute \033[33mCMD\033[0m after a file move/rename")
|
1279
|
+
ap2.add_argument("--xbd", metavar="CMD", type=u, action="append", help="\033[34mREPEATABLE:\033[0m execute \033[33mCMD\033[0m before a file delete")
|
1280
|
+
ap2.add_argument("--xad", metavar="CMD", type=u, action="append", help="\033[34mREPEATABLE:\033[0m execute \033[33mCMD\033[0m after a file delete")
|
1281
|
+
ap2.add_argument("--xm", metavar="CMD", type=u, action="append", help="\033[34mREPEATABLE:\033[0m execute \033[33mCMD\033[0m on message")
|
1282
|
+
ap2.add_argument("--xban", metavar="CMD", type=u, action="append", help="\033[34mREPEATABLE:\033[0m execute \033[33mCMD\033[0m if someone gets banned (pw/404/403/url)")
|
1276
1283
|
ap2.add_argument("--hook-v", action="store_true", help="verbose hooks")
|
1277
1284
|
|
1278
1285
|
|
1279
1286
|
def add_stats(ap):
|
1280
|
-
ap2 = ap.add_argument_group(
|
1287
|
+
ap2 = ap.add_argument_group("grafana/prometheus metrics endpoint")
|
1281
1288
|
ap2.add_argument("--stats", action="store_true", help="enable openmetrics at /.cpr/metrics for admin accounts")
|
1282
1289
|
ap2.add_argument("--nos-hdd", action="store_true", help="disable disk-space metrics (used/free space)")
|
1283
1290
|
ap2.add_argument("--nos-vol", action="store_true", help="disable volume size metrics (num files, total bytes, vmaxb/vmaxn)")
|
@@ -1287,15 +1294,16 @@ def add_stats(ap):
|
|
1287
1294
|
|
1288
1295
|
|
1289
1296
|
def add_yolo(ap):
|
1290
|
-
ap2 = ap.add_argument_group(
|
1297
|
+
ap2 = ap.add_argument_group("yolo options")
|
1291
1298
|
ap2.add_argument("--allow-csrf", action="store_true", help="disable csrf protections; let other domains/sites impersonate you through cross-site requests")
|
1292
1299
|
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")
|
1300
|
+
ap2.add_argument("--no-fnugg", action="store_true", help="disable the smoketest for caching-related issues in the web-UI")
|
1293
1301
|
ap2.add_argument("--getmod", action="store_true", help="permit ?move=[...] and ?delete as GET")
|
1294
1302
|
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)")
|
1295
1303
|
|
1296
1304
|
|
1297
1305
|
def add_optouts(ap):
|
1298
|
-
ap2 = ap.add_argument_group(
|
1306
|
+
ap2 = ap.add_argument_group("opt-outs")
|
1299
1307
|
ap2.add_argument("-nw", action="store_true", help="never write anything to disk (debug/benchmark)")
|
1300
1308
|
ap2.add_argument("--keep-qem", action="store_true", help="do not disable quick-edit-mode on windows (it is disabled to avoid accidental text selection in the terminal window, as this would pause execution)")
|
1301
1309
|
ap2.add_argument("--no-dav", action="store_true", help="disable webdav support")
|
@@ -1321,7 +1329,7 @@ def add_optouts(ap):
|
|
1321
1329
|
|
1322
1330
|
|
1323
1331
|
def add_safety(ap):
|
1324
|
-
ap2 = ap.add_argument_group(
|
1332
|
+
ap2 = ap.add_argument_group("safety options")
|
1325
1333
|
ap2.add_argument("-s", action="count", default=0, help="increase safety: Disable thumbnails / potentially dangerous software (ffmpeg/pillow/vips), hide partial uploads, avoid crawlers.\n └─Alias of\033[32m --dotpart --no-thumb --no-mtag-ff --no-robots --force-js")
|
1326
1334
|
ap2.add_argument("-ss", action="store_true", help="further increase safety: Prevent js-injection, accidental move/delete, broken symlinks, webdav, 404 on 403, ban on excessive 404s.\n └─Alias of\033[32m -s --unpost=0 --no-del --no-mv --hardlink --vague-403 -nih")
|
1327
1335
|
ap2.add_argument("-sss", action="store_true", help="further increase safety: Enable logging to disk, scan for dangerous symlinks.\n └─Alias of\033[32m -ss --no-dav --no-logues --no-readme -lo=cpp-%%Y-%%m%%d-%%H%%M%%S.txt.xz --ls=**,*,ln,p,r")
|
@@ -1352,7 +1360,7 @@ def add_safety(ap):
|
|
1352
1360
|
|
1353
1361
|
|
1354
1362
|
def add_salt(ap, fk_salt, dk_salt, ah_salt):
|
1355
|
-
ap2 = ap.add_argument_group(
|
1363
|
+
ap2 = ap.add_argument_group("salting options")
|
1356
1364
|
ap2.add_argument("--ah-alg", metavar="ALG", type=u, default="none", help="account-pw hashing algorithm; one of these, best to worst: \033[32margon2 scrypt sha2 none\033[0m (each optionally followed by alg-specific comma-sep. config)")
|
1357
1365
|
ap2.add_argument("--ah-salt", metavar="SALT", type=u, default=ah_salt, help="account-pw salt; ignored if \033[33m--ah-alg\033[0m is none (default)")
|
1358
1366
|
ap2.add_argument("--ah-gen", metavar="PW", type=u, default="", help="generate hashed password for \033[33mPW\033[0m, or read passwords from STDIN if \033[33mPW\033[0m is [\033[32m-\033[0m]")
|
@@ -1366,23 +1374,23 @@ def add_salt(ap, fk_salt, dk_salt, ah_salt):
|
|
1366
1374
|
|
1367
1375
|
|
1368
1376
|
def add_shutdown(ap):
|
1369
|
-
ap2 = ap.add_argument_group(
|
1377
|
+
ap2 = ap.add_argument_group("shutdown options")
|
1370
1378
|
ap2.add_argument("--ign-ebind", action="store_true", help="continue running even if it's impossible to listen on some of the requested endpoints")
|
1371
1379
|
ap2.add_argument("--ign-ebind-all", action="store_true", help="continue running even if it's impossible to receive connections at all")
|
1372
1380
|
ap2.add_argument("--exit", metavar="WHEN", type=u, default="", help="shutdown after \033[33mWHEN\033[0m has finished; [\033[32mcfg\033[0m] config parsing, [\033[32midx\033[0m] volscan + multimedia indexing")
|
1373
1381
|
|
1374
1382
|
|
1375
1383
|
def add_logging(ap):
|
1376
|
-
ap2 = ap.add_argument_group(
|
1384
|
+
ap2 = ap.add_argument_group("logging options")
|
1377
1385
|
ap2.add_argument("-q", action="store_true", help="quiet; disable most STDOUT messages")
|
1378
|
-
ap2.add_argument("-lo", metavar="PATH", type=u, default="", help="logfile
|
1386
|
+
ap2.add_argument("-lo", metavar="PATH", type=u, default="", help="logfile; use .txt for plaintext or .xz for compressed. Example: \033[32mcpp-%%Y-%%m%%d-%%H%%M%%S.txt.xz\033[0m (NB: some errors may appear on STDOUT only)")
|
1379
1387
|
ap2.add_argument("--no-ansi", action="store_true", default=not VT100, help="disable colors; same as environment-variable NO_COLOR")
|
1380
1388
|
ap2.add_argument("--ansi", action="store_true", help="force colors; overrides environment-variable NO_COLOR")
|
1381
1389
|
ap2.add_argument("--no-logflush", action="store_true", help="don't flush the logfile after each write; tiny bit faster")
|
1382
1390
|
ap2.add_argument("--no-voldump", action="store_true", help="do not list volumes and permissions on startup")
|
1383
1391
|
ap2.add_argument("--log-utc", action="store_true", help="do not use local timezone; assume the TZ env-var is UTC (tiny bit faster)")
|
1384
1392
|
ap2.add_argument("--log-tdec", metavar="N", type=int, default=3, help="timestamp resolution / number of timestamp decimals")
|
1385
|
-
ap2.add_argument("--log-badpwd", metavar="N", type=int, default=
|
1393
|
+
ap2.add_argument("--log-badpwd", metavar="N", type=int, default=2, help="log failed login attempt passwords: 0=terse, 1=plaintext, 2=hashed")
|
1386
1394
|
ap2.add_argument("--log-conn", action="store_true", help="debug: print tcp-server msgs")
|
1387
1395
|
ap2.add_argument("--log-htp", action="store_true", help="debug: print http-server threadpool scaling")
|
1388
1396
|
ap2.add_argument("--ihead", metavar="HEADER", type=u, action='append', help="print request \033[33mHEADER\033[0m; [\033[32m*\033[0m]=all")
|
@@ -1391,7 +1399,7 @@ def add_logging(ap):
|
|
1391
1399
|
|
1392
1400
|
|
1393
1401
|
def add_admin(ap):
|
1394
|
-
ap2 = ap.add_argument_group(
|
1402
|
+
ap2 = ap.add_argument_group("admin panel options")
|
1395
1403
|
ap2.add_argument("--no-reload", action="store_true", help="disable ?reload=cfg (reload users/volumes/volflags from config file)")
|
1396
1404
|
ap2.add_argument("--no-rescan", action="store_true", help="disable ?scan (volume reindexing)")
|
1397
1405
|
ap2.add_argument("--no-stack", action="store_true", help="disable ?stack (list all stacks)")
|
@@ -1405,7 +1413,7 @@ def add_admin(ap):
|
|
1405
1413
|
def add_thumbnail(ap):
|
1406
1414
|
th_ram = (RAM_AVAIL or RAM_TOTAL or 9) * 0.6
|
1407
1415
|
th_ram = int(max(min(th_ram, 6), 0.3) * 10) / 10
|
1408
|
-
ap2 = ap.add_argument_group(
|
1416
|
+
ap2 = ap.add_argument_group("thumbnail options")
|
1409
1417
|
ap2.add_argument("--no-thumb", action="store_true", help="disable all thumbnails (volflag=dthumb)")
|
1410
1418
|
ap2.add_argument("--no-vthumb", action="store_true", help="disable video thumbnails (volflag=dvthumb)")
|
1411
1419
|
ap2.add_argument("--no-athumb", action="store_true", help="disable audio thumbnails (spectrograms) (volflag=dathumb)")
|
@@ -1437,7 +1445,7 @@ def add_thumbnail(ap):
|
|
1437
1445
|
|
1438
1446
|
|
1439
1447
|
def add_transcoding(ap):
|
1440
|
-
ap2 = ap.add_argument_group(
|
1448
|
+
ap2 = ap.add_argument_group("transcoding options")
|
1441
1449
|
ap2.add_argument("--q-opus", metavar="KBPS", type=int, default=128, help="target bitrate for transcoding to opus; set 0 to disable")
|
1442
1450
|
ap2.add_argument("--q-mp3", metavar="QUALITY", type=u, default="q2", help="target quality for transcoding to mp3, for example [\033[32m192k\033[0m] (CBR) or [\033[32mq0\033[0m] (CQ/CRF, q0=maxquality, q9=smallest); set 0 to disable")
|
1443
1451
|
ap2.add_argument("--allow-wav", action="store_true", help="allow transcoding to wav (lossless, uncompressed)")
|
@@ -1450,7 +1458,7 @@ def add_transcoding(ap):
|
|
1450
1458
|
|
1451
1459
|
|
1452
1460
|
def add_tail(ap):
|
1453
|
-
ap2 = ap.add_argument_group(
|
1461
|
+
ap2 = ap.add_argument_group("tailing options (realtime streaming of a growing file)")
|
1454
1462
|
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)")
|
1455
1463
|
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")
|
1456
1464
|
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)")
|
@@ -1460,7 +1468,7 @@ def add_tail(ap):
|
|
1460
1468
|
|
1461
1469
|
|
1462
1470
|
def add_rss(ap):
|
1463
|
-
ap2 = ap.add_argument_group(
|
1471
|
+
ap2 = ap.add_argument_group("RSS options")
|
1464
1472
|
ap2.add_argument("--rss", action="store_true", help="enable RSS output (experimental) (volflag=rss)")
|
1465
1473
|
ap2.add_argument("--rss-nf", metavar="HITS", type=int, default=250, help="default number of files to return (url-param 'nf')")
|
1466
1474
|
ap2.add_argument("--rss-fext", metavar="E,E", type=u, default="", help="default list of file extensions to include (url-param 'fext'); blank=all")
|
@@ -1469,7 +1477,7 @@ def add_rss(ap):
|
|
1469
1477
|
|
1470
1478
|
def add_db_general(ap, hcores):
|
1471
1479
|
noidx = APPLESAN_TXT if MACOS else ""
|
1472
|
-
ap2 = ap.add_argument_group(
|
1480
|
+
ap2 = ap.add_argument_group("general db options")
|
1473
1481
|
ap2.add_argument("-e2d", action="store_true", help="enable up2k database; this enables file search, upload-undo, improves deduplication")
|
1474
1482
|
ap2.add_argument("-e2ds", action="store_true", help="scan writable folders for new files on startup; sets \033[33m-e2d\033[0m")
|
1475
1483
|
ap2.add_argument("-e2dsa", action="store_true", help="scans all folders on startup; sets \033[33m-e2ds\033[0m")
|
@@ -1478,8 +1486,8 @@ def add_db_general(ap, hcores):
|
|
1478
1486
|
ap2.add_argument("-e2vp", action="store_true", help="on hash mismatch: panic and quit copyparty")
|
1479
1487
|
ap2.add_argument("--hist", metavar="PATH", type=u, default="", help="where to store volume data (db, thumbs); default is a folder named \".hist\" inside each volume (volflag=hist)")
|
1480
1488
|
ap2.add_argument("--dbpath", metavar="PATH", type=u, default="", help="override where the volume databases are to be placed; default is the same as \033[33m--hist\033[0m (volflag=dbpath)")
|
1481
|
-
ap2.add_argument("--no-hash", metavar="PTN", type=u, default="", help="regex: disable hashing of matching absolute-filesystem-paths during e2ds folder scans (volflag=nohash)")
|
1482
|
-
ap2.add_argument("--no-idx", metavar="PTN", type=u, default=noidx, help="regex: disable indexing of matching absolute-filesystem-paths during e2ds folder
|
1489
|
+
ap2.add_argument("--no-hash", metavar="PTN", type=u, default="", help="regex: disable hashing of matching absolute-filesystem-paths during e2ds folder scans (must be specified as one big regex, not multiple times) (volflag=nohash)")
|
1490
|
+
ap2.add_argument("--no-idx", metavar="PTN", type=u, default=noidx, help="regex: disable indexing of matching absolute-filesystem-paths during e2ds folder scan (must be specified as one big regex, not multiple times) (volflag=noidx)")
|
1483
1491
|
ap2.add_argument("--no-dirsz", action="store_true", help="do not show total recursive size of folders in listings, show inode size instead; slightly faster (volflag=nodirsz)")
|
1484
1492
|
ap2.add_argument("--re-dirsz", action="store_true", help="if the directory-sizes in the UI are bonkers, use this along with \033[33m-e2dsa\033[0m to rebuild the index from scratch")
|
1485
1493
|
ap2.add_argument("--no-dhash", action="store_true", help="disable rescan acceleration; do full database integrity check -- makes the db ~5%% smaller and bootup/rescans 3~10x slower")
|
@@ -1498,7 +1506,7 @@ def add_db_general(ap, hcores):
|
|
1498
1506
|
|
1499
1507
|
|
1500
1508
|
def add_db_metadata(ap):
|
1501
|
-
ap2 = ap.add_argument_group(
|
1509
|
+
ap2 = ap.add_argument_group("metadata db options")
|
1502
1510
|
ap2.add_argument("-e2t", action="store_true", help="enable metadata indexing; makes it possible to search for artist/title/codec/resolution/...")
|
1503
1511
|
ap2.add_argument("-e2ts", action="store_true", help="scan newly discovered files for metadata on startup; sets \033[33m-e2t\033[0m")
|
1504
1512
|
ap2.add_argument("-e2tsr", action="store_true", help="delete all metadata from DB and do a full rescan; sets \033[33m-e2ts\033[0m")
|
@@ -1508,15 +1516,16 @@ def add_db_metadata(ap):
|
|
1508
1516
|
ap2.add_argument("--mtag-mt", metavar="CORES", type=int, default=CORES, help="num cpu cores to use for tag scanning")
|
1509
1517
|
ap2.add_argument("--mtag-v", action="store_true", help="verbose tag scanning; print errors from mtp subprocesses and such")
|
1510
1518
|
ap2.add_argument("--mtag-vv", action="store_true", help="debug mtp settings and mutagen/FFprobe parsers")
|
1511
|
-
ap2.add_argument("-mtm", metavar="M=t,t,t", type=u, action="append", help="add/replace metadata mapping")
|
1519
|
+
ap2.add_argument("-mtm", metavar="M=t,t,t", type=u, action="append", help="\033[34mREPEATABLE:\033[0m add/replace metadata mapping")
|
1512
1520
|
ap2.add_argument("-mte", metavar="M,M,M", type=u, help="tags to index/display (comma-sep.); either an entire replacement list, or add/remove stuff on the default-list with +foo or /bar", default=DEF_MTE)
|
1513
1521
|
ap2.add_argument("-mth", metavar="M,M,M", type=u, help="tags to hide by default (comma-sep.); assign/add/remove same as \033[33m-mte\033[0m", default=DEF_MTH)
|
1514
|
-
ap2.add_argument("-mtp", metavar="M=[f,]BIN", type=u, action="append", help="read tag \033[33mM\033[0m using program \033[33mBIN\033[0m to parse the file")
|
1522
|
+
ap2.add_argument("-mtp", metavar="M=[f,]BIN", type=u, action="append", help="\033[34mREPEATABLE:\033[0m read tag \033[33mM\033[0m using program \033[33mBIN\033[0m to parse the file")
|
1515
1523
|
|
1516
1524
|
|
1517
1525
|
def add_txt(ap):
|
1518
|
-
ap2 = ap.add_argument_group(
|
1526
|
+
ap2 = ap.add_argument_group("textfile options")
|
1519
1527
|
ap2.add_argument("--md-hist", metavar="TXT", type=u, default="s", help="where to store old version of markdown files; [\033[32ms\033[0m]=subfolder, [\033[32mv\033[0m]=volume-histpath, [\033[32mn\033[0m]=nope/disabled (volflag=md_hist)")
|
1528
|
+
ap2.add_argument("--txt-eol", metavar="TYPE", type=u, default="", help="enable EOL conversion when writing documents; supported: CRLF, LF (volflag=txt_eol)")
|
1520
1529
|
ap2.add_argument("-mcr", metavar="SEC", type=int, default=60, help="the textfile editor will check for serverside changes every \033[33mSEC\033[0m seconds")
|
1521
1530
|
ap2.add_argument("-emp", action="store_true", help="enable markdown plugins -- neat but dangerous, big XSS risk")
|
1522
1531
|
ap2.add_argument("--exp", action="store_true", help="enable textfile expansion -- replace {{self.ip}} and such; see \033[33m--help-exp\033[0m (volflag=exp)")
|
@@ -1526,7 +1535,7 @@ def add_txt(ap):
|
|
1526
1535
|
|
1527
1536
|
|
1528
1537
|
def add_og(ap):
|
1529
|
-
ap2 = ap.add_argument_group(
|
1538
|
+
ap2 = ap.add_argument_group("og / open graph / discord-embed options")
|
1530
1539
|
ap2.add_argument("--og", action="store_true", help="disable hotlinking and return an html document instead; this is required by open-graph, but can also be useful on its own (volflag=og)")
|
1531
1540
|
ap2.add_argument("--og-ua", metavar="RE", type=u, default="", help="only disable hotlinking / engage OG behavior if the useragent matches regex \033[33mRE\033[0m (volflag=og_ua)")
|
1532
1541
|
ap2.add_argument("--og-tpl", metavar="PATH", type=u, default="", help="do not return the regular copyparty html, but instead load the jinja2 template at \033[33mPATH\033[0m (if path contains 'EXT' then EXT will be replaced with the requested file's extension) (volflag=og_tpl)")
|
@@ -1544,7 +1553,7 @@ def add_og(ap):
|
|
1544
1553
|
|
1545
1554
|
|
1546
1555
|
def add_ui(ap, retry):
|
1547
|
-
ap2 = ap.add_argument_group(
|
1556
|
+
ap2 = ap.add_argument_group("ui options")
|
1548
1557
|
ap2.add_argument("--grid", action="store_true", help="show grid/thumbnails by default (volflag=grid)")
|
1549
1558
|
ap2.add_argument("--gsel", action="store_true", help="select files in grid by ctrl-click (volflag=gsel)")
|
1550
1559
|
ap2.add_argument("--localtime", action="store_true", help="default to local timezone instead of UTC")
|
@@ -1559,7 +1568,7 @@ def add_ui(ap, retry):
|
|
1559
1568
|
ap2.add_argument("--qdel", metavar="LVL", type=int, default=2, help="number of confirmations to show when deleting files (2/1/0)")
|
1560
1569
|
ap2.add_argument("--unlist", metavar="REGEX", type=u, default="", help="don't show files/folders matching \033[33mREGEX\033[0m in file list. WARNING: Purely cosmetic! Does not affect API calls, just the browser. Example: [\033[32m\\.(js|css)$\033[0m] (volflag=unlist)")
|
1561
1570
|
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")
|
1562
|
-
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)")
|
1571
|
+
ap2.add_argument("--ext-th", metavar="E=VP", type=u, action="append", help="\033[34mREPEATABLE:\033[0m 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)")
|
1563
1572
|
ap2.add_argument("--mpmc", type=u, default="", help=argparse.SUPPRESS)
|
1564
1573
|
ap2.add_argument("--spinner", metavar="TXT", type=u, default="🌲", help="\033[33memoji\033[0m or \033[33memoji,css\033[0m Example: [\033[32m🥖,padding:0\033[0m]")
|
1565
1574
|
ap2.add_argument("--css-browser", metavar="L", type=u, default="", help="URL to additional CSS to include in the filebrowser html")
|
@@ -1575,6 +1584,7 @@ def add_ui(ap, retry):
|
|
1575
1584
|
ap2.add_argument("--ver", action="store_true", help="show version on the control panel (incompatible with \033[33m-nb\033[0m)")
|
1576
1585
|
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")
|
1577
1586
|
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")
|
1587
|
+
ap2.add_argument("--ctl-re", metavar="SEC", type=int, default=1, help="the controlpanel Refresh-button will autorefresh every SEC; [\033[32m0\033[0m] = just once")
|
1578
1588
|
ap2.add_argument("--md-sbf", metavar="FLAGS", type=u, default="downloads forms popups scripts top-navigation-by-user-activation", help="list of capabilities to allow in the iframe 'sandbox' attribute for README.md docs (volflag=md_sbf); see https://developer.mozilla.org/en-US/docs/Web/HTML/Element/iframe#sandbox")
|
1579
1589
|
ap2.add_argument("--lg-sbf", metavar="FLAGS", type=u, default="downloads forms popups scripts top-navigation-by-user-activation", help="list of capabilities to allow in the iframe 'sandbox' attribute for prologue/epilogue docs (volflag=lg_sbf)")
|
1580
1590
|
ap2.add_argument("--md-sba", metavar="TXT", type=u, default="", help="the value of the iframe 'allow' attribute for README.md docs, for example [\033[32mfullscreen\033[0m] (volflag=md_sba)")
|
@@ -1585,7 +1595,7 @@ def add_ui(ap, retry):
|
|
1585
1595
|
|
1586
1596
|
|
1587
1597
|
def add_debug(ap):
|
1588
|
-
ap2 = ap.add_argument_group(
|
1598
|
+
ap2 = ap.add_argument_group("debug options")
|
1589
1599
|
ap2.add_argument("--vc", action="store_true", help="verbose config file parser (explain config)")
|
1590
1600
|
ap2.add_argument("--cgen", action="store_true", help="generate config file from current config (best-effort; probably buggy)")
|
1591
1601
|
ap2.add_argument("--deps", action="store_true", help="list information about detected optional dependencies")
|
@@ -1750,6 +1760,10 @@ def main(argv = None) :
|
|
1750
1760
|
|
1751
1761
|
ensure_webdeps()
|
1752
1762
|
|
1763
|
+
if CFG_DEF:
|
1764
|
+
supp = args_from_cfg(CFG_DEF[0])
|
1765
|
+
argv.extend(supp)
|
1766
|
+
|
1753
1767
|
for k, v in zip(argv[1:], argv[2:]):
|
1754
1768
|
if k == "-c" and os.path.isfile(v):
|
1755
1769
|
supp = args_from_cfg(v)
|
copyparty/__version__.py
CHANGED
@@ -1,8 +1,8 @@
|
|
1
1
|
# coding: utf-8
|
2
2
|
|
3
|
-
VERSION = (1,
|
4
|
-
CODENAME = "
|
5
|
-
BUILD_DT = (2025, 8,
|
3
|
+
VERSION = (1, 19, 1)
|
4
|
+
CODENAME = "usernames"
|
5
|
+
BUILD_DT = (2025, 8, 10)
|
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
@@ -1692,6 +1692,7 @@ class AuthSrv(object):
|
|
1692
1692
|
if not mount and not self.args.idp_h_usr:
|
1693
1693
|
# -h says our defaults are CWD at root and read/write for everyone
|
1694
1694
|
axs = AXS(["*"], ["*"], None, None)
|
1695
|
+
ehint = ""
|
1695
1696
|
if self.is_lxc:
|
1696
1697
|
t = "Read-access has been disabled due to failsafe: Docker detected, but %s. This failsafe is to prevent unintended access if this is due to accidental loss of config. You can override this safeguard and allow read/write to all of /w/ by adding the following arguments to the docker container: -v .::rw"
|
1697
1698
|
if len(cfg_files_loaded) == 1:
|
@@ -1701,10 +1702,21 @@ class AuthSrv(object):
|
|
1701
1702
|
else:
|
1702
1703
|
self.log(t % ("the config does not define any volumes",), 1)
|
1703
1704
|
axs = AXS()
|
1705
|
+
ehint = "; please try moving them up one level, into the parent folder:"
|
1704
1706
|
elif self.args.c:
|
1705
1707
|
t = "Read-access has been disabled due to failsafe: No volumes were defined by the config-file. This failsafe is to prevent unintended access if this is due to accidental loss of config. You can override this safeguard and allow read/write to the working-directory by adding the following arguments: -v .::rw"
|
1706
1708
|
self.log(t, 1)
|
1707
1709
|
axs = AXS()
|
1710
|
+
ehint = ":"
|
1711
|
+
if ehint:
|
1712
|
+
try:
|
1713
|
+
files = os.listdir(E.cfg)
|
1714
|
+
except:
|
1715
|
+
files = []
|
1716
|
+
hits = [x for x in files if x.lower().endswith(".conf")]
|
1717
|
+
if hits:
|
1718
|
+
t = "Hint: Found some config files in [%s], but these were not automatically loaded because they are in the wrong place%s %s\n"
|
1719
|
+
self.log(t % (E.cfg, ehint, ", ".join(hits)), 3)
|
1708
1720
|
zvf = {"tcolor": self.args.tcolor}
|
1709
1721
|
vfs = VFS(self.log_func, absreal("."), "", "", axs, zvf)
|
1710
1722
|
if not axs.uread:
|
@@ -2621,6 +2633,8 @@ class AuthSrv(object):
|
|
2621
2633
|
self.re_pwd = None
|
2622
2634
|
pwds = [re.escape(x) for x in self.iacct.keys()]
|
2623
2635
|
pwds.extend(list(self.sesa))
|
2636
|
+
if self.args.usernames:
|
2637
|
+
pwds.extend([x.split(":", 1)[1] for x in pwds if ":" in x])
|
2624
2638
|
if pwds:
|
2625
2639
|
if self.ah.on:
|
2626
2640
|
zs = r"(\[H\] pw:.*|[?&]pw=)([^&]+)"
|
@@ -2917,6 +2931,9 @@ class AuthSrv(object):
|
|
2917
2931
|
t = "minimum password length: %d characters"
|
2918
2932
|
return False, t % (self.args.chpw_len,)
|
2919
2933
|
|
2934
|
+
if self.args.usernames:
|
2935
|
+
pw = "%s:%s" % (uname, pw)
|
2936
|
+
|
2920
2937
|
hpw = self.ah.hash(pw) if self.ah.on else pw
|
2921
2938
|
|
2922
2939
|
if hpw == self.acct[uname]:
|
@@ -3008,6 +3025,12 @@ class AuthSrv(object):
|
|
3008
3025
|
self.log("chpw: " + msg, 6)
|
3009
3026
|
|
3010
3027
|
def setup_pwhash(self, acct ) :
|
3028
|
+
if self.args.usernames:
|
3029
|
+
for uname, pw in list(acct.items())[:]:
|
3030
|
+
if pw.startswith("+") and len(pw) == 33:
|
3031
|
+
continue
|
3032
|
+
acct[uname] = "%s:%s" % (uname, pw)
|
3033
|
+
|
3011
3034
|
self.ah = PWHash(self.args)
|
3012
3035
|
if not self.ah.on:
|
3013
3036
|
if self.args.ah_cli or self.args.ah_gen:
|
copyparty/cfg.py
CHANGED
@@ -111,6 +111,7 @@ def vf_vmap() :
|
|
111
111
|
"tail_tmax",
|
112
112
|
"tail_who",
|
113
113
|
"tcolor",
|
114
|
+
"txt_eol",
|
114
115
|
"unlist",
|
115
116
|
"u2abort",
|
116
117
|
"u2ts",
|
@@ -322,6 +323,7 @@ flagcats = {
|
|
322
323
|
"exp": "enable textfile expansion; see --help-exp",
|
323
324
|
"exp_md": "placeholders to expand in markdown files; see --help",
|
324
325
|
"exp_lg": "placeholders to expand in prologue/epilogue; see --help",
|
326
|
+
"txt_eol=lf": "enable EOL conversion when writing docs (LF or CRLF)",
|
325
327
|
},
|
326
328
|
"tailing": {
|
327
329
|
"notail": "disable ?tail (download a growing file continuously)",
|
copyparty/ftpd.py
CHANGED
@@ -79,7 +79,12 @@ class FtpAuth(DummyAuthorizer):
|
|
79
79
|
uname = "*"
|
80
80
|
if username != "anonymous":
|
81
81
|
uname = ""
|
82
|
-
|
82
|
+
if args.usernames:
|
83
|
+
alts = ["%s:%s" % (username, password)]
|
84
|
+
else:
|
85
|
+
alts = password, username
|
86
|
+
|
87
|
+
for zs in alts:
|
83
88
|
zs = asrv.iacct.get(asrv.ah.hash(zs), "")
|
84
89
|
if zs:
|
85
90
|
uname = zs
|
@@ -603,7 +608,7 @@ class Ftpd(object):
|
|
603
608
|
if "::" in ips:
|
604
609
|
ips.append("0.0.0.0")
|
605
610
|
|
606
|
-
ips = [x for x in ips if "unix:"
|
611
|
+
ips = [x for x in ips if not x.startswith(("unix:", "fd:"))]
|
607
612
|
|
608
613
|
if self.args.ftp4:
|
609
614
|
ips = [x for x in ips if ":" not in x]
|