mirror of
https://github.com/9001/copyparty.git
synced 2026-01-12 07:44:08 -07:00
sftp: misc fixes + add to docker-im
This commit is contained in:
parent
4e9cf95e8d
commit
ec7ea30951
|
|
@ -1408,7 +1408,7 @@ goes roughly 700 MiB/s (slower than webdav and ftp)
|
||||||
|
|
||||||
the sftp-server requires the optional dependency [paramiko](https://pypi.org/project/paramiko/);
|
the sftp-server requires the optional dependency [paramiko](https://pypi.org/project/paramiko/);
|
||||||
* if you are **not** using docker, then install paramiko somehow
|
* if you are **not** using docker, then install paramiko somehow
|
||||||
* if you **are** using docker, then use one of the following image variants: `ac` / `iv` / `dj`
|
* if you **are** using docker, then use one of the following image variants: `ac` / `im` / `iv` / `dj`
|
||||||
|
|
||||||
enable sftpd with `--sftp 3922` to listen on port 3922;
|
enable sftpd with `--sftp 3922` to listen on port 3922;
|
||||||
* use global-option `sftp-key` to associate an ssh-key with a user;
|
* use global-option `sftp-key` to associate an ssh-key with a user;
|
||||||
|
|
|
||||||
|
|
@ -14,7 +14,13 @@ import paramiko
|
||||||
import paramiko.common
|
import paramiko.common
|
||||||
import paramiko.sftp_attr
|
import paramiko.sftp_attr
|
||||||
from paramiko.common import AUTH_FAILED, AUTH_SUCCESSFUL
|
from paramiko.common import AUTH_FAILED, AUTH_SUCCESSFUL
|
||||||
from paramiko.sftp import SFTP_FAILURE, SFTP_OK, SFTP_PERMISSION_DENIED
|
from paramiko.sftp import (
|
||||||
|
SFTP_FAILURE,
|
||||||
|
SFTP_NO_SUCH_FILE,
|
||||||
|
SFTP_OK,
|
||||||
|
SFTP_OP_UNSUPPORTED,
|
||||||
|
SFTP_PERMISSION_DENIED,
|
||||||
|
)
|
||||||
|
|
||||||
from .__init__ import ANYWIN, TYPE_CHECKING
|
from .__init__ import ANYWIN, TYPE_CHECKING
|
||||||
from .authsrv import LEELOO_DALLAS, VFS, AuthSrv
|
from .authsrv import LEELOO_DALLAS, VFS, AuthSrv
|
||||||
|
|
@ -41,8 +47,7 @@ if TYPE_CHECKING:
|
||||||
from .svchub import SvcHub
|
from .svchub import SvcHub
|
||||||
|
|
||||||
if True: # pylint: disable=using-constant-test
|
if True: # pylint: disable=using-constant-test
|
||||||
import typing
|
from typing import Any, BinaryIO, Optional, Union
|
||||||
from typing import Any, Optional, Union
|
|
||||||
|
|
||||||
SATTR = paramiko.sftp_attr.SFTPAttributes
|
SATTR = paramiko.sftp_attr.SFTPAttributes
|
||||||
|
|
||||||
|
|
@ -247,11 +252,17 @@ class SSH_Srv(paramiko.ServerInterface):
|
||||||
|
|
||||||
|
|
||||||
class SFTP_FH(paramiko.SFTPHandle):
|
class SFTP_FH(paramiko.SFTPHandle):
|
||||||
|
def __init__(self, flags: int = 0) -> None:
|
||||||
|
self.filename = ""
|
||||||
|
self.readfile: Optional[BinaryIO] = None
|
||||||
|
self.writefile: Optional[BinaryIO] = None
|
||||||
|
super(SFTP_FH, self).__init__(flags)
|
||||||
|
|
||||||
def stat(self):
|
def stat(self):
|
||||||
try:
|
try:
|
||||||
return SATTR.from_stat(os.fstat(self.readfile.fileno()))
|
f = self.readfile or self.writefile
|
||||||
|
return SATTR.from_stat(os.fstat(f.fileno()))
|
||||||
except OSError as ex:
|
except OSError as ex:
|
||||||
print("a", repr(ex))
|
|
||||||
return paramiko.SFTPServer.convert_errno(ex.errno)
|
return paramiko.SFTPServer.convert_errno(ex.errno)
|
||||||
|
|
||||||
def chattr(self, attr):
|
def chattr(self, attr):
|
||||||
|
|
@ -332,16 +343,21 @@ class SFTP_Srv(paramiko.SFTPServerInterface):
|
||||||
def list_folder(self, path: str) -> list[SATTR] | int:
|
def list_folder(self, path: str) -> list[SATTR] | int:
|
||||||
try:
|
try:
|
||||||
return self._list_folder(path)
|
return self._list_folder(path)
|
||||||
|
except Pebkac as ex:
|
||||||
|
if ex.code == 404:
|
||||||
|
self.log("folder 404: %s" % (path,))
|
||||||
|
return SFTP_NO_SUCH_FILE
|
||||||
|
return SFTP_PERMISSION_DENIED
|
||||||
except:
|
except:
|
||||||
self.log("unhandled exception: %s" % (min_ex(),), 1)
|
self.log("unhandled exception: %s" % (min_ex(),), 1)
|
||||||
return SFTP_FAILURE
|
return SFTP_FAILURE
|
||||||
|
|
||||||
def _list_folder(self, path: str) -> list[SATTR] | int:
|
def _list_folder(self, path: str) -> list[SATTR] | int:
|
||||||
try:
|
try:
|
||||||
ap, vn, rem = self.v2a(path, True, False, False, False)
|
ap, vn, rem = self.v2a(path, r=True)
|
||||||
except Pebkac:
|
except Pebkac:
|
||||||
try:
|
try:
|
||||||
self.v2a(path, False, True, False, False)
|
self.v2a(path, w=True)
|
||||||
return [] # display write-only folders as empty
|
return [] # display write-only folders as empty
|
||||||
except:
|
except:
|
||||||
pass
|
pass
|
||||||
|
|
@ -396,12 +412,12 @@ class SFTP_Srv(paramiko.SFTPServerInterface):
|
||||||
|
|
||||||
def _stat(self, vp: str) -> SATTR | int:
|
def _stat(self, vp: str) -> SATTR | int:
|
||||||
try:
|
try:
|
||||||
ap = self.v2a(vp, True, False, False, False)[0]
|
ap = self.v2a(vp, r=True)[0]
|
||||||
st = bos.stat(ap)
|
st = bos.stat(ap)
|
||||||
except:
|
except:
|
||||||
if vp.strip("/") or self.asrv.vfs.realpath:
|
if vp.strip("/") or self.asrv.vfs.realpath:
|
||||||
try:
|
try:
|
||||||
self.v2a(vp, False, True, False, False)[0]
|
self.v2a(vp, w=True)[0]
|
||||||
except:
|
except:
|
||||||
return SFTP_PERMISSION_DENIED
|
return SFTP_PERMISSION_DENIED
|
||||||
zi = int(time.time())
|
zi = int(time.time())
|
||||||
|
|
@ -634,7 +650,7 @@ class SFTP_Srv(paramiko.SFTPServerInterface):
|
||||||
return paramiko.SFTPServer.convert_errno(ex.errno)
|
return paramiko.SFTPServer.convert_errno(ex.errno)
|
||||||
|
|
||||||
def symlink(self, target_path: str, path: str) -> int:
|
def symlink(self, target_path: str, path: str) -> int:
|
||||||
return paramiko.SFTPServer.SFTP_OP_UNSUPPORTED
|
return SFTP_OP_UNSUPPORTED
|
||||||
|
|
||||||
def readlink(self, path: str) -> str | int:
|
def readlink(self, path: str) -> str | int:
|
||||||
return path
|
return path
|
||||||
|
|
|
||||||
|
|
@ -1148,7 +1148,7 @@ class Up2k(object):
|
||||||
ft = "\033[0;32m{}{:.0}"
|
ft = "\033[0;32m{}{:.0}"
|
||||||
ff = "\033[0;35m{}{:.0}"
|
ff = "\033[0;35m{}{:.0}"
|
||||||
fv = "\033[0;36m{}:\033[90m{}"
|
fv = "\033[0;36m{}:\033[90m{}"
|
||||||
zs = "bcasechk du_iwho emb_lgs emb_mds ext_th_d html_head html_head_d html_head_s put_name2 mv_re_r mv_re_t rm_re_r rm_re_t srch_re_dots srch_re_nodot zipmax zipmaxn_v zipmaxs_v"
|
zs = "bcasechk du_iwho emb_lgs emb_mds ext_th_d html_head html_head_d html_head_s ls_q_m put_name2 mv_re_r mv_re_t rm_re_r rm_re_t srch_re_dots srch_re_nodot zipmax zipmaxn_v zipmaxs_v"
|
||||||
fx = set(zs.split())
|
fx = set(zs.split())
|
||||||
fd = vf_bmap()
|
fd = vf_bmap()
|
||||||
fd.update(vf_cmap())
|
fd.update(vf_cmap())
|
||||||
|
|
|
||||||
|
|
@ -9,7 +9,8 @@ ENV XDG_CONFIG_HOME=/cfg
|
||||||
|
|
||||||
RUN apk --no-cache add !pyc \
|
RUN apk --no-cache add !pyc \
|
||||||
tzdata wget mimalloc2 mimalloc2-insecure \
|
tzdata wget mimalloc2 mimalloc2-insecure \
|
||||||
py3-jinja2 py3-argon2-cffi py3-openssl py3-pillow py3-mutagen
|
py3-jinja2 py3-argon2-cffi \
|
||||||
|
py3-openssl py3-paramiko py3-pillow py3-mutagen
|
||||||
|
|
||||||
COPY i/dist/copyparty-sfx.py innvikler.sh ./
|
COPY i/dist/copyparty-sfx.py innvikler.sh ./
|
||||||
ADD base ./base
|
ADD base ./base
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue