Skip to content

Commit 33ba7f1

Browse files
authored
feat: sftp server support (#7643)
* feat: sftp server support * fix(sftp-server): try fix build failed * fix: sftp download lack
1 parent 201e25c commit 33ba7f1

File tree

14 files changed

+584
-32
lines changed

14 files changed

+584
-32
lines changed

cmd/common.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ import (
1515
func Init() {
1616
bootstrap.InitConfig()
1717
bootstrap.Log()
18+
bootstrap.InitHostKey()
1819
bootstrap.InitDB()
1920
data.InitData()
2021
bootstrap.InitIndex()

cmd/server.go

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import (
55
"errors"
66
"fmt"
77
ftpserver "github.com/KirCute/ftpserverlib-pasvportmap"
8+
"github.com/KirCute/sftpd-alist"
89
"net"
910
"net/http"
1011
"os"
@@ -131,6 +132,24 @@ the address is defined in config file`,
131132
}()
132133
}
133134
}
135+
var sftpDriver *server.SftpDriver
136+
var sftpServer *sftpd.SftpServer
137+
if conf.Conf.SFTP.Listen != "" && conf.Conf.SFTP.Enable {
138+
var err error
139+
sftpDriver, err = server.NewSftpDriver()
140+
if err != nil {
141+
utils.Log.Fatalf("failed to start sftp driver: %s", err.Error())
142+
} else {
143+
utils.Log.Infof("start sftp server on %s", conf.Conf.SFTP.Listen)
144+
go func() {
145+
sftpServer = sftpd.NewSftpServer(sftpDriver)
146+
err = sftpServer.RunServer()
147+
if err != nil {
148+
utils.Log.Fatalf("problem sftp server listening: %s", err.Error())
149+
}
150+
}()
151+
}
152+
}
134153
// Wait for interrupt signal to gracefully shutdown the server with
135154
// a timeout of 1 second.
136155
quit := make(chan os.Signal, 1)
@@ -181,6 +200,15 @@ the address is defined in config file`,
181200
}
182201
}()
183202
}
203+
if conf.Conf.SFTP.Listen != "" && conf.Conf.SFTP.Enable && sftpServer != nil && sftpDriver != nil {
204+
wg.Add(1)
205+
go func() {
206+
defer wg.Done()
207+
if err := sftpServer.Close(); err != nil {
208+
utils.Log.Fatal("SFTP server shutdown err: ", err)
209+
}
210+
}()
211+
}
184212
wg.Wait()
185213
utils.Log.Println("Server exit")
186214
},

go.mod

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@ module github.com/alist-org/alist/v3
33
go 1.22.4
44

55
require (
6+
github.com/KirCute/ftpserverlib-pasvportmap v1.25.0
7+
github.com/KirCute/sftpd-alist v0.0.11
68
github.com/SheltonZhu/115driver v1.0.32
79
github.com/Xhofe/go-cache v0.0.0-20240804043513-b1a71927bc21
810
github.com/Xhofe/rateg v0.0.0-20230728072201-251a4e1adad4
@@ -60,7 +62,7 @@ require (
6062
github.com/xhofe/tache v0.1.3
6163
github.com/xhofe/wopan-sdk-go v0.1.3
6264
github.com/zzzhr1990/go-common-entity v0.0.0-20221216044934-fd1c571e3a22
63-
golang.org/x/crypto v0.27.0
65+
golang.org/x/crypto v0.30.0
6466
golang.org/x/exp v0.0.0-20240904232852-e7e105dedf7e
6567
golang.org/x/image v0.19.0
6668
golang.org/x/net v0.28.0
@@ -76,7 +78,6 @@ require (
7678

7779
require (
7880
github.com/BurntSushi/toml v0.3.1 // indirect
79-
github.com/KirCute/ftpserverlib-pasvportmap v0.0.0-20241208190057-c9a7bf2571e2 // indirect
8081
github.com/blevesearch/go-faiss v1.0.20 // indirect
8182
github.com/blevesearch/zapx/v16 v16.1.5 // indirect
8283
github.com/bytedance/sonic/loader v0.1.1 // indirect
@@ -90,6 +91,7 @@ require (
9091
github.com/hekmon/cunits/v2 v2.1.0 // indirect
9192
github.com/ipfs/boxo v0.12.0 // indirect
9293
github.com/jackc/puddle/v2 v2.2.1 // indirect
94+
github.com/taruti/bytepool v0.0.0-20160310082835-5e3a9ea56543 // indirect
9395
)
9496

9597
require (
@@ -223,10 +225,10 @@ require (
223225
github.com/yusufpapurcu/wmi v1.2.4 // indirect
224226
go.etcd.io/bbolt v1.3.8 // indirect
225227
golang.org/x/arch v0.8.0 // indirect
226-
golang.org/x/sync v0.8.0 // indirect
228+
golang.org/x/sync v0.10.0 // indirect
227229
golang.org/x/sys v0.28.0 // indirect
228-
golang.org/x/term v0.24.0 // indirect
229-
golang.org/x/text v0.18.0 // indirect
230+
golang.org/x/term v0.27.0 // indirect
231+
golang.org/x/text v0.21.0 // indirect
230232
golang.org/x/tools v0.24.0 // indirect
231233
google.golang.org/api v0.169.0 // indirect
232234
google.golang.org/genproto/googleapis/rpc v0.0.0-20240604185151-ef581f913117 // indirect

go.sum

Lines changed: 14 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,10 @@ cloud.google.com/go/compute/metadata v0.3.0 h1:Tz+eQXMEqDIKRsmY3cHTL6FVaynIjX2Qx
44
cloud.google.com/go/compute/metadata v0.3.0/go.mod h1:zFmK7XCadkQkj6TtorcaGlCW1hT1fIilQDwofLpJ20k=
55
github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ=
66
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
7-
github.com/KirCute/ftpserverlib-pasvportmap v0.0.0-20241208190057-c9a7bf2571e2 h1:P3MoQ1kDfbCjL6+MPd5K7wPdKB4nqMuLU6Mv0+tdWDA=
8-
github.com/KirCute/ftpserverlib-pasvportmap v0.0.0-20241208190057-c9a7bf2571e2/go.mod h1:v0NgMtKDDi/6CM6r4P+daCljCW3eO9yS+Z+pZDTKo1E=
7+
github.com/KirCute/ftpserverlib-pasvportmap v1.25.0 h1:ikwCzeqoqN6wvBHOB9OI6dde/jbV7EoTMpUcxtYl5Po=
8+
github.com/KirCute/ftpserverlib-pasvportmap v1.25.0/go.mod h1:v0NgMtKDDi/6CM6r4P+daCljCW3eO9yS+Z+pZDTKo1E=
9+
github.com/KirCute/sftpd-alist v0.0.11 h1:BGInXmmLBI+v6S9WZCwvY0DRK1vDprGNcTv/57p2GSo=
10+
github.com/KirCute/sftpd-alist v0.0.11/go.mod h1:pPFzr6GrKqXvFXLr46ZpoqmtSpwH8DKTYloSp/ybzKQ=
911
github.com/Max-Sum/base32768 v0.0.0-20230304063302-18e6ce5945fd h1:nzE1YQBdx1bq9IlZinHa+HVffy+NmVRoKr+wHN8fpLE=
1012
github.com/Max-Sum/base32768 v0.0.0-20230304063302-18e6ce5945fd/go.mod h1:C8yoIfvESpM3GD07OCHU7fqI7lhwyZ2Td1rbNbTAhnc=
1113
github.com/RoaringBitmap/roaring v1.9.3 h1:t4EbC5qQwnisr5PrP9nt0IRhRTb9gMUgQF4t4S2OByM=
@@ -492,12 +494,13 @@ github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO
492494
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
493495
github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
494496
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
495-
github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
496497
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
497498
github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
498499
github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
499500
github.com/t3rm1n4l/go-mega v0.0.0-20240219080617-d494b6a8ace7 h1:Jtcrb09q0AVWe3BGe8qtuuGxNSHWGkTWr43kHTJ+CpA=
500501
github.com/t3rm1n4l/go-mega v0.0.0-20240219080617-d494b6a8ace7/go.mod h1:suDIky6yrK07NnaBadCB4sS0CqFOvUK91lH7CR+JlDA=
502+
github.com/taruti/bytepool v0.0.0-20160310082835-5e3a9ea56543 h1:6Y51mutOvRGRx6KqyMNo//xk8B8o6zW9/RVmy1VamOs=
503+
github.com/taruti/bytepool v0.0.0-20160310082835-5e3a9ea56543/go.mod h1:jpwqYA8KUVEvSUJHkCXsnBRJCSKP1BMa81QZ6kvRpow=
501504
github.com/tklauser/go-sysconf v0.3.12/go.mod h1:Ho14jnntGE1fpdOqQEEaiKRpvIavV0hSfmBq8nJbHYI=
502505
github.com/tklauser/go-sysconf v0.3.13 h1:GBUpcahXSpR2xN01jhkNAbTLRk2Yzgggk8IM08lq3r4=
503506
github.com/tklauser/go-sysconf v0.3.13/go.mod h1:zwleP4Q4OehZHGn4CYZDipCgg9usW5IJePewFCGVEa0=
@@ -571,8 +574,8 @@ golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliY
571574
golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU=
572575
golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8=
573576
golang.org/x/crypto v0.25.0/go.mod h1:T+wALwcMOSE0kXgUAnPAHqTLW+XHgcELELW8VaDgm/M=
574-
golang.org/x/crypto v0.27.0 h1:GXm2NjJrPaiv/h1tb2UH8QfgC/hOf/+z0p6PT8o1w7A=
575-
golang.org/x/crypto v0.27.0/go.mod h1:1Xngt8kV6Dvbssa53Ziq6Eqn0HqbZi5Z6R0ZpwQzt70=
577+
golang.org/x/crypto v0.30.0 h1:RwoQn3GkWiMkzlX562cLB7OxWvjH1L8xutO2WoJcRoY=
578+
golang.org/x/crypto v0.30.0/go.mod h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ssk=
576579
golang.org/x/exp v0.0.0-20240904232852-e7e105dedf7e h1:I88y4caeGeuDQxgdoFPUq097j7kNfw6uvuiNxUBfcBk=
577580
golang.org/x/exp v0.0.0-20240904232852-e7e105dedf7e/go.mod h1:akd2r19cwCdwSwWeIdzYQGa/EZZyqcOdwWiwj5L5eKQ=
578581
golang.org/x/image v0.0.0-20191009234506-e7c1f5e7dbb8/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
@@ -614,8 +617,8 @@ golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
614617
golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y=
615618
golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
616619
golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
617-
golang.org/x/sync v0.8.0 h1:3NFvSEYkUoMifnESzZl15y791HH1qU2xm6eCJU5ZPXQ=
618-
golang.org/x/sync v0.8.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
620+
golang.org/x/sync v0.10.0 h1:3NQrjDixjgGwUOCaF8w2+VYHv0Ve/vGYSbdkTa98gmQ=
621+
golang.org/x/sync v0.10.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
619622
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
620623
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
621624
golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
@@ -647,8 +650,6 @@ golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
647650
golang.org/x/sys v0.19.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
648651
golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
649652
golang.org/x/sys v0.22.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
650-
golang.org/x/sys v0.25.0 h1:r+8e+loiHxRqhXVl6ML1nO3l1+oFoWbnlu2Ehimmi34=
651-
golang.org/x/sys v0.25.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
652653
golang.org/x/sys v0.28.0 h1:Fksou7UEQUWlKvIdsqzJmUmCX3cZuD2+P3XyyzwMhlA=
653654
golang.org/x/sys v0.28.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
654655
golang.org/x/telemetry v0.0.0-20240228155512-f48c80bd79b2/go.mod h1:TeRTkGYfJXctD9OcfyVLyj2J3IxLnKwHJR8f4D8a3YE=
@@ -661,8 +662,8 @@ golang.org/x/term v0.12.0/go.mod h1:owVbMEjm3cBLCHdkQu9b1opXd4ETQWc3BhuQGKgXgvU=
661662
golang.org/x/term v0.17.0/go.mod h1:lLRBjIVuehSbZlaOtGMbcMncT+aqLLLmKrsjNrUguwk=
662663
golang.org/x/term v0.20.0/go.mod h1:8UkIAJTvZgivsXaD6/pH6U9ecQzZ45awqEOzuCvwpFY=
663664
golang.org/x/term v0.22.0/go.mod h1:F3qCibpT5AMpCRfhfT53vVJwhLtIVHhB9XDjfFvnMI4=
664-
golang.org/x/term v0.24.0 h1:Mh5cbb+Zk2hqqXNO7S1iTjEphVL+jb8ZWaqh/g+JWkM=
665-
golang.org/x/term v0.24.0/go.mod h1:lOBK/LVxemqiMij05LGJ0tzNr8xlmwBRJ81PX6wVLH8=
665+
golang.org/x/term v0.27.0 h1:WP60Sv1nlK1T6SupCHbXzSaN0b9wUmsPoRS9b61A23Q=
666+
golang.org/x/term v0.27.0/go.mod h1:iMsnZpn0cago0GOrHO2+Y7u7JPn5AylBrcoWkElMTSM=
666667
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
667668
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
668669
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
@@ -676,8 +677,8 @@ golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
676677
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
677678
golang.org/x/text v0.15.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
678679
golang.org/x/text v0.16.0/go.mod h1:GhwF1Be+LQoKShO3cGOHzqOgRrGaYc9AvblQOmPVHnI=
679-
golang.org/x/text v0.18.0 h1:XvMDiNzPAl0jr17s6W9lcaIhGUfUORdGCNsuLmPG224=
680-
golang.org/x/text v0.18.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY=
680+
golang.org/x/text v0.21.0 h1:zyQAAkrwaneQ066sspRyJaG9VNi/YJ1NfzcGB3hZ/qo=
681+
golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ=
681682
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
682683
golang.org/x/time v0.0.0-20220722155302-e5dcc9cfc0b9/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
683684
golang.org/x/time v0.6.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM=

internal/bootstrap/ssh.go

Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
package bootstrap
2+
3+
import (
4+
"crypto/rand"
5+
"crypto/rsa"
6+
"crypto/x509"
7+
"encoding/pem"
8+
"fmt"
9+
"github.com/alist-org/alist/v3/cmd/flags"
10+
"github.com/alist-org/alist/v3/internal/conf"
11+
"github.com/alist-org/alist/v3/pkg/utils"
12+
"golang.org/x/crypto/ssh"
13+
"os"
14+
"path/filepath"
15+
)
16+
17+
func InitHostKey() {
18+
sshPath := filepath.Join(flags.DataDir, "ssh")
19+
if !utils.Exists(sshPath) {
20+
err := utils.CreateNestedDirectory(sshPath)
21+
if err != nil {
22+
utils.Log.Fatalf("failed to create ssh directory: %+v", err)
23+
return
24+
}
25+
}
26+
conf.SSHSigners = make([]ssh.Signer, 0, 4)
27+
if rsaKey, ok := LoadOrGenerateRSAHostKey(sshPath); ok {
28+
conf.SSHSigners = append(conf.SSHSigners, rsaKey)
29+
}
30+
// TODO Add keys for other encryption algorithms
31+
}
32+
33+
func LoadOrGenerateRSAHostKey(parentDir string) (ssh.Signer, bool) {
34+
privateKeyPath := filepath.Join(parentDir, "ssh_host_rsa_key")
35+
publicKeyPath := filepath.Join(parentDir, "ssh_host_rsa_key.pub")
36+
privateKeyBytes, err := os.ReadFile(privateKeyPath)
37+
if err == nil {
38+
var privateKey *rsa.PrivateKey
39+
privateKey, err = rsaDecodePrivateKey(privateKeyBytes)
40+
if err == nil {
41+
var ret ssh.Signer
42+
ret, err = ssh.NewSignerFromKey(privateKey)
43+
if err == nil {
44+
return ret, true
45+
}
46+
}
47+
}
48+
_ = os.Remove(privateKeyPath)
49+
_ = os.Remove(publicKeyPath)
50+
privateKey, err := rsa.GenerateKey(rand.Reader, 4096)
51+
if err != nil {
52+
utils.Log.Fatalf("failed to generate RSA private key: %+v", err)
53+
return nil, false
54+
}
55+
publicKey, err := ssh.NewPublicKey(&privateKey.PublicKey)
56+
if err != nil {
57+
utils.Log.Fatalf("failed to generate RSA public key: %+v", err)
58+
return nil, false
59+
}
60+
ret, err := ssh.NewSignerFromKey(privateKey)
61+
if err != nil {
62+
utils.Log.Fatalf("failed to generate RSA signer: %+v", err)
63+
return nil, false
64+
}
65+
privateBytes := rsaEncodePrivateKey(privateKey)
66+
publicBytes := ssh.MarshalAuthorizedKey(publicKey)
67+
err = os.WriteFile(privateKeyPath, privateBytes, 0600)
68+
if err != nil {
69+
utils.Log.Fatalf("failed to write RSA private key to file: %+v", err)
70+
return nil, false
71+
}
72+
err = os.WriteFile(publicKeyPath, publicBytes, 0644)
73+
if err != nil {
74+
_ = os.Remove(privateKeyPath)
75+
utils.Log.Fatalf("failed to write RSA public key to file: %+v", err)
76+
return nil, false
77+
}
78+
return ret, true
79+
}
80+
81+
func rsaEncodePrivateKey(privateKey *rsa.PrivateKey) []byte {
82+
privateKeyBytes := x509.MarshalPKCS1PrivateKey(privateKey)
83+
privateBlock := &pem.Block{
84+
Type: "RSA PRIVATE KEY",
85+
Headers: nil,
86+
Bytes: privateKeyBytes,
87+
}
88+
return pem.EncodeToMemory(privateBlock)
89+
}
90+
91+
func rsaDecodePrivateKey(bytes []byte) (*rsa.PrivateKey, error) {
92+
block, _ := pem.Decode(bytes)
93+
if block == nil {
94+
return nil, fmt.Errorf("failed to parse PEM block containing the key")
95+
}
96+
privateKey, err := x509.ParsePKCS1PrivateKey(block.Bytes)
97+
if err != nil {
98+
return nil, err
99+
}
100+
return privateKey, nil
101+
}

internal/conf/config.go

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,11 @@ type FTP struct {
8484
EnablePasvConnIPCheck bool `json:"enable_pasv_conn_ip_check" env:"ENABLE_PASV_CONN_IP_CHECK"`
8585
}
8686

87+
type SFTP struct {
88+
Enable bool `json:"enable" env:"ENABLE"`
89+
Listen string `json:"listen" env:"LISTEN"`
90+
}
91+
8792
type Config struct {
8893
Force bool `json:"force" env:"FORCE"`
8994
SiteURL string `json:"site_url" env:"SITE_URL"`
@@ -104,6 +109,7 @@ type Config struct {
104109
Cors Cors `json:"cors" envPrefix:"CORS_"`
105110
S3 S3 `json:"s3" envPrefix:"S3_"`
106111
FTP FTP `json:"ftp" envPrefix:"FTP_"`
112+
SFTP SFTP `json:"sftp" envPrefix:"SFTP_"`
107113
}
108114

109115
func DefaultConfig() *Config {
@@ -185,5 +191,9 @@ func DefaultConfig() *Config {
185191
EnableActiveConnIPCheck: true,
186192
EnablePasvConnIPCheck: true,
187193
},
194+
SFTP: SFTP{
195+
Enable: true,
196+
Listen: ":5222",
197+
},
188198
}
189199
}

internal/conf/var.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package conf
22

33
import (
4+
"golang.org/x/crypto/ssh"
45
"net/url"
56
"regexp"
67
)
@@ -32,3 +33,5 @@ var (
3233
ManageHtml string
3334
IndexHtml string
3435
)
36+
37+
var SSHSigners []ssh.Signer

server/ftp.go

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@ func NewMainDriver() (*FtpMainDriver, error) {
7070
Banner: setting.GetStr(conf.Announcement),
7171
TLSRequired: tlsRequired,
7272
DisableLISTArgs: false,
73-
DisableSite: true,
73+
DisableSite: false,
7474
DisableActiveMode: conf.Conf.FTP.DisableActiveMode,
7575
EnableHASH: false,
7676
DisableSTAT: false,
@@ -79,6 +79,9 @@ func NewMainDriver() (*FtpMainDriver, error) {
7979
DefaultTransferType: transferType,
8080
ActiveConnectionsCheck: activeConnCheck,
8181
PasvConnectionsCheck: pasvConnCheck,
82+
SiteHandlers: map[string]ftpserver.SiteHandler{
83+
"SIZE": ftp.HandleSIZE,
84+
},
8285
},
8386
proxyHeader: header,
8487
clients: make(map[uint32]ftpserver.ClientContext),
@@ -128,7 +131,7 @@ func (d *FtpMainDriver) AuthUser(cc ftpserver.ClientContext, user, pass string)
128131
}
129132
}
130133
if userObj.Disabled || !userObj.CanFTPAccess() {
131-
return nil, errors.New("user not allowed to access FTP")
134+
return nil, errors.New("user is not allowed to access via FTP")
132135
}
133136

134137
ctx := context.Background()

0 commit comments

Comments
 (0)