WebShell中实现SFTP文件管理

WebShell终端给了用户网页形式操作终端的能力后,还需要提供可视化的文件管理,具体来说就是文件上下载,权限修改,在线编辑等。

这里总结下关于这块的实现。

ssh2+ssh2-sftp-client

使用ssh2模块进行解决终端连接后,继续使用ssh2-sftp-client来实现文件的相关操作

  1. list方法实现文件列表获取
    • 返回值中可以拿到文件类型,文件名称,文件所属用户id,文件所属用户组id,文件大小,访问时间,修改时间
    • 需要说明,如果是软链接,返回的type是l,硬连接的话会是-
  2. get/put方法实现流方式的上下载
  3. rename方法实现文件重命名
  4. delete方法实现文件删除
  5. stat方法实现文件信息获取
  6. mkdir方法实现文件夹创建
  7. rename方法实现文件重命名

如上使用这些方法可以解决了文件管理的一些基本问题,但还有些问题需要处理

问题

  1. 判断当前用户是否有权限

首先需要知道当前用户的uid,gid,因此需要走ssh2的exec执行id命令从而获取这些信息,然后当list方法返回文件的uid,gid后,两者进行比较判断即可确定权限

  1. 用户列表

GUI上需要实现修改文件所有者,通过执行文件list或者stat命令可以知道文件归属的uid,gid,因此只需要再获取user list即可。这里使用执行命令

1
2
3
# 返回格式如下
# root,0
grep /bin/bash /etc/passwd | awk -F: '{print $1 "," $3}'
  1. 文件列表-隐藏文件显示控制

    如果需要隐藏文件不可见,如下配置正则表达式,即过滤掉.开头文件

    1
    conn.list(path, /^[^.]/);

    这里有意思的是SFTP协议是没有针对文件列表过滤支持的,因此ssh2实际上还是拿了全量的文件列表,在客户端进行的过滤。

    ssh2-sftp-client v9已经调整了list方法,filter从正则改为了回调函数,还是可以实现上述效果

  2. 以终端会话的当前工作路径作为缺省打开路径

    这个文件严格来说是终端部分,并不是SFTP问题,但支持该功能,非常提升UE。这个feat的实现简单,主要是利用了终端钩子,用户每次执行命令后,执行PWD命令,并将解决返回客户端,客户端解析PWD了解当前的路径并存储起来。这样当用户操作到某个路径下时,打开SFTP,将该路径作为path参数传入即可

    1
    2
    3
    4
    source /usr/local/bash-precmd/bash-preexec.sh
    preexec() { printf "\x1B]1337;PreExec;Timestamp=$(date +%s);\x7"; }

    precmd() { printf "\x1B]1337;PostExec;Exit=$?;CurrentDir=$(pwd);Timestamp=$(date +%s);CurrentUser=$USER;\x7"; }

除了SFTP协议下支持文件管理,还有一些其它情况,比如kubectl

kubectl

如果是kubectl管理连接的容器,那么并不能使用sftp协议,因此需要走透传执行各种命令来解决。命令获取后则解析结果

  1. ls等命令来实现文件列表。但问题在于不同容器系统下命令存在一定程度的兼容性,这里就需要区分处理了

    1
    ls -l --time-style=full-iso /
    • 如果是不显示隐藏文件,则增加A选项
    • full-iso用于控制时间的格式化,如果不加的话,时间参数的格式受系统locale影响
  2. 文件属性的方法不建议采用stat命令做,因为命令结果存在国际化部分,比如其中的文件类型,下图显示是directory,但是如果目标机器locale不是en,则会不同。

    https://static.1991421.cn/2023/2023-09-26-223148.jpeg

    因此,这里推荐仍然走ls命令解决,注意携带参数d,这样结果只有一个,即目标文件/文件夹。另外注意与ls -l相比,没有第一行的统计结果。

    1
    ls -ld --time-style=full-iso /

写在最后

  • 以上即为文件管理的大致实现,当然实际会比上述复杂些,但关键点还是这些

  • 在WebShell上线了文件管理相关功能后,通过长期的观察,文件功能属于现有所有功能的No1,可见该功能非常重要。