mirror of
https://github.com/drakkan/sftpgo.git
synced 2025-12-07 14:50:55 +03:00
transfer logs: add FTP mode
This commit is contained in:
@@ -30,6 +30,7 @@ type BaseTransfer struct { //nolint:maligned
|
|||||||
fsPath string
|
fsPath string
|
||||||
effectiveFsPath string
|
effectiveFsPath string
|
||||||
requestPath string
|
requestPath string
|
||||||
|
ftpMode string
|
||||||
start time.Time
|
start time.Time
|
||||||
MaxWriteSize int64
|
MaxWriteSize int64
|
||||||
MinWriteOffset int64
|
MinWriteOffset int64
|
||||||
@@ -68,6 +69,11 @@ func NewBaseTransfer(file vfs.File, conn *BaseConnection, cancelFn func(), fsPat
|
|||||||
return t
|
return t
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SetFtpMode sets the FTP mode for the current transfer
|
||||||
|
func (t *BaseTransfer) SetFtpMode(mode string) {
|
||||||
|
t.ftpMode = mode
|
||||||
|
}
|
||||||
|
|
||||||
// GetID returns the transfer ID
|
// GetID returns the transfer ID
|
||||||
func (t *BaseTransfer) GetID() uint64 {
|
func (t *BaseTransfer) GetID() uint64 {
|
||||||
return t.ID
|
return t.ID
|
||||||
@@ -236,7 +242,7 @@ func (t *BaseTransfer) Close() error {
|
|||||||
elapsed := time.Since(t.start).Nanoseconds() / 1000000
|
elapsed := time.Since(t.start).Nanoseconds() / 1000000
|
||||||
if t.transferType == TransferDownload {
|
if t.transferType == TransferDownload {
|
||||||
logger.TransferLog(downloadLogSender, t.fsPath, elapsed, atomic.LoadInt64(&t.BytesSent), t.Connection.User.Username,
|
logger.TransferLog(downloadLogSender, t.fsPath, elapsed, atomic.LoadInt64(&t.BytesSent), t.Connection.User.Username,
|
||||||
t.Connection.ID, t.Connection.protocol, t.Connection.localAddr, t.Connection.remoteAddr)
|
t.Connection.ID, t.Connection.protocol, t.Connection.localAddr, t.Connection.remoteAddr, t.ftpMode)
|
||||||
ExecuteActionNotification(&t.Connection.User, operationDownload, t.fsPath, t.requestPath, "", "", t.Connection.protocol,
|
ExecuteActionNotification(&t.Connection.User, operationDownload, t.fsPath, t.requestPath, "", "", t.Connection.protocol,
|
||||||
atomic.LoadInt64(&t.BytesSent), t.ErrTransfer)
|
atomic.LoadInt64(&t.BytesSent), t.ErrTransfer)
|
||||||
} else {
|
} else {
|
||||||
@@ -247,7 +253,7 @@ func (t *BaseTransfer) Close() error {
|
|||||||
t.Connection.Log(logger.LevelDebug, "uploaded file size %v", fileSize)
|
t.Connection.Log(logger.LevelDebug, "uploaded file size %v", fileSize)
|
||||||
t.updateQuota(numFiles, fileSize)
|
t.updateQuota(numFiles, fileSize)
|
||||||
logger.TransferLog(uploadLogSender, t.fsPath, elapsed, atomic.LoadInt64(&t.BytesReceived), t.Connection.User.Username,
|
logger.TransferLog(uploadLogSender, t.fsPath, elapsed, atomic.LoadInt64(&t.BytesReceived), t.Connection.User.Username,
|
||||||
t.Connection.ID, t.Connection.protocol, t.Connection.localAddr, t.Connection.remoteAddr)
|
t.Connection.ID, t.Connection.protocol, t.Connection.localAddr, t.Connection.remoteAddr, t.ftpMode)
|
||||||
ExecuteActionNotification(&t.Connection.User, operationUpload, t.fsPath, t.requestPath, "", "", t.Connection.protocol, fileSize,
|
ExecuteActionNotification(&t.Connection.User, operationUpload, t.fsPath, t.requestPath, "", "", t.Connection.protocol, fileSize,
|
||||||
t.ErrTransfer)
|
t.ErrTransfer)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -284,3 +284,16 @@ func TestRemovePartialCryptoFile(t *testing.T) {
|
|||||||
assert.Equal(t, int64(9), size)
|
assert.Equal(t, int64(9), size)
|
||||||
assert.NoFileExists(t, testFile)
|
assert.NoFileExists(t, testFile)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestFTPMode(t *testing.T) {
|
||||||
|
conn := NewBaseConnection("", ProtocolFTP, "", "", dataprovider.User{})
|
||||||
|
transfer := BaseTransfer{
|
||||||
|
Connection: conn,
|
||||||
|
transferType: TransferUpload,
|
||||||
|
BytesReceived: 123,
|
||||||
|
Fs: vfs.NewOsFs("", os.TempDir(), ""),
|
||||||
|
}
|
||||||
|
assert.Empty(t, transfer.ftpMode)
|
||||||
|
transfer.SetFtpMode("active")
|
||||||
|
assert.Equal(t, "active", transfer.ftpMode)
|
||||||
|
}
|
||||||
|
|||||||
@@ -20,7 +20,8 @@ The logs can be divided into the following categories:
|
|||||||
- `username`, string
|
- `username`, string
|
||||||
- `file_path` string
|
- `file_path` string
|
||||||
- `connection_id` string. Unique connection identifier
|
- `connection_id` string. Unique connection identifier
|
||||||
- `protocol` string. `SFTP` or `SCP`
|
- `protocol` string. `SFTP`, `SCP`, `SSH`, `FTP`, `HTTP`, `DAV`
|
||||||
|
- `ftp_mode`, string. `active` or `passive`. Included only for `FTP` protocol
|
||||||
- **"command logs"**, SFTP/SCP command logs:
|
- **"command logs"**, SFTP/SCP command logs:
|
||||||
- `sender` string. `Rename`, `Rmdir`, `Mkdir`, `Symlink`, `Remove`, `Chmod`, `Chown`, `Chtimes`, `Truncate`, `SSHCommand`
|
- `sender` string. `Rename`, `Rmdir`, `Mkdir`, `Symlink`, `Remove`, `Chmod`, `Chown`, `Chtimes`, `Truncate`, `SSHCommand`
|
||||||
- `level` string
|
- `level` string
|
||||||
|
|||||||
@@ -30,6 +30,19 @@ type Connection struct {
|
|||||||
clientContext ftpserver.ClientContext
|
clientContext ftpserver.ClientContext
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *Connection) getFTPMode() string {
|
||||||
|
if c.clientContext == nil {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
switch c.clientContext.GetLastDataChannel() {
|
||||||
|
case ftpserver.DataChannelActive:
|
||||||
|
return "active"
|
||||||
|
case ftpserver.DataChannelPassive:
|
||||||
|
return "passive"
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
// GetClientVersion returns the connected client's version.
|
// GetClientVersion returns the connected client's version.
|
||||||
// It returns "Unknown" if the client does not advertise its
|
// It returns "Unknown" if the client does not advertise its
|
||||||
// version
|
// version
|
||||||
@@ -325,6 +338,7 @@ func (c *Connection) downloadFile(fs vfs.Fs, fsPath, ftpPath string, offset int6
|
|||||||
|
|
||||||
baseTransfer := common.NewBaseTransfer(file, c.BaseConnection, cancelFn, fsPath, fsPath, ftpPath, common.TransferDownload,
|
baseTransfer := common.NewBaseTransfer(file, c.BaseConnection, cancelFn, fsPath, fsPath, ftpPath, common.TransferDownload,
|
||||||
0, 0, 0, false, fs)
|
0, 0, 0, false, fs)
|
||||||
|
baseTransfer.SetFtpMode(c.getFTPMode())
|
||||||
t := newTransfer(baseTransfer, nil, r, offset)
|
t := newTransfer(baseTransfer, nil, r, offset)
|
||||||
|
|
||||||
return t, nil
|
return t, nil
|
||||||
@@ -390,6 +404,7 @@ func (c *Connection) handleFTPUploadToNewFile(fs vfs.Fs, resolvedPath, filePath,
|
|||||||
|
|
||||||
baseTransfer := common.NewBaseTransfer(file, c.BaseConnection, cancelFn, resolvedPath, filePath, requestPath,
|
baseTransfer := common.NewBaseTransfer(file, c.BaseConnection, cancelFn, resolvedPath, filePath, requestPath,
|
||||||
common.TransferUpload, 0, 0, maxWriteSize, true, fs)
|
common.TransferUpload, 0, 0, maxWriteSize, true, fs)
|
||||||
|
baseTransfer.SetFtpMode(c.getFTPMode())
|
||||||
t := newTransfer(baseTransfer, w, nil, 0)
|
t := newTransfer(baseTransfer, w, nil, 0)
|
||||||
|
|
||||||
return t, nil
|
return t, nil
|
||||||
@@ -466,6 +481,7 @@ func (c *Connection) handleFTPUploadToExistingFile(fs vfs.Fs, flags int, resolve
|
|||||||
|
|
||||||
baseTransfer := common.NewBaseTransfer(file, c.BaseConnection, cancelFn, resolvedPath, filePath, requestPath,
|
baseTransfer := common.NewBaseTransfer(file, c.BaseConnection, cancelFn, resolvedPath, filePath, requestPath,
|
||||||
common.TransferUpload, minWriteOffset, initialSize, maxWriteSize, false, fs)
|
common.TransferUpload, minWriteOffset, initialSize, maxWriteSize, false, fs)
|
||||||
|
baseTransfer.SetFtpMode(c.getFTPMode())
|
||||||
t := newTransfer(baseTransfer, w, nil, 0)
|
t := newTransfer(baseTransfer, w, nil, 0)
|
||||||
|
|
||||||
return t, nil
|
return t, nil
|
||||||
|
|||||||
@@ -253,6 +253,7 @@ xr5cb9VBRBtB9aOKVfuRhpatAfS2Pzm2Htae9lFn7slGPUmu2hkjDw==
|
|||||||
)
|
)
|
||||||
|
|
||||||
type mockFTPClientContext struct {
|
type mockFTPClientContext struct {
|
||||||
|
lastDataChannel ftpserver.DataChannel
|
||||||
}
|
}
|
||||||
|
|
||||||
func (cc mockFTPClientContext) Path() string {
|
func (cc mockFTPClientContext) Path() string {
|
||||||
@@ -298,7 +299,7 @@ func (cc mockFTPClientContext) GetLastCommand() string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (cc mockFTPClientContext) GetLastDataChannel() ftpserver.DataChannel {
|
func (cc mockFTPClientContext) GetLastDataChannel() ftpserver.DataChannel {
|
||||||
return ftpserver.DataChannelPassive
|
return cc.lastDataChannel
|
||||||
}
|
}
|
||||||
|
|
||||||
// MockOsFs mockable OsFs
|
// MockOsFs mockable OsFs
|
||||||
@@ -559,6 +560,19 @@ func TestUserInvalidParams(t *testing.T) {
|
|||||||
assert.Error(t, err)
|
assert.Error(t, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestFTPMode(t *testing.T) {
|
||||||
|
connection := &Connection{
|
||||||
|
BaseConnection: common.NewBaseConnection("", common.ProtocolFTP, "", "", dataprovider.User{}),
|
||||||
|
}
|
||||||
|
assert.Empty(t, connection.getFTPMode())
|
||||||
|
connection.clientContext = mockFTPClientContext{lastDataChannel: ftpserver.DataChannelActive}
|
||||||
|
assert.Equal(t, "active", connection.getFTPMode())
|
||||||
|
connection.clientContext = mockFTPClientContext{lastDataChannel: ftpserver.DataChannelPassive}
|
||||||
|
assert.Equal(t, "passive", connection.getFTPMode())
|
||||||
|
connection.clientContext = mockFTPClientContext{lastDataChannel: 0}
|
||||||
|
assert.Empty(t, connection.getFTPMode())
|
||||||
|
}
|
||||||
|
|
||||||
func TestClientVersion(t *testing.T) {
|
func TestClientVersion(t *testing.T) {
|
||||||
mockCC := mockFTPClientContext{}
|
mockCC := mockFTPClientContext{}
|
||||||
connID := fmt.Sprintf("2_%v", mockCC.ID())
|
connID := fmt.Sprintf("2_%v", mockCC.ID())
|
||||||
|
|||||||
@@ -259,8 +259,10 @@ func ErrorToConsole(format string, v ...interface{}) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// TransferLog logs uploads or downloads
|
// TransferLog logs uploads or downloads
|
||||||
func TransferLog(operation, path string, elapsed int64, size int64, user, connectionID, protocol, localAddr, remoteAddr string) {
|
func TransferLog(operation, path string, elapsed int64, size int64, user, connectionID, protocol, localAddr,
|
||||||
logger.Info().
|
remoteAddr, ftpMode string,
|
||||||
|
) {
|
||||||
|
ev := logger.Info().
|
||||||
Timestamp().
|
Timestamp().
|
||||||
Str("sender", operation).
|
Str("sender", operation).
|
||||||
Str("local_addr", localAddr).
|
Str("local_addr", localAddr).
|
||||||
@@ -270,8 +272,11 @@ func TransferLog(operation, path string, elapsed int64, size int64, user, connec
|
|||||||
Str("username", user).
|
Str("username", user).
|
||||||
Str("file_path", path).
|
Str("file_path", path).
|
||||||
Str("connection_id", connectionID).
|
Str("connection_id", connectionID).
|
||||||
Str("protocol", protocol).
|
Str("protocol", protocol)
|
||||||
Send()
|
if ftpMode != "" {
|
||||||
|
ev.Str("ftp_mode", ftpMode)
|
||||||
|
}
|
||||||
|
ev.Send()
|
||||||
}
|
}
|
||||||
|
|
||||||
// CommandLog logs an SFTP/SCP/SSH command
|
// CommandLog logs an SFTP/SCP/SSH command
|
||||||
|
|||||||
Reference in New Issue
Block a user