gitea/workflows: upgrade actions (#173)
All checks were successful
checks / check and test (push) Successful in 14s
All checks were successful
checks / check and test (push) Successful in 14s
Attempt at upgrading actions/checkout, actions/setup-go. Also upgrade the Go version to the moving target `stable`. Co-authored-by: Olivier Mengué <dolmen@cpan.org> Co-authored-by: Lunny Xiao <xiaolunwen@gmail.com> Reviewed-on: #173 Co-authored-by: dolmen <dolmen@noreply.gitea.com> Co-committed-by: dolmen <dolmen@noreply.gitea.com>
This commit was merged in pull request #173.
This commit is contained in:
@@ -3,56 +3,34 @@ on:
|
||||
- push
|
||||
- pull_request
|
||||
|
||||
env:
|
||||
GOPROXY: https://goproxy.io,direct
|
||||
GOPATH: /go_path
|
||||
GOCACHE: /go_cache
|
||||
|
||||
jobs:
|
||||
lint:
|
||||
name: check and test
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
# - name: cache go path
|
||||
# id: cache-go-path
|
||||
# uses: https://github.com/actions/cache@v3
|
||||
# with:
|
||||
# path: /go_path
|
||||
# key: go_path-${{ github.repository }}-${{ github.ref_name }}
|
||||
# restore-keys: |
|
||||
# go_path-${{ github.repository }}-
|
||||
# go_path-
|
||||
# - name: cache go cache
|
||||
# id: cache-go-cache
|
||||
# uses: https://github.com/actions/cache@v3
|
||||
# with:
|
||||
# path: /go_cache
|
||||
# key: go_cache-${{ github.repository }}-${{ github.ref_name }}
|
||||
# restore-keys: |
|
||||
# go_cache-${{ github.repository }}-
|
||||
# go_cache-
|
||||
- uses: actions/setup-go@v3
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/setup-go@v5
|
||||
with:
|
||||
go-version: 1.20
|
||||
- uses: https://github.com/actions/checkout@v3
|
||||
- name: lint
|
||||
run: go install golang.org/x/lint/golint@latest && golint ./...
|
||||
- name: vet
|
||||
run: go vet ./...
|
||||
go-version-file: 'go.mod'
|
||||
- name: lint and build
|
||||
run: |
|
||||
go vet ./...
|
||||
make lint
|
||||
make fmt-check
|
||||
make misspell-check
|
||||
go build
|
||||
- name: test
|
||||
run: go test -v -race -coverprofile=coverage.txt -covermode=atomic ./...
|
||||
env:
|
||||
MINIO_SERVER_ENDPOINT: minio:9000
|
||||
MINIO_SERVER_ACCESS_KEY_ID: ${{ secrets.aws_access_key_id }}
|
||||
MINIO_SERVER_SECRET_KEY: ${{ secrets.aws_secret_access_key }}
|
||||
MINIO_SERVER_ACCESS_KEY_ID: 123456
|
||||
MINIO_SERVER_SECRET_KEY: 12345678
|
||||
MINIO_SERVER_BUCKET: test
|
||||
services:
|
||||
minio:
|
||||
image: minio/minio:RELEASE.2022-07-24T01-54-52Z
|
||||
image: bitnami/minio:2023.8.31
|
||||
env:
|
||||
MINIO_ACCESS_KEY: ${{ secrets.aws_access_key_id }}
|
||||
MINIO_SECRET_KEY: ${{ secrets.aws_secret_access_key }}
|
||||
cmd:
|
||||
- 'minio'
|
||||
- 'server'
|
||||
- '/data'
|
||||
MINIO_ROOT_USER: 123456
|
||||
MINIO_ROOT_PASSWORD: 12345678
|
||||
ports:
|
||||
- "9000:9000"
|
||||
|
||||
1
.gitignore
vendored
1
.gitignore
vendored
@@ -3,3 +3,4 @@ coverage.txt
|
||||
exampleftpd/exampleftpd
|
||||
.vscode
|
||||
*~
|
||||
ftp_server
|
||||
24
.revive.toml
Normal file
24
.revive.toml
Normal file
@@ -0,0 +1,24 @@
|
||||
ignoreGeneratedHeader = false
|
||||
severity = "warning"
|
||||
confidence = 0.8
|
||||
errorCode = 1
|
||||
warningCode = 1
|
||||
|
||||
[rule.blank-imports]
|
||||
[rule.context-as-argument]
|
||||
[rule.context-keys-type]
|
||||
[rule.dot-imports]
|
||||
[rule.error-return]
|
||||
[rule.error-strings]
|
||||
[rule.error-naming]
|
||||
[rule.exported]
|
||||
[rule.if-return]
|
||||
[rule.increment-decrement]
|
||||
[rule.var-naming]
|
||||
[rule.var-declaration]
|
||||
[rule.range]
|
||||
[rule.receiver-naming]
|
||||
[rule.time-naming]
|
||||
[rule.unexported-return]
|
||||
[rule.indent-error-flow]
|
||||
[rule.errorf]
|
||||
64
Makefile
Normal file
64
Makefile
Normal file
@@ -0,0 +1,64 @@
|
||||
DIST := dist
|
||||
GO ?= go
|
||||
SHASUM ?= shasum -a 256
|
||||
|
||||
export PATH := $($(GO) env GOPATH)/bin:$(PATH)
|
||||
|
||||
GOFILES := $(shell find . -name "*.go" -type f ! -path "*/bindata.go")
|
||||
SERVER_VERSION ?= $(shell git describe --tags --always | sed 's/-/+/' | sed 's/^v//')
|
||||
SERVER_VERSION_TAG ?= $(shell sed 's/+/_/' <<< $(SERVER_VERSION))
|
||||
|
||||
TAGS ?=
|
||||
LDFLAGS := -X "gitea.com/goftp/server.version=$(SERVER_VERSION)" -s -w
|
||||
|
||||
# override to allow passing additional goflags via make CLI
|
||||
override GOFLAGS := $(GOFLAGS) -tags '$(TAGS)' -ldflags '$(LDFLAGS)'
|
||||
|
||||
PACKAGES ?= $(shell $(GO) list ./...)
|
||||
SOURCES ?= $(shell find . -name "*.go" -type f)
|
||||
|
||||
.PHONY: fmt
|
||||
fmt:
|
||||
go fmt ./...
|
||||
|
||||
.PHONY: lint
|
||||
lint: install-lint-tools
|
||||
$(GO) run github.com/mgechev/revive@v1.3.2 -config .revive.toml ./... || exit 1
|
||||
|
||||
.PHONY: misspell-check
|
||||
misspell-check: install-lint-tools
|
||||
$(GO) run github.com/client9/misspell/cmd/misspell@latest -error -i unknwon,destory $(GOFILES)
|
||||
|
||||
.PHONY: misspell
|
||||
misspell: install-lint-tools
|
||||
$(GO) run github.com/client9/misspell/cmd/misspell@latest -w -i unknwon $(GOFILES)
|
||||
|
||||
.PHONY: fmt-check
|
||||
fmt-check:
|
||||
# get all go files and run go fmt on them
|
||||
@diff=$$(go fmt ./...); \
|
||||
if [ -n "$$diff" ]; then \
|
||||
echo "Please run 'make fmt' and commit the result:"; \
|
||||
echo "$${diff}"; \
|
||||
exit 1; \
|
||||
fi;
|
||||
|
||||
.PHONY: test
|
||||
test:
|
||||
$(GO) test $(PACKAGES)
|
||||
|
||||
.PHONY: unit-test-coverage
|
||||
unit-test-coverage:
|
||||
$(GO) test -cover -coverprofile coverage.out $(PACKAGES) && echo "\n==>\033[32m Ok\033[m\n" || exit 1
|
||||
|
||||
.PHONY: tidy
|
||||
tidy:
|
||||
$(GO) mod tidy
|
||||
|
||||
install-lint-tools:
|
||||
@hash revive > /dev/null 2>&1; if [ $$? -ne 0 ]; then \
|
||||
$(GO) install github.com/mgechev/revive@v1.3.2; \
|
||||
fi
|
||||
@hash misspell > /dev/null 2>&1; if [ $$? -ne 0 ]; then \
|
||||
$(GO) install github.com/client9/misspell/cmd/misspell@latest; \
|
||||
fi
|
||||
148
cmd.go
148
cmd.go
@@ -24,58 +24,56 @@ type Command interface {
|
||||
Execute(*Session, string)
|
||||
}
|
||||
|
||||
var (
|
||||
defaultCommands = map[string]Command{
|
||||
"ADAT": commandAdat{},
|
||||
"ALLO": commandAllo{},
|
||||
"APPE": commandAppe{},
|
||||
"AUTH": commandAuth{},
|
||||
"CDUP": commandCdup{},
|
||||
"CWD": commandCwd{},
|
||||
"CCC": commandCcc{},
|
||||
"CONF": commandConf{},
|
||||
"CLNT": commandCLNT{},
|
||||
"DELE": commandDele{},
|
||||
"ENC": commandEnc{},
|
||||
"EPRT": commandEprt{},
|
||||
"EPSV": commandEpsv{},
|
||||
"FEAT": commandFeat{},
|
||||
"LIST": commandList{},
|
||||
"LPRT": commandLprt{},
|
||||
"NLST": commandNlst{},
|
||||
"MDTM": commandMdtm{},
|
||||
"MIC": commandMic{},
|
||||
"MLSD": commandMLSD{},
|
||||
"MKD": commandMkd{},
|
||||
"MODE": commandMode{},
|
||||
"NOOP": commandNoop{},
|
||||
"OPTS": commandOpts{},
|
||||
"PASS": commandPass{},
|
||||
"PASV": commandPasv{},
|
||||
"PBSZ": commandPbsz{},
|
||||
"PORT": commandPort{},
|
||||
"PROT": commandProt{},
|
||||
"PWD": commandPwd{},
|
||||
"QUIT": commandQuit{},
|
||||
"RETR": commandRetr{},
|
||||
"REST": commandRest{},
|
||||
"RNFR": commandRnfr{},
|
||||
"RNTO": commandRnto{},
|
||||
"RMD": commandRmd{},
|
||||
"SIZE": commandSize{},
|
||||
"STAT": commandStat{},
|
||||
"STOR": commandStor{},
|
||||
"STRU": commandStru{},
|
||||
"SYST": commandSyst{},
|
||||
"TYPE": commandType{},
|
||||
"USER": commandUser{},
|
||||
"XCUP": commandCdup{},
|
||||
"XCWD": commandCwd{},
|
||||
"XMKD": commandMkd{},
|
||||
"XPWD": commandPwd{},
|
||||
"XRMD": commandXRmd{},
|
||||
}
|
||||
)
|
||||
var defaultCommands = map[string]Command{
|
||||
"ADAT": commandAdat{},
|
||||
"ALLO": commandAllo{},
|
||||
"APPE": commandAppe{},
|
||||
"AUTH": commandAuth{},
|
||||
"CDUP": commandCdup{},
|
||||
"CWD": commandCwd{},
|
||||
"CCC": commandCcc{},
|
||||
"CONF": commandConf{},
|
||||
"CLNT": commandCLNT{},
|
||||
"DELE": commandDele{},
|
||||
"ENC": commandEnc{},
|
||||
"EPRT": commandEprt{},
|
||||
"EPSV": commandEpsv{},
|
||||
"FEAT": commandFeat{},
|
||||
"LIST": commandList{},
|
||||
"LPRT": commandLprt{},
|
||||
"NLST": commandNlst{},
|
||||
"MDTM": commandMdtm{},
|
||||
"MIC": commandMic{},
|
||||
"MLSD": commandMLSD{},
|
||||
"MKD": commandMkd{},
|
||||
"MODE": commandMode{},
|
||||
"NOOP": commandNoop{},
|
||||
"OPTS": commandOpts{},
|
||||
"PASS": commandPass{},
|
||||
"PASV": commandPasv{},
|
||||
"PBSZ": commandPbsz{},
|
||||
"PORT": commandPort{},
|
||||
"PROT": commandProt{},
|
||||
"PWD": commandPwd{},
|
||||
"QUIT": commandQuit{},
|
||||
"RETR": commandRetr{},
|
||||
"REST": commandRest{},
|
||||
"RNFR": commandRnfr{},
|
||||
"RNTO": commandRnto{},
|
||||
"RMD": commandRmd{},
|
||||
"SIZE": commandSize{},
|
||||
"STAT": commandStat{},
|
||||
"STOR": commandStor{},
|
||||
"STRU": commandStru{},
|
||||
"SYST": commandSyst{},
|
||||
"TYPE": commandType{},
|
||||
"USER": commandUser{},
|
||||
"XCUP": commandCdup{},
|
||||
"XCWD": commandCwd{},
|
||||
"XMKD": commandMkd{},
|
||||
"XPWD": commandPwd{},
|
||||
"XRMD": commandXRmd{},
|
||||
}
|
||||
|
||||
// DefaultCommands returns the default commands
|
||||
func DefaultCommands() map[string]Command {
|
||||
@@ -131,7 +129,7 @@ func (cmd commandAppe) Execute(sess *Session, param string) {
|
||||
sess.lastFilePos = -1
|
||||
}()
|
||||
|
||||
var ctx = Context{
|
||||
ctx := Context{
|
||||
Sess: sess,
|
||||
Cmd: "APPE",
|
||||
Param: param,
|
||||
@@ -257,7 +255,7 @@ func (cmd commandCwd) RequireAuth() bool {
|
||||
|
||||
func (cmd commandCwd) Execute(sess *Session, param string) {
|
||||
path := sess.buildPath(param)
|
||||
var ctx = Context{
|
||||
ctx := Context{
|
||||
Sess: sess,
|
||||
Cmd: "CWD",
|
||||
Param: param,
|
||||
@@ -303,7 +301,7 @@ func (cmd commandDele) RequireAuth() bool {
|
||||
|
||||
func (cmd commandDele) Execute(sess *Session, param string) {
|
||||
path := sess.buildPath(param)
|
||||
var ctx = Context{
|
||||
ctx := Context{
|
||||
Sess: sess,
|
||||
Cmd: "DELE",
|
||||
Param: param,
|
||||
@@ -510,7 +508,7 @@ func convertFileInfo(sess *Session, f os.FileInfo, p string) (FileInfo, error) {
|
||||
}
|
||||
|
||||
func list(sess *Session, cmd, p, param string) ([]FileInfo, error) {
|
||||
var ctx = &Context{
|
||||
ctx := &Context{
|
||||
Sess: sess,
|
||||
Cmd: cmd,
|
||||
Param: param,
|
||||
@@ -574,7 +572,7 @@ func parseListParam(param string) (path string) {
|
||||
}
|
||||
i = strings.LastIndex(param, " "+field) + len(field) + 1
|
||||
}
|
||||
path = strings.TrimLeft(param[i:], " ") //Get all the path even with space inside
|
||||
path = strings.TrimLeft(param[i:], " ") // Get all the path even with space inside
|
||||
}
|
||||
return path
|
||||
}
|
||||
@@ -596,7 +594,7 @@ func (cmd commandNlst) RequireAuth() bool {
|
||||
}
|
||||
|
||||
func (cmd commandNlst) Execute(sess *Session, param string) {
|
||||
var ctx = &Context{
|
||||
ctx := &Context{
|
||||
Sess: sess,
|
||||
Cmd: "NLST",
|
||||
Param: param,
|
||||
@@ -647,7 +645,7 @@ func (cmd commandNlst) Execute(sess *Session, param string) {
|
||||
}
|
||||
|
||||
// commandMdtm responds to the MDTM FTP command. It allows the client to
|
||||
// retreive the last modified time of a file.
|
||||
// retrieve the last modified time of a file.
|
||||
type commandMdtm struct{}
|
||||
|
||||
func (cmd commandMdtm) IsExtend() bool {
|
||||
@@ -695,7 +693,7 @@ func (cmd commandMkd) RequireAuth() bool {
|
||||
|
||||
func (cmd commandMkd) Execute(sess *Session, param string) {
|
||||
path := sess.buildPath(param)
|
||||
var ctx = Context{
|
||||
ctx := Context{
|
||||
Sess: sess,
|
||||
Cmd: "MKD",
|
||||
Param: param,
|
||||
@@ -783,7 +781,7 @@ func (cmd commandPass) Execute(sess *Session, param string) {
|
||||
if driverAuth, found := sess.server.Driver.(Auth); found {
|
||||
auth = driverAuth
|
||||
}
|
||||
var ctx = Context{
|
||||
ctx := Context{
|
||||
Sess: sess,
|
||||
Cmd: "PASS",
|
||||
Param: param,
|
||||
@@ -946,14 +944,14 @@ func (cmd commandRetr) Execute(sess *Session, param string) {
|
||||
defer func() {
|
||||
sess.lastFilePos = -1
|
||||
}()
|
||||
var ctx = Context{
|
||||
ctx := Context{
|
||||
Sess: sess,
|
||||
Cmd: "RETR",
|
||||
Param: param,
|
||||
Data: make(map[string]interface{}),
|
||||
}
|
||||
sess.server.notifiers.BeforeDownloadFile(&ctx, path)
|
||||
var readPos = sess.lastFilePos
|
||||
readPos := sess.lastFilePos
|
||||
if readPos < 0 {
|
||||
readPos = 0
|
||||
}
|
||||
@@ -1106,7 +1104,7 @@ func (cmd commandXRmd) Execute(sess *Session, param string) {
|
||||
|
||||
func executeRmd(cmd string, sess *Session, param string) {
|
||||
p := sess.buildPath(param)
|
||||
var ctx = Context{
|
||||
ctx := Context{
|
||||
Sess: sess,
|
||||
Cmd: cmd,
|
||||
Param: param,
|
||||
@@ -1117,7 +1115,7 @@ func executeRmd(cmd string, sess *Session, param string) {
|
||||
return
|
||||
}
|
||||
|
||||
var needChangeCurDir = strings.HasPrefix(param, sess.curDir)
|
||||
needChangeCurDir := strings.HasPrefix(param, sess.curDir)
|
||||
|
||||
sess.server.notifiers.BeforeDeleteDir(&ctx, p)
|
||||
err := sess.server.Driver.DeleteDir(&ctx, p)
|
||||
@@ -1247,7 +1245,7 @@ func (cmd commandMLSD) RequireAuth() bool {
|
||||
func toMLSDFormat(files []FileInfo) []byte {
|
||||
var buf bytes.Buffer
|
||||
for _, file := range files {
|
||||
var fileType = "file"
|
||||
fileType := "file"
|
||||
if file.IsDir() {
|
||||
fileType = "dir"
|
||||
}
|
||||
@@ -1409,7 +1407,7 @@ func (cmd commandStat) Execute(sess *Session, param string) {
|
||||
return
|
||||
}
|
||||
|
||||
var ctx = Context{
|
||||
ctx := Context{
|
||||
Sess: sess,
|
||||
Cmd: "STAT",
|
||||
Param: param,
|
||||
@@ -1479,7 +1477,7 @@ func (cmd commandStor) Execute(sess *Session, param string) {
|
||||
sess.lastFilePos = -1
|
||||
}()
|
||||
|
||||
var ctx = Context{
|
||||
ctx := Context{
|
||||
Sess: sess,
|
||||
Cmd: "STOR",
|
||||
Param: param,
|
||||
@@ -1548,14 +1546,14 @@ func (cmd commandSyst) Execute(sess *Session, param string) {
|
||||
|
||||
// commandType responds to the TYPE FTP command.
|
||||
//
|
||||
// like the MODE and STRU commands, TYPE dates back to a time when the FTP
|
||||
// protocol was more aware of the content of the files it was transferring, and
|
||||
// would sometimes be expected to translate things like EOL markers on the fly.
|
||||
// like the MODE and STRU commands, TYPE dates back to a time when the FTP
|
||||
// protocol was more aware of the content of the files it was transferring, and
|
||||
// would sometimes be expected to translate things like EOL markers on the fly.
|
||||
//
|
||||
// Valid options were A(SCII), I(mage), E(BCDIC) or LN (for local type). Since
|
||||
// we plan to just accept bytes from the client unchanged, I think Image mode is
|
||||
// adequate. The RFC requires we accept ASCII mode however, so accept it, but
|
||||
// ignore it.
|
||||
// Valid options were A(SCII), I(mage), E(BCDIC) or LN (for local type). Since
|
||||
// we plan to just accept bytes from the client unchanged, I think Image mode is
|
||||
// adequate. The RFC requires we accept ASCII mode however, so accept it, but
|
||||
// ignore it.
|
||||
type commandType struct{}
|
||||
|
||||
func (cmd commandType) IsExtend() bool {
|
||||
|
||||
@@ -40,12 +40,12 @@ type DataSocket interface {
|
||||
}
|
||||
|
||||
type activeSocket struct {
|
||||
conn *net.TCPConn
|
||||
conn *net.TCPConn
|
||||
reader io.Reader
|
||||
writer io.Writer
|
||||
sess *Session
|
||||
host string
|
||||
port int
|
||||
sess *Session
|
||||
host string
|
||||
port int
|
||||
}
|
||||
|
||||
func newActiveSocket(sess *Session, remote string, port int) (DataSocket, error) {
|
||||
@@ -105,8 +105,8 @@ func (socket *activeSocket) Close() error {
|
||||
type passiveSocket struct {
|
||||
sess *Session
|
||||
conn net.Conn
|
||||
reader io.Reader
|
||||
writer io.Writer
|
||||
reader io.Reader
|
||||
writer io.Writer
|
||||
port int
|
||||
host string
|
||||
ingress chan []byte
|
||||
|
||||
10
go.mod
10
go.mod
@@ -1,13 +1,21 @@
|
||||
module goftp.io/server/v2
|
||||
|
||||
go 1.12
|
||||
go 1.20
|
||||
|
||||
require (
|
||||
github.com/jlaffaye/ftp v0.0.0-20190624084859-c1312a7102bf
|
||||
github.com/minio/minio-go/v6 v6.0.46
|
||||
github.com/stretchr/testify v1.3.0
|
||||
)
|
||||
|
||||
require (
|
||||
github.com/davecgh/go-spew v1.1.1 // indirect
|
||||
github.com/minio/sha256-simd v0.1.1 // indirect
|
||||
github.com/mitchellh/go-homedir v1.1.0 // indirect
|
||||
github.com/pmezard/go-difflib v1.0.0 // indirect
|
||||
golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4 // indirect
|
||||
golang.org/x/net v0.0.0-20190724013045-ca1201d0de80 // indirect
|
||||
golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e // indirect
|
||||
golang.org/x/text v0.3.2 // indirect
|
||||
gopkg.in/ini.v1 v1.42.0 // indirect
|
||||
)
|
||||
|
||||
5
go.sum
5
go.sum
@@ -1,4 +1,3 @@
|
||||
github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8=
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
@@ -29,23 +28,19 @@ github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXf
|
||||
github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q=
|
||||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.0.0-20190513172903-22d7a77e9e5f h1:R423Cnkcp5JABoeemiGEPlt9tHXFfw5kvc0yqlxRPWo=
|
||||
golang.org/x/crypto v0.0.0-20190513172903-22d7a77e9e5f/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4 h1:HuIa8hRrWRSrqYzx1qI49NNxhdi2PrY7gxVSq1JjLDc=
|
||||
golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190522155817-f3200d17e092 h1:4QSRKanuywn15aTZvI/mIDEgPQpswuFndXpOj3rKEco=
|
||||
golang.org/x/net v0.0.0-20190522155817-f3200d17e092/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
|
||||
golang.org/x/net v0.0.0-20190724013045-ca1201d0de80 h1:Ao/3l156eZf2AW5wK8a7/smtodRU+gha3+BeqJ69lRk=
|
||||
golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190422165155-953cdadca894 h1:Cz4ceDQGXuKRnVBDTS23GTn/pU5OE2C0WrNTOYK1Uuc=
|
||||
golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e h1:D5TXcfTk7xF7hvieo4QErS3qqCB4teTffacDWr7CI+0=
|
||||
golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs=
|
||||
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
||||
|
||||
@@ -34,7 +34,7 @@ func (formatter listFormatter) Detailed() []byte {
|
||||
fmt.Fprint(&buf, lpad(strconv.FormatInt(file.Size(), 10), 12))
|
||||
if file.ModTime().Before(time.Now().AddDate(-1, 0, 0)) {
|
||||
fmt.Fprint(&buf, file.ModTime().Format(" Jan _2 2006 "))
|
||||
} else{
|
||||
} else {
|
||||
fmt.Fprint(&buf, file.ModTime().Format(" Jan _2 15:04 "))
|
||||
}
|
||||
fmt.Fprintf(&buf, "%s\r\n", file.Name())
|
||||
|
||||
21
server.go
21
server.go
@@ -161,16 +161,15 @@ func optsWithDefaults(opts *Options) *Options {
|
||||
// via an instance of Options. Calling this function in your code will
|
||||
// probably look something like this:
|
||||
//
|
||||
// driver := &MyDriver{}
|
||||
// opts := &server.Options{
|
||||
// Driver: driver,
|
||||
// Auth: auth,
|
||||
// Port: 2000,
|
||||
// Perm: perm,
|
||||
// Hostname: "127.0.0.1",
|
||||
// }
|
||||
// server, err := server.NewServer(opts)
|
||||
//
|
||||
// driver := &MyDriver{}
|
||||
// opts := &server.Options{
|
||||
// Driver: driver,
|
||||
// Auth: auth,
|
||||
// Port: 2000,
|
||||
// Perm: perm,
|
||||
// Hostname: "127.0.0.1",
|
||||
// }
|
||||
// server, err := server.NewServer(opts)
|
||||
func NewServer(opts *Options) (*Server, error) {
|
||||
opts = optsWithDefaults(opts)
|
||||
if opts.Perm == nil {
|
||||
@@ -250,7 +249,6 @@ func simpleTLSConfig(certFile, keyFile string) (*tls.Config, error) {
|
||||
// If the server fails to start for any reason, an error will be returned. Common
|
||||
// errors are trying to bind to a privileged port or something else is already
|
||||
// listening on the same port.
|
||||
//
|
||||
func (server *Server) ListenAndServe() error {
|
||||
var listener net.Listener
|
||||
var err error
|
||||
@@ -280,7 +278,6 @@ func (server *Server) ListenAndServe() error {
|
||||
|
||||
// Serve accepts connections on a given net.Listener and handles each
|
||||
// request in a new goroutine.
|
||||
//
|
||||
func (server *Server) Serve(l net.Listener) error {
|
||||
server.listener = l
|
||||
server.ctx, server.cancel = context.WithCancel(context.Background())
|
||||
|
||||
22
session.go
22
session.go
@@ -228,6 +228,7 @@ func (sess *Session) parseLine(line string) (string, string) {
|
||||
return params[0], params[1]
|
||||
}
|
||||
|
||||
// WriteMessage sends a standard FTP response back to the client.
|
||||
func (sess *Session) WriteMessage(code int, message string) {
|
||||
sess.writeMessage(code, message)
|
||||
}
|
||||
@@ -248,6 +249,7 @@ func (sess *Session) writeMessageMultiline(code int, message string) {
|
||||
sess.controlWriter.Flush()
|
||||
}
|
||||
|
||||
// BuildPath generates a safe absolute path for the given filename.
|
||||
func (sess *Session) BuildPath(filename string) string {
|
||||
return sess.buildPath(filename)
|
||||
}
|
||||
@@ -255,16 +257,16 @@ func (sess *Session) BuildPath(filename string) string {
|
||||
// buildPath takes a client supplied path or filename and generates a safe
|
||||
// absolute path within their account sandbox.
|
||||
//
|
||||
// buildpath("/")
|
||||
// => "/"
|
||||
// buildpath("one.txt")
|
||||
// => "/one.txt"
|
||||
// buildpath("/files/two.txt")
|
||||
// => "/files/two.txt"
|
||||
// buildpath("files/two.txt")
|
||||
// => "/files/two.txt"
|
||||
// buildpath("/../../../../etc/passwd")
|
||||
// => "/etc/passwd"
|
||||
// buildpath("/")
|
||||
// => "/"
|
||||
// buildpath("one.txt")
|
||||
// => "/one.txt"
|
||||
// buildpath("/files/two.txt")
|
||||
// => "/files/two.txt"
|
||||
// buildpath("files/two.txt")
|
||||
// => "/files/two.txt"
|
||||
// buildpath("/../../../../etc/passwd")
|
||||
// => "/etc/passwd"
|
||||
//
|
||||
// The driver implementation is responsible for deciding how to treat this path.
|
||||
// Obviously they MUST NOT just read the path off disk. The probably want to
|
||||
|
||||
Reference in New Issue
Block a user