Compare commits

...

7 Commits

Author SHA1 Message Date
ed
cacca663b3 v1.6.13 2023-04-23 23:05:31 +00:00
ed
d5109be559 ftp: track login state isolated from pyftpdlib;
for convenience, the password can be provided as the username
but that confuses pyftpd a little so let's do this
2023-04-23 21:06:19 +00:00
ed
d999f06bb9 volflags can be -unset 2023-04-23 21:05:29 +00:00
ed
a1a8a8c7b5 configurable tls-certificate location 2023-04-23 20:56:55 +00:00
ed
fdd6f3b4a6 tar/zip: use volume name as toplevel fallback 2023-04-23 20:55:34 +00:00
ed
f5191973df docs cleanup:
* mostly deprecate --http-only and --https-only since there is zero
   performance gain in recent python versions, however could still be
   useful for avoiding limitations in alternative python interpreters
   (and forcing http/https with mdns/ssdp/qr)

* mention antivirus being useless as usual
2023-04-23 20:25:44 +00:00
ed
ddbaebe779 update pkgs to 1.6.12 2023-04-20 22:47:37 +00:00
16 changed files with 153 additions and 48 deletions

View File

@@ -818,6 +818,13 @@ an FTP server can be started using `--ftp 3921`, and/or `--ftps` for explicit T
* some older software (filezilla on debian-stable) cannot passive-mode with TLS * some older software (filezilla on debian-stable) cannot passive-mode with TLS
* login with any username + your password, or put your password in the username field * login with any username + your password, or put your password in the username field
some recommended FTP / FTPS clients; `wark` = example password:
* https://winscp.net/eng/download.php
* https://filezilla-project.org/ struggles a bit with ftps in active-mode, but is fine otherwise
* https://rclone.org/ does FTPS with `tls=false explicit_tls=true`
* `lftp -u k,wark -p 3921 127.0.0.1 -e ls`
* `lftp -u k,wark -p 3990 127.0.0.1 -e 'set ssl:verify-certificate no; ls'`
## webdav server ## webdav server
@@ -1421,7 +1428,6 @@ defaults are usually fine - expect `8 GiB/s` download, `1 GiB/s` upload
below are some tweaks roughly ordered by usefulness: below are some tweaks roughly ordered by usefulness:
* `-q` disables logging and can help a bunch, even when combined with `-lo` to redirect logs to file * `-q` disables logging and can help a bunch, even when combined with `-lo` to redirect logs to file
* `--http-only` or `--https-only` (unless you want to support both protocols) will reduce the delay before a new connection is established
* `--hist` pointing to a fast location (ssd) will make directory listings and searches faster when `-e2d` or `-e2t` is set * `--hist` pointing to a fast location (ssd) will make directory listings and searches faster when `-e2d` or `-e2t` is set
* `--no-hash .` when indexing a network-disk if you don't care about the actual filehashes and only want the names/tags searchable * `--no-hash .` when indexing a network-disk if you don't care about the actual filehashes and only want the names/tags searchable
* `--no-htp --hash-mt=0 --mtag-mt=1 --th-mt=1` minimizes the number of threads; can help in some eccentric environments (like the vscode debugger) * `--no-htp --hash-mt=0 --mtag-mt=1 --th-mt=1` minimizes the number of threads; can help in some eccentric environments (like the vscode debugger)
@@ -1599,6 +1605,7 @@ can be convenient on machines where installing python is problematic, however is
* [copyparty.exe](https://github.com/9001/copyparty/releases/latest/download/copyparty.exe) runs on win8 or newer, was compiled on win10, does thumbnails + media tags, and is *currently* safe to use, but any future python/expat/pillow CVEs can only be remedied by downloading a newer version of the exe * [copyparty.exe](https://github.com/9001/copyparty/releases/latest/download/copyparty.exe) runs on win8 or newer, was compiled on win10, does thumbnails + media tags, and is *currently* safe to use, but any future python/expat/pillow CVEs can only be remedied by downloading a newer version of the exe
* on win8 it needs [vc redist 2015](https://www.microsoft.com/en-us/download/details.aspx?id=48145), on win10 it just works * on win8 it needs [vc redist 2015](https://www.microsoft.com/en-us/download/details.aspx?id=48145), on win10 it just works
* some antivirus may freak out (false-positive), possibly [Avast, AVG, and McAfee](https://www.virustotal.com/gui/file/52391a1e9842cf70ad243ef83844d46d29c0044d101ee0138fcdd3c8de2237d6/detection)
* dangerous: [copyparty32.exe](https://github.com/9001/copyparty/releases/latest/download/copyparty32.exe) is compatible with [windows7](https://user-images.githubusercontent.com/241032/221445944-ae85d1f4-d351-4837-b130-82cab57d6cca.png), which means it uses an ancient copy of python (3.7.9) which cannot be upgraded and should never be exposed to the internet (LAN is fine) * dangerous: [copyparty32.exe](https://github.com/9001/copyparty/releases/latest/download/copyparty32.exe) is compatible with [windows7](https://user-images.githubusercontent.com/241032/221445944-ae85d1f4-d351-4837-b130-82cab57d6cca.png), which means it uses an ancient copy of python (3.7.9) which cannot be upgraded and should never be exposed to the internet (LAN is fine)

View File

@@ -1,7 +1,6 @@
# when running copyparty behind a reverse proxy, # when running copyparty behind a reverse proxy,
# the following arguments are recommended: # the following arguments are recommended:
# #
# --http-only lower latency on initial connection
# -i 127.0.0.1 only accept connections from nginx # -i 127.0.0.1 only accept connections from nginx
# #
# if you are doing location-based proxying (such as `/stuff` below) # if you are doing location-based proxying (such as `/stuff` below)

View File

@@ -1,7 +1,6 @@
# when running copyparty behind a reverse proxy, # when running copyparty behind a reverse proxy,
# the following arguments are recommended: # the following arguments are recommended:
# #
# --http-only lower latency on initial connection
# -i 127.0.0.1 only accept connections from nginx # -i 127.0.0.1 only accept connections from nginx
# #
# -nc must match or exceed the webserver's max number of concurrent clients; # -nc must match or exceed the webserver's max number of concurrent clients;
@@ -9,7 +8,7 @@
# nginx default is 512 (worker_processes 1, worker_connections 512) # nginx default is 512 (worker_processes 1, worker_connections 512)
# #
# you may also consider adding -j0 for CPU-intensive configurations # you may also consider adding -j0 for CPU-intensive configurations
# (not that i can really think of any good examples) # (5'000 requests per second, or 20gbps upload/download in parallel)
# #
# on fedora/rhel, remember to setsebool -P httpd_can_network_connect 1 # on fedora/rhel, remember to setsebool -P httpd_can_network_connect 1

View File

@@ -1,6 +1,6 @@
# Maintainer: icxes <dev.null@need.moe> # Maintainer: icxes <dev.null@need.moe>
pkgname=copyparty pkgname=copyparty
pkgver="1.6.11" pkgver="1.6.12"
pkgrel=1 pkgrel=1
pkgdesc="Portable file sharing hub" pkgdesc="Portable file sharing hub"
arch=("any") arch=("any")
@@ -26,7 +26,7 @@ source=("${url}/releases/download/v${pkgver}/${pkgname}-sfx.py"
"https://raw.githubusercontent.com/9001/${pkgname}/v${pkgver}/LICENSE" "https://raw.githubusercontent.com/9001/${pkgname}/v${pkgver}/LICENSE"
) )
backup=("etc/${pkgname}.d/init" ) backup=("etc/${pkgname}.d/init" )
sha256sums=("d096e33ab666ef45213899dd3a10735f62b5441339cb7374f93b232d0b6c8d34" sha256sums=("ce3702634fecf7cd6a5c79709a8e6cb1e9fe0748ec4754a278be7a60b618dd42"
"b8565eba5e64dedba1cf6c7aac7e31c5a731ed7153d6810288a28f00a36c28b2" "b8565eba5e64dedba1cf6c7aac7e31c5a731ed7153d6810288a28f00a36c28b2"
"f65c207e0670f9d78ad2e399bda18d5502ff30d2ac79e0e7fc48e7fbdc39afdc" "f65c207e0670f9d78ad2e399bda18d5502ff30d2ac79e0e7fc48e7fbdc39afdc"
"c4f396b083c9ec02ad50b52412c84d2a82be7f079b2d016e1c9fad22d68285ff" "c4f396b083c9ec02ad50b52412c84d2a82be7f079b2d016e1c9fad22d68285ff"

View File

@@ -1,5 +1,5 @@
{ {
"url": "https://github.com/9001/copyparty/releases/download/v1.6.11/copyparty-sfx.py", "url": "https://github.com/9001/copyparty/releases/download/v1.6.12/copyparty-sfx.py",
"version": "1.6.11", "version": "1.6.12",
"hash": "sha256-0JbjOrZm70UhOJndOhBzX2K1RBM5y3N0+TsjLQtsjTQ=" "hash": "sha256-zjcCY0/s981qXHlwmo5ssen+B0jsR1SieL56YLYY3UI="
} }

View File

@@ -261,7 +261,7 @@ def ensure_locale() -> None:
warn(t.format(safe)) warn(t.format(safe))
def ensure_cert() -> None: def ensure_cert(al: argparse.Namespace) -> None:
""" """
the default cert (and the entire TLS support) is only here to enable the the default cert (and the entire TLS support) is only here to enable the
crypto.subtle javascript API, which is necessary due to the webkit guys crypto.subtle javascript API, which is necessary due to the webkit guys
@@ -270,15 +270,30 @@ def ensure_cert() -> None:
i feel awful about this and so should they i feel awful about this and so should they
""" """
cert_insec = os.path.join(E.mod, "res/insecure.pem") cert_insec = os.path.join(E.mod, "res/insecure.pem")
cert_cfg = os.path.join(E.cfg, "cert.pem") cert_appdata = os.path.join(E.cfg, "cert.pem")
if not os.path.exists(cert_cfg): if not os.path.isfile(al.cert):
shutil.copy(cert_insec, cert_cfg) if cert_appdata != al.cert:
raise Exception("certificate file does not exist: " + al.cert)
shutil.copy(cert_insec, al.cert)
with open(al.cert, "rb") as f:
buf = f.read()
o1 = buf.find(b"-BEGIN PRIVATE KEY-")
o2 = buf.find(b"-BEGIN CERTIFICATE-")
m = "unsupported certificate format: "
if o1 < 0:
raise Exception(m + "no private key inside pem")
if o2 < 0:
raise Exception(m + "no server certificate inside pem")
if o1 > o2:
raise Exception(m + "private key must appear before server certificate")
try: try:
if filecmp.cmp(cert_cfg, cert_insec): if filecmp.cmp(al.cert, cert_insec):
lprint( lprint(
"\033[33musing default TLS certificate; https will be insecure." "\033[33musing default TLS certificate; https will be insecure."
+ "\033[36m\ncertificate location: {}\033[0m\n".format(cert_cfg) + "\033[36m\ncertificate location: {}\033[0m\n".format(al.cert)
) )
except: except:
pass pass
@@ -499,8 +514,12 @@ def get_sects():
""" """
volflags are appended to volume definitions, for example, volflags are appended to volume definitions, for example,
to create a write-only volume with the \033[33mnodupe\033[0m and \033[32mnosub\033[0m flags: to create a write-only volume with the \033[33mnodupe\033[0m and \033[32mnosub\033[0m flags:
\033[35m-v /mnt/inc:/inc:w\033[33m:c,nodupe\033[32m:c,nosub""" \033[35m-v /mnt/inc:/inc:w\033[33m:c,nodupe\033[32m:c,nosub\033[0m
)
if global config defines a volflag for all volumes,
you can unset it for a specific volume with -flag
"""
).rstrip()
+ build_flags_desc(), + build_flags_desc(),
], ],
[ [
@@ -697,10 +716,11 @@ def add_network(ap):
ap2.add_argument("--rsp-jtr", metavar="SEC", type=float, default=0, help="debug: response delay, random duration 0..SEC") ap2.add_argument("--rsp-jtr", metavar="SEC", type=float, default=0, help="debug: response delay, random duration 0..SEC")
def add_tls(ap): def add_tls(ap, cert_path):
ap2 = ap.add_argument_group('SSL/TLS options') ap2 = ap.add_argument_group('SSL/TLS options')
ap2.add_argument("--http-only", action="store_true", help="disable ssl/tls -- force plaintext") ap2.add_argument("--http-only", action="store_true", help="disable ssl/tls -- force plaintext")
ap2.add_argument("--https-only", action="store_true", help="disable plaintext -- force tls") ap2.add_argument("--https-only", action="store_true", help="disable plaintext -- force tls")
ap2.add_argument("--cert", metavar="PATH", type=u, default=cert_path, help="path to TLS certificate")
ap2.add_argument("--ssl-ver", metavar="LIST", type=u, help="set allowed ssl/tls versions; [\033[32mhelp\033[0m] shows available versions; default is what your python version considers safe") ap2.add_argument("--ssl-ver", metavar="LIST", type=u, help="set allowed ssl/tls versions; [\033[32mhelp\033[0m] shows available versions; default is what your python version considers safe")
ap2.add_argument("--ciphers", metavar="LIST", type=u, help="set allowed ssl/tls ciphers; [\033[32mhelp\033[0m] shows available ciphers") ap2.add_argument("--ciphers", metavar="LIST", type=u, help="set allowed ssl/tls ciphers; [\033[32mhelp\033[0m] shows available ciphers")
ap2.add_argument("--ssl-dbg", action="store_true", help="dump some tls info") ap2.add_argument("--ssl-dbg", action="store_true", help="dump some tls info")
@@ -987,8 +1007,10 @@ def run_argparse(
description="http file sharing hub v{} ({})".format(S_VERSION, S_BUILD_DT), description="http file sharing hub v{} ({})".format(S_VERSION, S_BUILD_DT),
) )
cert_path = os.path.join(E.cfg, "cert.pem")
try: try:
fk_salt = unicode(os.path.getmtime(os.path.join(E.cfg, "cert.pem"))) fk_salt = unicode(os.path.getmtime(cert_path))
except: except:
fk_salt = "hunter2" fk_salt = "hunter2"
@@ -1000,7 +1022,7 @@ def run_argparse(
add_general(ap, nc, srvname) add_general(ap, nc, srvname)
add_network(ap) add_network(ap)
add_tls(ap) add_tls(ap, cert_path)
add_qr(ap, tty) add_qr(ap, tty)
add_zeroconf(ap) add_zeroconf(ap)
add_zc_mdns(ap) add_zc_mdns(ap)
@@ -1084,8 +1106,6 @@ def main(argv: Optional[list[str]] = None) -> None:
print("pybin: {}\n".format(pybin), end="") print("pybin: {}\n".format(pybin), end="")
ensure_locale() ensure_locale()
if HAVE_SSL:
ensure_cert()
for k, v in zip(argv[1:], argv[2:]): for k, v in zip(argv[1:], argv[2:]):
if k == "-c" and os.path.isfile(v): if k == "-c" and os.path.isfile(v):
@@ -1153,6 +1173,9 @@ def main(argv: Optional[list[str]] = None) -> None:
except: except:
sys.exit(1) sys.exit(1)
if HAVE_SSL:
ensure_cert(al)
if WINDOWS and not al.keep_qem: if WINDOWS and not al.keep_qem:
try: try:
disable_quickedit() disable_quickedit()

View File

@@ -1,8 +1,8 @@
# coding: utf-8 # coding: utf-8
VERSION = (1, 6, 12) VERSION = (1, 6, 13)
CODENAME = "cors k" CODENAME = "cors k"
BUILD_DT = (2023, 4, 20) BUILD_DT = (2023, 4, 23)
S_VERSION = ".".join(map(str, VERSION)) S_VERSION = ".".join(map(str, VERSION))
S_BUILD_DT = "{0:04d}-{1:02d}-{2:02d}".format(*BUILD_DT) S_BUILD_DT = "{0:04d}-{1:02d}-{2:02d}".format(*BUILD_DT)

View File

@@ -578,6 +578,7 @@ class VFS(object):
def zipgen( def zipgen(
self, self,
vpath: str,
vrem: str, vrem: str,
flt: set[str], flt: set[str],
uname: str, uname: str,
@@ -589,7 +590,7 @@ class VFS(object):
# if multiselect: add all items to archive root # if multiselect: add all items to archive root
# if single folder: the folder itself is the top-level item # if single folder: the folder itself is the top-level item
folder = "" if flt or not wrap else (vrem.split("/")[-1].lstrip(".") or "top") folder = "" if flt or not wrap else (vpath.split("/")[-1].lstrip(".") or "top")
g = self.walk(folder, vrem, [], uname, [[True, False]], dots, scandir, False) g = self.walk(folder, vrem, [], uname, [[True, False]], dots, scandir, False)
for _, _, vpath, apath, files, rd, vd in g: for _, _, vpath, apath, files, rd, vd in g:
@@ -858,7 +859,7 @@ class AuthSrv(object):
zd = split_cfg_ln(ln) zd = split_cfg_ln(ln)
fstr = "" fstr = ""
for sk, sv in zd.items(): for sk, sv in zd.items():
bad = re.sub(r"[a-z0-9_]", "", sk) bad = re.sub(r"[a-z0-9_-]", "", sk).lstrip("-")
if bad: if bad:
err = "bad characters [{}] in volflag name [{}]; " err = "bad characters [{}] in volflag name [{}]; "
err = err.format(bad, sk) err = err.format(bad, sk)
@@ -934,7 +935,14 @@ class AuthSrv(object):
value: Union[str, bool, list[str]], value: Union[str, bool, list[str]],
is_list: bool, is_list: bool,
) -> None: ) -> None:
desc = flagdescs.get(name, "?").replace("\n", " ") desc = flagdescs.get(name.lstrip("-"), "?").replace("\n", " ")
if re.match("^-[^-]+$", name):
t = "└─unset volflag [{}] ({})"
self._e(t.format(name[1:], desc))
flags[name] = True
return
if name not in "mtp xbu xau xiu xbr xar xbd xad xm".split(): if name not in "mtp xbu xau xiu xbr xar xbd xad xm".split():
if value is True: if value is True:
t = "└─add volflag [{}] = {} ({})" t = "└─add volflag [{}] = {} ({})"
@@ -1440,6 +1448,12 @@ class AuthSrv(object):
self.log(t, 1) self.log(t, 1)
errors = True errors = True
for vol in vfs.all_vols.values():
for k in list(vol.flags.keys()):
if re.match("^-[^-]+$", k):
vol.flags.pop(k[1:], None)
vol.flags.pop(k)
if errors: if errors:
sys.exit(1) sys.exit(1)

View File

@@ -55,6 +55,7 @@ class FtpAuth(DummyAuthorizer):
self, username: str, password: str, handler: Any self, username: str, password: str, handler: Any
) -> None: ) -> None:
handler.username = "{}:{}".format(username, password) handler.username = "{}:{}".format(username, password)
handler.uname = "*"
ip = handler.addr[0] ip = handler.addr[0]
if ip.startswith("::ffff:"): if ip.startswith("::ffff:"):
@@ -86,14 +87,14 @@ class FtpAuth(DummyAuthorizer):
raise AuthenticationFailed("Authentication failed.") raise AuthenticationFailed("Authentication failed.")
handler.username = uname handler.uname = uname
def get_home_dir(self, username: str) -> str: def get_home_dir(self, username: str) -> str:
return "/" return "/"
def has_user(self, username: str) -> bool: def has_user(self, username: str) -> bool:
asrv = self.hub.asrv asrv = self.hub.asrv
return username in asrv.acct return username in asrv.acct or username in asrv.iacct
def has_perm(self, username: str, perm: int, path: Optional[str] = None) -> bool: def has_perm(self, username: str, perm: int, path: Optional[str] = None) -> bool:
return True # handled at filesystem layer return True # handled at filesystem layer
@@ -115,8 +116,7 @@ class FtpFs(AbstractedFS):
self.h = self.cmd_channel = cmd_channel # type: FTPHandler self.h = self.cmd_channel = cmd_channel # type: FTPHandler
self.hub: "SvcHub" = cmd_channel.hub self.hub: "SvcHub" = cmd_channel.hub
self.args = cmd_channel.args self.args = cmd_channel.args
self.uname = cmd_channel.uname
self.uname = self.hub.asrv.iacct.get(cmd_channel.password, "*")
self.cwd = "/" # pyftpdlib convention of leading slash self.cwd = "/" # pyftpdlib convention of leading slash
self.root = "/var/lib/empty" self.root = "/var/lib/empty"
@@ -215,7 +215,7 @@ class FtpFs(AbstractedFS):
self.can_delete, self.can_delete,
self.can_get, self.can_get,
self.can_upget, self.can_upget,
) = self.hub.asrv.vfs.can_access(self.cwd.lstrip("/"), self.h.username) ) = self.hub.asrv.vfs.can_access(self.cwd.lstrip("/"), self.h.uname)
def mkdir(self, path: str) -> None: def mkdir(self, path: str) -> None:
ap = self.rv2a(path, w=True)[0] ap = self.rv2a(path, w=True)[0]
@@ -265,7 +265,7 @@ class FtpFs(AbstractedFS):
def rename(self, src: str, dst: str) -> None: def rename(self, src: str, dst: str) -> None:
if not self.can_move: if not self.can_move:
self.die("Not allowed for user " + self.h.username) self.die("Not allowed for user " + self.h.uname)
if self.args.no_mv: if self.args.no_mv:
self.die("The rename/move feature is disabled in server config") self.die("The rename/move feature is disabled in server config")
@@ -344,10 +344,12 @@ class FtpHandler(FTPHandler):
abstracted_fs = FtpFs abstracted_fs = FtpFs
hub: "SvcHub" hub: "SvcHub"
args: argparse.Namespace args: argparse.Namespace
uname: str
def __init__(self, conn: Any, server: Any, ioloop: Any = None) -> None: def __init__(self, conn: Any, server: Any, ioloop: Any = None) -> None:
self.hub: "SvcHub" = FtpHandler.hub self.hub: "SvcHub" = FtpHandler.hub
self.args: argparse.Namespace = FtpHandler.args self.args: argparse.Namespace = FtpHandler.args
self.uname = "*"
if PY2: if PY2:
FTPHandler.__init__(self, conn, server, ioloop) FTPHandler.__init__(self, conn, server, ioloop)
@@ -379,7 +381,7 @@ class FtpHandler(FTPHandler):
ap, ap,
vfs.canonical(rem), vfs.canonical(rem),
"", "",
self.username, self.uname,
0, 0,
0, 0,
self.cli_ip, self.cli_ip,
@@ -408,7 +410,7 @@ class FtpHandler(FTPHandler):
# print("xfer_end: {} => {}".format(ap, vp)) # print("xfer_end: {} => {}".format(ap, vp))
if vp: if vp:
vp, fn = os.path.split(vp) vp, fn = os.path.split(vp)
vfs, rem = self.hub.asrv.vfs.get(vp, self.username, False, True) vfs, rem = self.hub.asrv.vfs.get(vp, self.uname, False, True)
vfs, rem = vfs.get_dbv(rem) vfs, rem = vfs.get_dbv(rem)
self.hub.up2k.hash_file( self.hub.up2k.hash_file(
vfs.realpath, vfs.realpath,
@@ -418,7 +420,7 @@ class FtpHandler(FTPHandler):
fn, fn,
self.cli_ip, self.cli_ip,
time.time(), time.time(),
self.username, self.uname,
) )
return FTPHandler.log_transfer( return FTPHandler.log_transfer(
@@ -452,7 +454,7 @@ class Ftpd(object):
print(t.format(pybin)) print(t.format(pybin))
sys.exit(1) sys.exit(1)
h1.certfile = os.path.join(self.args.E.cfg, "cert.pem") h1.certfile = self.args.cert
h1.tls_control_required = True h1.tls_control_required = True
h1.tls_data_required = True h1.tls_data_required = True

View File

@@ -884,6 +884,7 @@ class HttpCli(object):
return True return True
fgen = vn.zipgen( fgen = vn.zipgen(
rem,
rem, rem,
set(), set(),
self.uname, self.uname,
@@ -1669,7 +1670,7 @@ class HttpCli(object):
items = [unquotep(x) for x in items if items] items = [unquotep(x) for x in items if items]
self.parser.drop() self.parser.drop()
return self.tx_zip(k, v, vn, rem, items, self.args.ed) return self.tx_zip(k, v, "", vn, rem, items, self.args.ed)
def handle_post_json(self) -> bool: def handle_post_json(self) -> bool:
try: try:
@@ -2656,7 +2657,14 @@ class HttpCli(object):
return ret return ret
def tx_zip( def tx_zip(
self, fmt: str, uarg: str, vn: VFS, rem: str, items: list[str], dots: bool self,
fmt: str,
uarg: str,
vpath: str,
vn: VFS,
rem: str,
items: list[str],
dots: bool,
) -> bool: ) -> bool:
if self.args.no_zip: if self.args.no_zip:
raise Pebkac(400, "not enabled") raise Pebkac(400, "not enabled")
@@ -2699,7 +2707,7 @@ class HttpCli(object):
self.send_headers(None, mime=mime, headers={"Content-Disposition": cdis}) self.send_headers(None, mime=mime, headers={"Content-Disposition": cdis})
fgen = vn.zipgen( fgen = vn.zipgen(
rem, set(items), self.uname, False, dots, not self.args.no_scandir vpath, rem, set(items), self.uname, dots, False, not self.args.no_scandir
) )
# for f in fgen: print(repr({k: f[k] for k in ["vp", "ap"]})) # for f in fgen: print(repr({k: f[k] for k in ["vp", "ap"]}))
bgen = packer(self.log, fgen, utf8="utf" in uarg, pre_crc="crc" in uarg) bgen = packer(self.log, fgen, utf8="utf" in uarg, pre_crc="crc" in uarg)
@@ -3503,7 +3511,7 @@ class HttpCli(object):
for k in ["zip", "tar"]: for k in ["zip", "tar"]:
v = self.uparam.get(k) v = self.uparam.get(k)
if v is not None: if v is not None:
return self.tx_zip(k, v, vn, rem, [], self.args.ed) return self.tx_zip(k, v, self.vpath, vn, rem, [], self.args.ed)
fsroot, vfs_ls, vfs_virt = vn.ls( fsroot, vfs_ls, vfs_virt = vn.ls(
rem, self.uname, not self.args.no_scandir, [[True, False], [False, True]] rem, self.uname, not self.args.no_scandir, [[True, False], [False, True]]

View File

@@ -132,7 +132,7 @@ class HttpSrv(object):
self.ssdp = SSDPr(broker) self.ssdp = SSDPr(broker)
cert_path = os.path.join(self.E.cfg, "cert.pem") cert_path = self.args.cert
if bos.path.exists(cert_path): if bos.path.exists(cert_path):
self.cert_path = cert_path self.cert_path = cert_path
else: else:

View File

@@ -110,10 +110,21 @@
<div class="os win"> <div class="os win">
<p>if you can, install <a href="https://winfsp.dev/rel/">winfsp</a>+<a href="https://downloads.rclone.org/rclone-current-windows-amd64.zip">rclone</a> and then paste this in cmd:</p> <p>if you can, install <a href="https://winfsp.dev/rel/">winfsp</a>+<a href="https://downloads.rclone.org/rclone-current-windows-amd64.zip">rclone</a> and then paste this in cmd:</p>
{% if args.ftp %}
<p>connect with plaintext FTP:</p>
<pre> <pre>
rclone config create {{ aname }}-ftp ftp host={{ rip }} port={{ args.ftp or args.ftps }} pass=k user={% if accs %}<b>{{ pw }}</b>{% else %}anonymous{% endif %} tls={{ "false" if args.ftp else "true" }} rclone config create {{ aname }}-ftp ftp host={{ rip }} port={{ args.ftp }} pass=k user={% if accs %}<b>{{ pw }}</b>{% else %}anonymous{% endif %} tls=false
rclone mount --vfs-cache-mode writes --dir-cache-time 5s {{ aname }}-ftp:{{ rvp }} <b>W:</b> rclone mount --vfs-cache-mode writes --dir-cache-time 5s {{ aname }}-ftp:{{ rvp }} <b>W:</b>
</pre> </pre>
{% endif %}
{% if args.ftps %}
<p>connect with TLS-encrypted FTPS:</p>
<pre>
rclone config create {{ aname }}-ftps ftp host={{ rip }} port={{ args.ftps }} pass=k user={% if accs %}<b>{{ pw }}</b>{% else %}anonymous{% endif %} tls=false explicit_tls=true
rclone mount --vfs-cache-mode writes --dir-cache-time 5s {{ aname }}-ftps:{{ rvp }} <b>W:</b>
</pre>
<p><em>note: if you are on LAN (or just dont have valid certificates), add <code>no_check_certificate=true</code> to the config command</em><br />---</p>
{% endif %}
<p>if you want to use the native FTP client in windows instead (please dont), press <code>win+R</code> and run this command:</p> <p>if you want to use the native FTP client in windows instead (please dont), press <code>win+R</code> and run this command:</p>
<pre> <pre>
explorer {{ "ftp" if args.ftp else "ftps" }}://{% if accs %}<b>{{ pw }}</b>:k@{% endif %}{{ host }}:{{ args.ftp or args.ftps }}/{{ rvp }} explorer {{ "ftp" if args.ftp else "ftps" }}://{% if accs %}<b>{{ pw }}</b>:k@{% endif %}{{ host }}:{{ args.ftp or args.ftps }}/{{ rvp }}
@@ -121,10 +132,21 @@
</div> </div>
<div class="os lin"> <div class="os lin">
{% if args.ftp %}
<p>connect with plaintext FTP:</p>
<pre> <pre>
rclone config create {{ aname }}-ftp ftp host={{ rip }} port={{ args.ftp or args.ftps }} pass=k user={% if accs %}<b>{{ pw }}</b>{% else %}anonymous{% endif %} tls={{ "false" if args.ftp else "true" }} rclone config create {{ aname }}-ftp ftp host={{ rip }} port={{ args.ftp }} pass=k user={% if accs %}<b>{{ pw }}</b>{% else %}anonymous{% endif %} tls=false
rclone mount --vfs-cache-mode writes --dir-cache-time 5s {{ aname }}-ftp:{{ rvp }} <b>mp</b> rclone mount --vfs-cache-mode writes --dir-cache-time 5s {{ aname }}-ftp:{{ rvp }} <b>mp</b>
</pre> </pre>
{% endif %}
{% if args.ftps %}
<p>connect with TLS-encrypted FTPS:</p>
<pre>
rclone config create {{ aname }}-ftps ftp host={{ rip }} port={{ args.ftps }} pass=k user={% if accs %}<b>{{ pw }}</b>{% else %}anonymous{% endif %} tls=false explicit_tls=true
rclone mount --vfs-cache-mode writes --dir-cache-time 5s {{ aname }}-ftps:{{ rvp }} <b>mp</b>
</pre>
<p><em>note: if you are on LAN (or just dont have valid certificates), add <code>no_check_certificate=true</code> to the config command</em><br />---</p>
{% endif %}
<p>emergency alternative (gnome/gui-only):</p> <p>emergency alternative (gnome/gui-only):</p>
<!-- gnome-bug: ignores vp --> <!-- gnome-bug: ignores vp -->
<pre> <pre>

View File

@@ -1,3 +1,33 @@
▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀
# 2023-0420-2141 `v1.6.12` as seen on nixos
## new features
* @chinponya [made](https://github.com/9001/copyparty/pull/22) a copyparty [Nix package](https://github.com/9001/copyparty#nix-package) and a [NixOS module](https://github.com/9001/copyparty#nixos-module)! nice 🎉
* with [systemd-based hardening](https://github.com/9001/copyparty/blob/hovudstraum/contrib/nixos/modules/copyparty.nix#L230-L270) instead of [prisonparty](https://github.com/9001/copyparty/blob/hovudstraum/bin/prisonparty.sh)
* complements the [arch package](https://github.com/9001/copyparty/tree/hovudstraum/contrib/package/arch) very well w
## bugfixes
* fix an sqlite fd leak
* with enough simultaneous traffic, copyparty could run out of file descriptors since it relied on the gc to close sqlite cursors
* now there's a pool of cursors shared between the tcp connections instead, limited to the number of CPU cores
* performance mostly unaffected (or slightly improved) compared to before, except for a 20% reduction only during max server load caused by directory-listings or searches
* ~~somehow explicitly closing the cursors didn't always work... maybe this was actually a python bug :\\/~~
* yes, it does incomplete cleanup if opening a WAL database fails
* multirange requests would fail with an error; now they get a 200 as expected (since they're kinda useless and not worth the overhead)
* [the only software i've ever seen do that](https://apps.kde.org/discover/) now works as intended
* expand `~/` filesystem paths in all remaining args: `-c`, `-lo`, `--hist`, `--ssl-log`, and the `hist` volflag
* never use IPv6-format IPv4 (`::ffff:127.0.0.1`) in responses
* [u2cli](https://github.com/9001/copyparty/blob/hovudstraum/bin/up2k.py): don't enter delete stage if some of the uploads failed
* audio player in safari on touchbar macbooks
* songs would play backwards because the touchbar keeps spamming play/pause
* playback would stop when the preloader kicks in because safari sees the new audio object and freaks out
## other changes
* added [windows quickstart / service example](https://github.com/9001/copyparty/blob/hovudstraum/docs/examples/windows.md)
* updated pyinstaller (it makes smaller exe files now)
▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀ ▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀
# 2023-0401-2112 `v1.6.11` not joke # 2023-0401-2112 `v1.6.11` not joke

View File

@@ -15,7 +15,7 @@ open up notepad and save the following as `c:\users\you\documents\party.conf` (f
```yaml ```yaml
[global] [global]
lo: c:\users\you\logs\cpp-%Y-%m%d.xz # log to file lo: ~/logs/cpp-%Y-%m%d.xz # log to c:\users\you\logs\
e2dsa, e2ts, no-dedup, z # sets 4 flags; see expl. e2dsa, e2ts, no-dedup, z # sets 4 flags; see expl.
p: 80, 443 # listen on ports 80 and 443, not 3923 p: 80, 443 # listen on ports 80 and 443, not 3923
theme: 2 # default theme: protonmail-monokai theme: 2 # default theme: protonmail-monokai
@@ -47,8 +47,7 @@ open up notepad and save the following as `c:\users\you\documents\party.conf` (f
### config explained: [global] ### config explained: [global]
the `[global]` section accepts any config parameters you can see when running copyparty (either the exe or the sfx.py) with `--help`, so this is the same as running copyparty with arguments `--lo c:\users\you\logs\copyparty-%Y-%m%d.xz -e2dsa -e2ts --no-dedup -z -p 80,443 --theme 2 --lang nor` the `[global]` section accepts any config parameters you can see when running copyparty (either the exe or the sfx.py) with `--help`, so this is the same as running copyparty with arguments `--lo c:\users\you\logs\copyparty-%Y-%m%d.xz -e2dsa -e2ts --no-dedup -z -p 80,443 --theme 2 --lang nor`
* `lo: c:\users\you\logs\cpp-%Y-%m%d.xz` writes compressed logs (the compression will make them delayed) * `lo: ~/logs/cpp-%Y-%m%d.xz` writes compressed logs (the compression will make them delayed)
* sorry that `~/logs/` doesn't work currently, good oversight
* `e2dsa` enables the upload deduplicator and file indexer, which enables searching * `e2dsa` enables the upload deduplicator and file indexer, which enables searching
* `e2ts` enables music metadata indexing, making albums / titles etc. searchable too * `e2ts` enables music metadata indexing, making albums / titles etc. searchable too
* `no-dedup` writes full dupes to disk instead of symlinking, since lots of windows software doesn't handle symlinks well * `no-dedup` writes full dupes to disk instead of symlinking, since lots of windows software doesn't handle symlinks well

View File

@@ -0,0 +1,2 @@
vsftpd a.conf -olisten=YES -olisten_port=3921 -orun_as_launching_user=YES -obackground=NO -olog_ftp_protocol=YES

View File

@@ -122,7 +122,7 @@ class TestHttpCli(unittest.TestCase):
tar = tarfile.open(fileobj=io.BytesIO(b)).getnames() tar = tarfile.open(fileobj=io.BytesIO(b)).getnames()
except: except:
tar = [] tar = []
tar = [x[4:] if x.startswith("top/") else x for x in tar] tar = [x.split("/", 1)[1] for x in tar]
tar = ["/".join([y for y in [top, durl, x] if y]) for x in tar] tar = ["/".join([y for y in [top, durl, x] if y]) for x in tar]
tar = [[x] + self.can_rw(x) for x in tar] tar = [[x] + self.can_rw(x) for x in tar]
tar_ok = [x[0] for x in tar if x[1]] tar_ok = [x[0] for x in tar if x[1]]