mirror of
https://github.com/drakkan/sftpgo.git
synced 2024-11-22 07:30:25 +00:00
add session id to notifier plugins/hook
This commit is contained in:
parent
dc1cc88a46
commit
a7c0b07a2a
18 changed files with 120 additions and 91 deletions
|
@ -51,10 +51,10 @@ func InitializeActionHandler(handler ActionHandler) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// ExecutePreAction executes a pre-* action and returns the result
|
// ExecutePreAction executes a pre-* action and returns the result
|
||||||
func ExecutePreAction(user *dataprovider.User, operation, filePath, virtualPath, protocol, ip string, fileSize int64,
|
func ExecutePreAction(conn *BaseConnection, operation, filePath, virtualPath string, fileSize int64, openFlags int) error {
|
||||||
openFlags int,
|
remoteIP := conn.GetRemoteIP()
|
||||||
) error {
|
plugin.Handler.NotifyFsEvent(time.Now().UnixNano(), operation, conn.User.Username, filePath, "", "", conn.protocol,
|
||||||
plugin.Handler.NotifyFsEvent(time.Now().UnixNano(), operation, user.Username, filePath, "", "", protocol, ip, virtualPath, "", fileSize, nil)
|
remoteIP, virtualPath, "", conn.ID, fileSize, nil)
|
||||||
if !util.IsStringInSlice(operation, Config.Actions.ExecuteOn) {
|
if !util.IsStringInSlice(operation, Config.Actions.ExecuteOn) {
|
||||||
// for pre-delete we execute the internal handling on error, so we must return errUnconfiguredAction.
|
// for pre-delete we execute the internal handling on error, so we must return errUnconfiguredAction.
|
||||||
// Other pre action will deny the operation on error so if we have no configuration we must return
|
// Other pre action will deny the operation on error so if we have no configuration we must return
|
||||||
|
@ -64,19 +64,20 @@ func ExecutePreAction(user *dataprovider.User, operation, filePath, virtualPath,
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
notification := newActionNotification(user, operation, filePath, virtualPath, "", "", "", protocol, ip, fileSize,
|
notification := newActionNotification(&conn.User, operation, filePath, virtualPath, "", "", "",
|
||||||
openFlags, nil)
|
conn.protocol, remoteIP, conn.ID, fileSize, openFlags, nil)
|
||||||
return actionHandler.Handle(notification)
|
return actionHandler.Handle(notification)
|
||||||
}
|
}
|
||||||
|
|
||||||
// ExecuteActionNotification executes the defined hook, if any, for the specified action
|
// ExecuteActionNotification executes the defined hook, if any, for the specified action
|
||||||
func ExecuteActionNotification(user *dataprovider.User, operation, filePath, virtualPath, target, virtualTarget, sshCmd,
|
func ExecuteActionNotification(conn *BaseConnection, operation, filePath, virtualPath, target, virtualTarget, sshCmd string,
|
||||||
protocol, ip string, fileSize int64, err error,
|
fileSize int64, err error,
|
||||||
) {
|
) {
|
||||||
plugin.Handler.NotifyFsEvent(time.Now().UnixNano(), operation, user.Username, filePath, target, sshCmd, protocol, ip, virtualPath,
|
remoteIP := conn.GetRemoteIP()
|
||||||
virtualTarget, fileSize, err)
|
plugin.Handler.NotifyFsEvent(time.Now().UnixNano(), operation, conn.User.Username, filePath, target, sshCmd, conn.protocol,
|
||||||
notification := newActionNotification(user, operation, filePath, virtualPath, target, virtualTarget, sshCmd, protocol,
|
remoteIP, virtualPath, virtualTarget, conn.ID, fileSize, err)
|
||||||
ip, fileSize, 0, err)
|
notification := newActionNotification(&conn.User, operation, filePath, virtualPath, target, virtualTarget, sshCmd,
|
||||||
|
conn.protocol, remoteIP, conn.ID, fileSize, 0, err)
|
||||||
|
|
||||||
if util.IsStringInSlice(operation, Config.Actions.ExecuteSync) {
|
if util.IsStringInSlice(operation, Config.Actions.ExecuteSync) {
|
||||||
actionHandler.Handle(notification) //nolint:errcheck
|
actionHandler.Handle(notification) //nolint:errcheck
|
||||||
|
@ -107,13 +108,14 @@ type ActionNotification struct {
|
||||||
Status int `json:"status"`
|
Status int `json:"status"`
|
||||||
Protocol string `json:"protocol"`
|
Protocol string `json:"protocol"`
|
||||||
IP string `json:"ip"`
|
IP string `json:"ip"`
|
||||||
|
SessionID string `json:"session_id"`
|
||||||
Timestamp int64 `json:"timestamp"`
|
Timestamp int64 `json:"timestamp"`
|
||||||
OpenFlags int `json:"open_flags,omitempty"`
|
OpenFlags int `json:"open_flags,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func newActionNotification(
|
func newActionNotification(
|
||||||
user *dataprovider.User,
|
user *dataprovider.User,
|
||||||
operation, filePath, virtualPath, target, virtualTarget, sshCmd, protocol, ip string,
|
operation, filePath, virtualPath, target, virtualTarget, sshCmd, protocol, ip, sessionID string,
|
||||||
fileSize int64,
|
fileSize int64,
|
||||||
openFlags int,
|
openFlags int,
|
||||||
err error,
|
err error,
|
||||||
|
@ -159,6 +161,7 @@ func newActionNotification(
|
||||||
Status: status,
|
Status: status,
|
||||||
Protocol: protocol,
|
Protocol: protocol,
|
||||||
IP: ip,
|
IP: ip,
|
||||||
|
SessionID: sessionID,
|
||||||
OpenFlags: openFlags,
|
OpenFlags: openFlags,
|
||||||
Timestamp: time.Now().UnixNano(),
|
Timestamp: time.Now().UnixNano(),
|
||||||
}
|
}
|
||||||
|
@ -252,6 +255,7 @@ func notificationAsEnvVars(notification *ActionNotification) []string {
|
||||||
fmt.Sprintf("SFTPGO_ACTION_STATUS=%v", notification.Status),
|
fmt.Sprintf("SFTPGO_ACTION_STATUS=%v", notification.Status),
|
||||||
fmt.Sprintf("SFTPGO_ACTION_PROTOCOL=%v", notification.Protocol),
|
fmt.Sprintf("SFTPGO_ACTION_PROTOCOL=%v", notification.Protocol),
|
||||||
fmt.Sprintf("SFTPGO_ACTION_IP=%v", notification.IP),
|
fmt.Sprintf("SFTPGO_ACTION_IP=%v", notification.IP),
|
||||||
|
fmt.Sprintf("SFTPGO_ACTION_SESSION_ID=%v", notification.SessionID),
|
||||||
fmt.Sprintf("SFTPGO_ACTION_OPEN_FLAGS=%v", notification.OpenFlags),
|
fmt.Sprintf("SFTPGO_ACTION_OPEN_FLAGS=%v", notification.OpenFlags),
|
||||||
fmt.Sprintf("SFTPGO_ACTION_TIMESTAMP=%v", notification.Timestamp),
|
fmt.Sprintf("SFTPGO_ACTION_TIMESTAMP=%v", notification.Timestamp),
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,6 +9,8 @@ import (
|
||||||
"runtime"
|
"runtime"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
"github.com/lithammer/shortuuid/v3"
|
||||||
|
"github.com/rs/xid"
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
|
|
||||||
"github.com/drakkan/sftpgo/v2/dataprovider"
|
"github.com/drakkan/sftpgo/v2/dataprovider"
|
||||||
|
@ -45,38 +47,45 @@ func TestNewActionNotification(t *testing.T) {
|
||||||
Endpoint: "sftpendpoint",
|
Endpoint: "sftpendpoint",
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
a := newActionNotification(user, operationDownload, "path", "vpath", "target", "", "", ProtocolSFTP, "", 123, 0, errors.New("fake error"))
|
sessionID := xid.New().String()
|
||||||
|
a := newActionNotification(user, operationDownload, "path", "vpath", "target", "", "", ProtocolSFTP, "", sessionID,
|
||||||
|
123, 0, errors.New("fake error"))
|
||||||
assert.Equal(t, user.Username, a.Username)
|
assert.Equal(t, user.Username, a.Username)
|
||||||
assert.Equal(t, 0, len(a.Bucket))
|
assert.Equal(t, 0, len(a.Bucket))
|
||||||
assert.Equal(t, 0, len(a.Endpoint))
|
assert.Equal(t, 0, len(a.Endpoint))
|
||||||
assert.Equal(t, 2, a.Status)
|
assert.Equal(t, 2, a.Status)
|
||||||
|
|
||||||
user.FsConfig.Provider = sdk.S3FilesystemProvider
|
user.FsConfig.Provider = sdk.S3FilesystemProvider
|
||||||
a = newActionNotification(user, operationDownload, "path", "vpath", "target", "", "", ProtocolSSH, "", 123, 0, nil)
|
a = newActionNotification(user, operationDownload, "path", "vpath", "target", "", "", ProtocolSSH, "", sessionID,
|
||||||
|
123, 0, nil)
|
||||||
assert.Equal(t, "s3bucket", a.Bucket)
|
assert.Equal(t, "s3bucket", a.Bucket)
|
||||||
assert.Equal(t, "endpoint", a.Endpoint)
|
assert.Equal(t, "endpoint", a.Endpoint)
|
||||||
assert.Equal(t, 1, a.Status)
|
assert.Equal(t, 1, a.Status)
|
||||||
|
|
||||||
user.FsConfig.Provider = sdk.GCSFilesystemProvider
|
user.FsConfig.Provider = sdk.GCSFilesystemProvider
|
||||||
a = newActionNotification(user, operationDownload, "path", "vpath", "target", "", "", ProtocolSCP, "", 123, 0, ErrQuotaExceeded)
|
a = newActionNotification(user, operationDownload, "path", "vpath", "target", "", "", ProtocolSCP, "", sessionID,
|
||||||
|
123, 0, ErrQuotaExceeded)
|
||||||
assert.Equal(t, "gcsbucket", a.Bucket)
|
assert.Equal(t, "gcsbucket", a.Bucket)
|
||||||
assert.Equal(t, 0, len(a.Endpoint))
|
assert.Equal(t, 0, len(a.Endpoint))
|
||||||
assert.Equal(t, 3, a.Status)
|
assert.Equal(t, 3, a.Status)
|
||||||
|
|
||||||
user.FsConfig.Provider = sdk.AzureBlobFilesystemProvider
|
user.FsConfig.Provider = sdk.AzureBlobFilesystemProvider
|
||||||
a = newActionNotification(user, operationDownload, "path", "vpath", "target", "", "", ProtocolSCP, "", 123, 0, nil)
|
a = newActionNotification(user, operationDownload, "path", "vpath", "target", "", "", ProtocolSCP, "", sessionID,
|
||||||
|
123, 0, nil)
|
||||||
assert.Equal(t, "azcontainer", a.Bucket)
|
assert.Equal(t, "azcontainer", a.Bucket)
|
||||||
assert.Equal(t, "azendpoint", a.Endpoint)
|
assert.Equal(t, "azendpoint", a.Endpoint)
|
||||||
assert.Equal(t, 1, a.Status)
|
assert.Equal(t, 1, a.Status)
|
||||||
|
|
||||||
a = newActionNotification(user, operationDownload, "path", "vpath", "target", "", "", ProtocolSCP, "", 123, os.O_APPEND, nil)
|
a = newActionNotification(user, operationDownload, "path", "vpath", "target", "", "", ProtocolSCP, "", sessionID,
|
||||||
|
123, os.O_APPEND, nil)
|
||||||
assert.Equal(t, "azcontainer", a.Bucket)
|
assert.Equal(t, "azcontainer", a.Bucket)
|
||||||
assert.Equal(t, "azendpoint", a.Endpoint)
|
assert.Equal(t, "azendpoint", a.Endpoint)
|
||||||
assert.Equal(t, 1, a.Status)
|
assert.Equal(t, 1, a.Status)
|
||||||
assert.Equal(t, os.O_APPEND, a.OpenFlags)
|
assert.Equal(t, os.O_APPEND, a.OpenFlags)
|
||||||
|
|
||||||
user.FsConfig.Provider = sdk.SFTPFilesystemProvider
|
user.FsConfig.Provider = sdk.SFTPFilesystemProvider
|
||||||
a = newActionNotification(user, operationDownload, "path", "vpath", "target", "", "", ProtocolSFTP, "", 123, 0, nil)
|
a = newActionNotification(user, operationDownload, "path", "vpath", "target", "", "", ProtocolSFTP, "", sessionID,
|
||||||
|
123, 0, nil)
|
||||||
assert.Equal(t, "sftpendpoint", a.Endpoint)
|
assert.Equal(t, "sftpendpoint", a.Endpoint)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -92,7 +101,8 @@ func TestActionHTTP(t *testing.T) {
|
||||||
Username: "username",
|
Username: "username",
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
a := newActionNotification(user, operationDownload, "path", "vpath", "target", "", "", ProtocolSFTP, "", 123, 0, nil)
|
a := newActionNotification(user, operationDownload, "path", "vpath", "target", "", "", ProtocolSFTP, "",
|
||||||
|
xid.New().String(), 123, 0, nil)
|
||||||
err := actionHandler.Handle(a)
|
err := actionHandler.Handle(a)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
@ -127,11 +137,14 @@ func TestActionCMD(t *testing.T) {
|
||||||
Username: "username",
|
Username: "username",
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
a := newActionNotification(user, operationDownload, "path", "vpath", "target", "", "", ProtocolSFTP, "", 123, 0, nil)
|
sessionID := shortuuid.New()
|
||||||
|
a := newActionNotification(user, operationDownload, "path", "vpath", "target", "", "", ProtocolSFTP, "", sessionID,
|
||||||
|
123, 0, nil)
|
||||||
err = actionHandler.Handle(a)
|
err = actionHandler.Handle(a)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
|
|
||||||
ExecuteActionNotification(user, OperationSSHCmd, "path", "vpath", "target", "vtarget", "sha1sum", ProtocolSSH, "", 0, nil)
|
c := NewBaseConnection("id", ProtocolSFTP, "", "", *user)
|
||||||
|
ExecuteActionNotification(c, OperationSSHCmd, "path", "vpath", "target", "vtarget", "sha1sum", 0, nil)
|
||||||
|
|
||||||
Config.Actions = actionsCopy
|
Config.Actions = actionsCopy
|
||||||
}
|
}
|
||||||
|
@ -153,7 +166,8 @@ func TestWrongActions(t *testing.T) {
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
a := newActionNotification(user, operationUpload, "", "", "", "", "", ProtocolSFTP, "", 123, 0, nil)
|
a := newActionNotification(user, operationUpload, "", "", "", "", "", ProtocolSFTP, "", xid.New().String(),
|
||||||
|
123, 0, nil)
|
||||||
err := actionHandler.Handle(a)
|
err := actionHandler.Handle(a)
|
||||||
assert.Error(t, err, "action with bad command must fail")
|
assert.Error(t, err, "action with bad command must fail")
|
||||||
|
|
||||||
|
|
|
@ -264,7 +264,7 @@ func (c *BaseConnection) CreateDir(virtualPath string) error {
|
||||||
|
|
||||||
logger.CommandLog(mkdirLogSender, fsPath, "", c.User.Username, "", c.ID, c.protocol, -1, -1, "", "", "", -1,
|
logger.CommandLog(mkdirLogSender, fsPath, "", c.User.Username, "", c.ID, c.protocol, -1, -1, "", "", "", -1,
|
||||||
c.localAddr, c.remoteAddr)
|
c.localAddr, c.remoteAddr)
|
||||||
ExecuteActionNotification(&c.User, operationMkdir, fsPath, virtualPath, "", "", "", c.protocol, c.GetRemoteIP(), 0, nil)
|
ExecuteActionNotification(c, operationMkdir, fsPath, virtualPath, "", "", "", 0, nil)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -287,7 +287,7 @@ func (c *BaseConnection) RemoveFile(fs vfs.Fs, fsPath, virtualPath string, info
|
||||||
}
|
}
|
||||||
|
|
||||||
size := info.Size()
|
size := info.Size()
|
||||||
actionErr := ExecutePreAction(&c.User, operationPreDelete, fsPath, virtualPath, c.protocol, c.GetRemoteIP(), size, 0)
|
actionErr := ExecutePreAction(c, operationPreDelete, fsPath, virtualPath, size, 0)
|
||||||
if actionErr == nil {
|
if actionErr == nil {
|
||||||
c.Log(logger.LevelDebug, "remove for path %#v handled by pre-delete action", fsPath)
|
c.Log(logger.LevelDebug, "remove for path %#v handled by pre-delete action", fsPath)
|
||||||
} else {
|
} else {
|
||||||
|
@ -311,7 +311,7 @@ func (c *BaseConnection) RemoveFile(fs vfs.Fs, fsPath, virtualPath string, info
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if actionErr != nil {
|
if actionErr != nil {
|
||||||
ExecuteActionNotification(&c.User, operationDelete, fsPath, virtualPath, "", "", "", c.protocol, c.GetRemoteIP(), size, nil)
|
ExecuteActionNotification(c, operationDelete, fsPath, virtualPath, "", "", "", size, nil)
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -371,7 +371,7 @@ func (c *BaseConnection) RemoveDir(virtualPath string) error {
|
||||||
|
|
||||||
logger.CommandLog(rmdirLogSender, fsPath, "", c.User.Username, "", c.ID, c.protocol, -1, -1, "", "", "", -1,
|
logger.CommandLog(rmdirLogSender, fsPath, "", c.User.Username, "", c.ID, c.protocol, -1, -1, "", "", "", -1,
|
||||||
c.localAddr, c.remoteAddr)
|
c.localAddr, c.remoteAddr)
|
||||||
ExecuteActionNotification(&c.User, operationRmdir, fsPath, virtualPath, "", "", "", c.protocol, c.GetRemoteIP(), 0, nil)
|
ExecuteActionNotification(c, operationRmdir, fsPath, virtualPath, "", "", "", 0, nil)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -432,8 +432,8 @@ func (c *BaseConnection) Rename(virtualSourcePath, virtualTargetPath string) err
|
||||||
c.updateQuotaAfterRename(fsDst, virtualSourcePath, virtualTargetPath, fsTargetPath, initialSize) //nolint:errcheck
|
c.updateQuotaAfterRename(fsDst, virtualSourcePath, virtualTargetPath, fsTargetPath, initialSize) //nolint:errcheck
|
||||||
logger.CommandLog(renameLogSender, fsSourcePath, fsTargetPath, c.User.Username, "", c.ID, c.protocol, -1, -1,
|
logger.CommandLog(renameLogSender, fsSourcePath, fsTargetPath, c.User.Username, "", c.ID, c.protocol, -1, -1,
|
||||||
"", "", "", -1, c.localAddr, c.remoteAddr)
|
"", "", "", -1, c.localAddr, c.remoteAddr)
|
||||||
ExecuteActionNotification(&c.User, operationRename, fsSourcePath, virtualSourcePath, fsTargetPath, virtualTargetPath, "",
|
ExecuteActionNotification(c, operationRename, fsSourcePath, virtualSourcePath, fsTargetPath, virtualTargetPath,
|
||||||
c.protocol, c.GetRemoteIP(), 0, nil)
|
"", 0, nil)
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -255,8 +255,8 @@ func (t *BaseTransfer) Close() error {
|
||||||
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.ftpMode)
|
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, operationDownload, t.fsPath, t.requestPath, "", "", "",
|
||||||
t.Connection.GetRemoteIP(), atomic.LoadInt64(&t.BytesSent), t.ErrTransfer)
|
atomic.LoadInt64(&t.BytesSent), t.ErrTransfer)
|
||||||
} else {
|
} else {
|
||||||
fileSize := atomic.LoadInt64(&t.BytesReceived) + t.MinWriteOffset
|
fileSize := atomic.LoadInt64(&t.BytesReceived) + t.MinWriteOffset
|
||||||
if statSize, err := t.getUploadFileSize(); err == nil {
|
if statSize, err := t.getUploadFileSize(); err == nil {
|
||||||
|
@ -267,8 +267,7 @@ func (t *BaseTransfer) Close() error {
|
||||||
t.updateTimes()
|
t.updateTimes()
|
||||||
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.ftpMode)
|
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,
|
ExecuteActionNotification(t.Connection, operationUpload, t.fsPath, t.requestPath, "", "", "", fileSize, t.ErrTransfer)
|
||||||
t.Connection.GetRemoteIP(), fileSize, t.ErrTransfer)
|
|
||||||
}
|
}
|
||||||
if t.ErrTransfer != nil {
|
if t.ErrTransfer != nil {
|
||||||
t.Connection.Log(logger.LevelWarn, "transfer error: %v, path: %#v", t.ErrTransfer, t.fsPath)
|
t.Connection.Log(logger.LevelWarn, "transfer error: %v, path: %#v", t.ErrTransfer, t.fsPath)
|
||||||
|
|
|
@ -43,8 +43,9 @@ If the `hook` defines a path to an external program, then this program can read
|
||||||
- `SFTPGO_ACTION_BUCKET`, non-empty for S3, GCS and Azure backends
|
- `SFTPGO_ACTION_BUCKET`, non-empty for S3, GCS and Azure backends
|
||||||
- `SFTPGO_ACTION_ENDPOINT`, non-empty for S3, SFTP and Azure backend if configured. For Azure this is the endpoint, if configured
|
- `SFTPGO_ACTION_ENDPOINT`, non-empty for S3, SFTP and Azure backend if configured. For Azure this is the endpoint, if configured
|
||||||
- `SFTPGO_ACTION_STATUS`, integer. Status for `upload`, `download` and `ssh_cmd` actions. 1 means no error, 2 means a generic error occurred, 3 means quota exceeded error
|
- `SFTPGO_ACTION_STATUS`, integer. Status for `upload`, `download` and `ssh_cmd` actions. 1 means no error, 2 means a generic error occurred, 3 means quota exceeded error
|
||||||
- `SFTPGO_ACTION_PROTOCOL`, string. Possible values are `SSH`, `SFTP`, `SCP`, `FTP`, `DAV`, `HTTP`, `DataRetention`
|
- `SFTPGO_ACTION_PROTOCOL`, string. Possible values are `SSH`, `SFTP`, `SCP`, `FTP`, `DAV`, `HTTP`, `HTTPShare`, `DataRetention`
|
||||||
- `SFTPGO_ACTION_IP`, the action was executed from this IP address
|
- `SFTPGO_ACTION_IP`, the action was executed from this IP address
|
||||||
|
- `SFTPGO_ACTION_SESSION_ID`, string. Unique protocol session identifier. For stateless protocols such as HTTP the session id will change for each request
|
||||||
- `SFTPGO_ACTION_OPEN_FLAGS`, integer. File open flags, can be non-zero for `pre-upload` action. If `SFTPGO_ACTION_FILE_SIZE` is greater than zero and `SFTPGO_ACTION_OPEN_FLAGS&512 == 0` the target file will not be truncated
|
- `SFTPGO_ACTION_OPEN_FLAGS`, integer. File open flags, can be non-zero for `pre-upload` action. If `SFTPGO_ACTION_FILE_SIZE` is greater than zero and `SFTPGO_ACTION_OPEN_FLAGS&512 == 0` the target file will not be truncated
|
||||||
- `SFTPGO_ACTION_TIMESTAMP`, int64. Event timestamp as nanoseconds since epoch
|
- `SFTPGO_ACTION_TIMESTAMP`, int64. Event timestamp as nanoseconds since epoch
|
||||||
|
|
||||||
|
@ -65,8 +66,9 @@ If the `hook` defines an HTTP URL then this URL will be invoked as HTTP POST. Th
|
||||||
- `bucket`, string, inlcuded for S3, GCS and Azure backends
|
- `bucket`, string, inlcuded for S3, GCS and Azure backends
|
||||||
- `endpoint`, string, included for S3, SFTP and Azure backend if configured
|
- `endpoint`, string, included for S3, SFTP and Azure backend if configured
|
||||||
- `status`, integer. Status for `upload`, `download` and `ssh_cmd` actions. 1 means no error, 2 means a generic error occurred, 3 means quota exceeded error
|
- `status`, integer. Status for `upload`, `download` and `ssh_cmd` actions. 1 means no error, 2 means a generic error occurred, 3 means quota exceeded error
|
||||||
- `protocol`, string. Possible values are `SSH`, `SFTP`, `SCP`, `FTP`, `DAV`, `HTTP`, `DataRetention`
|
- `protocol`, string. Possible values are `SSH`, `SFTP`, `SCP`, `FTP`, `DAV`, `HTTP`, `HTTPShare`, `DataRetention`
|
||||||
- `ip`, string. The action was executed from this IP address
|
- `ip`, string. The action was executed from this IP address
|
||||||
|
- `session_id`, string. Unique protocol session identifier. For stateless protocols such as HTTP the session id will change for each request
|
||||||
- `open_flags`, integer. File open flags, can be non-zero for `pre-upload` action. If `file_size` is greater than zero and `file_size&512 == 0` the target file will not be truncated
|
- `open_flags`, integer. File open flags, can be non-zero for `pre-upload` action. If `file_size` is greater than zero and `file_size&512 == 0` the target file will not be truncated
|
||||||
- `timestamp`, int64. Event timestamp as nanoseconds since epoch
|
- `timestamp`, int64. Event timestamp as nanoseconds since epoch
|
||||||
|
|
||||||
|
|
|
@ -325,8 +325,7 @@ func (c *Connection) downloadFile(fs vfs.Fs, fsPath, ftpPath string, offset int6
|
||||||
return nil, c.GetPermissionDeniedError()
|
return nil, c.GetPermissionDeniedError()
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := common.ExecutePreAction(&c.User, common.OperationPreDownload, fsPath, ftpPath, c.GetProtocol(), c.GetRemoteIP(),
|
if err := common.ExecutePreAction(c.BaseConnection, common.OperationPreDownload, fsPath, ftpPath, 0, 0); err != nil {
|
||||||
0, 0); err != nil {
|
|
||||||
c.Log(logger.LevelDebug, "download for file %#v denied by pre action: %v", ftpPath, err)
|
c.Log(logger.LevelDebug, "download for file %#v denied by pre action: %v", ftpPath, err)
|
||||||
return nil, c.GetPermissionDeniedError()
|
return nil, c.GetPermissionDeniedError()
|
||||||
}
|
}
|
||||||
|
@ -388,8 +387,7 @@ func (c *Connection) handleFTPUploadToNewFile(fs vfs.Fs, resolvedPath, filePath,
|
||||||
c.Log(logger.LevelInfo, "denying file write due to quota limits")
|
c.Log(logger.LevelInfo, "denying file write due to quota limits")
|
||||||
return nil, ftpserver.ErrStorageExceeded
|
return nil, ftpserver.ErrStorageExceeded
|
||||||
}
|
}
|
||||||
if err := common.ExecutePreAction(&c.User, common.OperationPreUpload, resolvedPath, requestPath, c.GetProtocol(),
|
if err := common.ExecutePreAction(c.BaseConnection, common.OperationPreUpload, resolvedPath, requestPath, 0, 0); err != nil {
|
||||||
c.GetRemoteIP(), 0, 0); err != nil {
|
|
||||||
c.Log(logger.LevelDebug, "upload for file %#v denied by pre action: %v", requestPath, err)
|
c.Log(logger.LevelDebug, "upload for file %#v denied by pre action: %v", requestPath, err)
|
||||||
return nil, fmt.Errorf("%w, denied by pre-upload action", ftpserver.ErrFileNameNotAllowed)
|
return nil, fmt.Errorf("%w, denied by pre-upload action", ftpserver.ErrFileNameNotAllowed)
|
||||||
}
|
}
|
||||||
|
@ -434,7 +432,7 @@ func (c *Connection) handleFTPUploadToExistingFile(fs vfs.Fs, flags int, resolve
|
||||||
c.Log(logger.LevelDebug, "unable to get max write size: %v", err)
|
c.Log(logger.LevelDebug, "unable to get max write size: %v", err)
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
if err := common.ExecutePreAction(&c.User, common.OperationPreUpload, resolvedPath, requestPath, c.GetProtocol(), c.GetRemoteIP(), fileSize, flags); err != nil {
|
if err := common.ExecutePreAction(c.BaseConnection, common.OperationPreUpload, resolvedPath, requestPath, fileSize, flags); err != nil {
|
||||||
c.Log(logger.LevelDebug, "upload for file %#v denied by pre action: %v", requestPath, err)
|
c.Log(logger.LevelDebug, "upload for file %#v denied by pre action: %v", requestPath, err)
|
||||||
return nil, fmt.Errorf("%w, denied by pre-upload action", ftpserver.ErrFileNameNotAllowed)
|
return nil, fmt.Errorf("%w, denied by pre-upload action", ftpserver.ErrFileNameNotAllowed)
|
||||||
}
|
}
|
||||||
|
|
|
@ -101,7 +101,7 @@ func (c *Connection) getFileReader(name string, offset int64, method string) (io
|
||||||
}
|
}
|
||||||
|
|
||||||
if method != http.MethodHead {
|
if method != http.MethodHead {
|
||||||
if err := common.ExecutePreAction(&c.User, common.OperationPreDownload, p, name, c.GetProtocol(), c.GetRemoteIP(), 0, 0); err != nil {
|
if err := common.ExecutePreAction(c.BaseConnection, common.OperationPreDownload, p, name, 0, 0); err != nil {
|
||||||
c.Log(logger.LevelDebug, "download for file %#v denied by pre action: %v", name, err)
|
c.Log(logger.LevelDebug, "download for file %#v denied by pre action: %v", name, err)
|
||||||
return nil, c.GetPermissionDeniedError()
|
return nil, c.GetPermissionDeniedError()
|
||||||
}
|
}
|
||||||
|
@ -176,7 +176,7 @@ func (c *Connection) handleUploadFile(fs vfs.Fs, resolvedPath, filePath, request
|
||||||
c.Log(logger.LevelInfo, "denying file write due to quota limits")
|
c.Log(logger.LevelInfo, "denying file write due to quota limits")
|
||||||
return nil, common.ErrQuotaExceeded
|
return nil, common.ErrQuotaExceeded
|
||||||
}
|
}
|
||||||
err := common.ExecutePreAction(&c.User, common.OperationPreUpload, resolvedPath, requestPath, c.GetProtocol(), c.GetRemoteIP(), fileSize, os.O_TRUNC)
|
err := common.ExecutePreAction(c.BaseConnection, common.OperationPreUpload, resolvedPath, requestPath, fileSize, os.O_TRUNC)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.Log(logger.LevelDebug, "upload for file %#v denied by pre action: %v", requestPath, err)
|
c.Log(logger.LevelDebug, "upload for file %#v denied by pre action: %v", requestPath, err)
|
||||||
return nil, c.GetPermissionDeniedError()
|
return nil, c.GetPermissionDeniedError()
|
||||||
|
|
|
@ -203,7 +203,7 @@ func (p *notifierPlugin) canQueueEvent(timestamp int64) bool {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *notifierPlugin) notifyFsAction(timestamp int64, action, username, fsPath, fsTargetPath, sshCmd,
|
func (p *notifierPlugin) notifyFsAction(timestamp int64, action, username, fsPath, fsTargetPath, sshCmd,
|
||||||
protocol, ip, virtualPath, virtualTargetPath string, fileSize int64, errAction error) {
|
protocol, ip, virtualPath, virtualTargetPath, sessionID string, fileSize int64, errAction error) {
|
||||||
if !util.IsStringInSlice(action, p.config.NotifierOptions.FsEvents) {
|
if !util.IsStringInSlice(action, p.config.NotifierOptions.FsEvents) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -214,7 +214,7 @@ func (p *notifierPlugin) notifyFsAction(timestamp int64, action, username, fsPat
|
||||||
status = 0
|
status = 0
|
||||||
}
|
}
|
||||||
p.sendFsEvent(timestamp, action, username, fsPath, fsTargetPath, sshCmd, protocol, ip, virtualPath, virtualTargetPath,
|
p.sendFsEvent(timestamp, action, username, fsPath, fsTargetPath, sshCmd, protocol, ip, virtualPath, virtualTargetPath,
|
||||||
fileSize, status)
|
sessionID, fileSize, status)
|
||||||
}()
|
}()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -237,9 +237,9 @@ func (p *notifierPlugin) notifyProviderAction(timestamp int64, action, username,
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *notifierPlugin) sendFsEvent(timestamp int64, action, username, fsPath, fsTargetPath, sshCmd,
|
func (p *notifierPlugin) sendFsEvent(timestamp int64, action, username, fsPath, fsTargetPath, sshCmd,
|
||||||
protocol, ip, virtualPath, virtualTargetPath string, fileSize int64, status int) {
|
protocol, ip, virtualPath, virtualTargetPath, sessionID string, fileSize int64, status int) {
|
||||||
if err := p.notifier.NotifyFsEvent(timestamp, action, username, fsPath, fsTargetPath, sshCmd, protocol, ip,
|
if err := p.notifier.NotifyFsEvent(timestamp, action, username, fsPath, fsTargetPath, sshCmd, protocol, ip,
|
||||||
virtualPath, virtualTargetPath, fileSize, status); err != nil {
|
virtualPath, virtualTargetPath, sessionID, fileSize, status); err != nil {
|
||||||
logger.Warn(logSender, "", "unable to send fs action notification to plugin %v: %v", p.config.Cmd, err)
|
logger.Warn(logSender, "", "unable to send fs action notification to plugin %v: %v", p.config.Cmd, err)
|
||||||
if p.canQueueEvent(timestamp) {
|
if p.canQueueEvent(timestamp) {
|
||||||
p.queue.addFsEvent(timestamp, action, username, fsPath, fsTargetPath, sshCmd, protocol, ip, fileSize, status)
|
p.queue.addFsEvent(timestamp, action, username, fsPath, fsTargetPath, sshCmd, protocol, ip, fileSize, status)
|
||||||
|
@ -267,7 +267,8 @@ func (p *notifierPlugin) sendQueuedEvents() {
|
||||||
fsEv := p.queue.popFsEvent()
|
fsEv := p.queue.popFsEvent()
|
||||||
for fsEv != nil {
|
for fsEv != nil {
|
||||||
go p.sendFsEvent(fsEv.Timestamp, fsEv.Action, fsEv.Username, fsEv.FsPath, fsEv.FsTargetPath,
|
go p.sendFsEvent(fsEv.Timestamp, fsEv.Action, fsEv.Username, fsEv.FsPath, fsEv.FsTargetPath,
|
||||||
fsEv.SshCmd, fsEv.Protocol, fsEv.Ip, fsEv.VirtualPath, fsEv.VirtualTargetPath, fsEv.FileSize, int(fsEv.Status))
|
fsEv.SshCmd, fsEv.Protocol, fsEv.Ip, fsEv.VirtualPath, fsEv.VirtualTargetPath, fsEv.SessionId,
|
||||||
|
fsEv.FileSize, int(fsEv.Status))
|
||||||
fsEv = p.queue.popFsEvent()
|
fsEv = p.queue.popFsEvent()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -20,7 +20,7 @@ type GRPCClient struct {
|
||||||
|
|
||||||
// NotifyFsEvent implements the Notifier interface
|
// NotifyFsEvent implements the Notifier interface
|
||||||
func (c *GRPCClient) NotifyFsEvent(timestamp int64, action, username, fsPath, fsTargetPath, sshCmd, protocol, ip,
|
func (c *GRPCClient) NotifyFsEvent(timestamp int64, action, username, fsPath, fsTargetPath, sshCmd, protocol, ip,
|
||||||
virtualPath, virtualTargetPath string, fileSize int64, status int,
|
virtualPath, virtualTargetPath, sessionID string, fileSize int64, status int,
|
||||||
) error {
|
) error {
|
||||||
ctx, cancel := context.WithTimeout(context.Background(), rpcTimeout)
|
ctx, cancel := context.WithTimeout(context.Background(), rpcTimeout)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
@ -38,6 +38,7 @@ func (c *GRPCClient) NotifyFsEvent(timestamp int64, action, username, fsPath, fs
|
||||||
Status: int32(status),
|
Status: int32(status),
|
||||||
VirtualPath: virtualPath,
|
VirtualPath: virtualPath,
|
||||||
VirtualTargetPath: virtualTargetPath,
|
VirtualTargetPath: virtualTargetPath,
|
||||||
|
SessionId: sessionID,
|
||||||
})
|
})
|
||||||
|
|
||||||
return err
|
return err
|
||||||
|
@ -69,7 +70,7 @@ type GRPCServer struct {
|
||||||
// SendFsEvent implements the serve side fs notify method
|
// SendFsEvent implements the serve side fs notify method
|
||||||
func (s *GRPCServer) SendFsEvent(ctx context.Context, req *proto.FsEvent) (*emptypb.Empty, error) {
|
func (s *GRPCServer) SendFsEvent(ctx context.Context, req *proto.FsEvent) (*emptypb.Empty, error) {
|
||||||
err := s.Impl.NotifyFsEvent(req.Timestamp, req.Action, req.Username, req.FsPath, req.FsTargetPath, req.SshCmd,
|
err := s.Impl.NotifyFsEvent(req.Timestamp, req.Action, req.Username, req.FsPath, req.FsTargetPath, req.SshCmd,
|
||||||
req.Protocol, req.Ip, req.VirtualPath, req.VirtualTargetPath, req.FileSize, int(req.Status))
|
req.Protocol, req.Ip, req.VirtualPath, req.VirtualTargetPath, req.SessionId, req.FileSize, int(req.Status))
|
||||||
return &emptypb.Empty{}, err
|
return &emptypb.Empty{}, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -33,7 +33,7 @@ var PluginMap = map[string]plugin.Plugin{
|
||||||
// Notifier defines the interface for notifiers plugins
|
// Notifier defines the interface for notifiers plugins
|
||||||
type Notifier interface {
|
type Notifier interface {
|
||||||
NotifyFsEvent(timestamp int64, action, username, fsPath, fsTargetPath, sshCmd, protocol, ip,
|
NotifyFsEvent(timestamp int64, action, username, fsPath, fsTargetPath, sshCmd, protocol, ip,
|
||||||
virtualPath, virtualTargetPath string, fileSize int64, status int) error
|
virtualPath, virtualTargetPath, sessionID string, fileSize int64, status int) error
|
||||||
NotifyProviderEvent(timestamp int64, action, username, objectType, objectName, ip string, object []byte) error
|
NotifyProviderEvent(timestamp int64, action, username, objectType, objectName, ip string, object []byte) error
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -42,6 +42,7 @@ type FsEvent struct {
|
||||||
Ip string `protobuf:"bytes,10,opt,name=ip,proto3" json:"ip,omitempty"`
|
Ip string `protobuf:"bytes,10,opt,name=ip,proto3" json:"ip,omitempty"`
|
||||||
VirtualPath string `protobuf:"bytes,11,opt,name=virtual_path,json=virtualPath,proto3" json:"virtual_path,omitempty"`
|
VirtualPath string `protobuf:"bytes,11,opt,name=virtual_path,json=virtualPath,proto3" json:"virtual_path,omitempty"`
|
||||||
VirtualTargetPath string `protobuf:"bytes,12,opt,name=virtual_target_path,json=virtualTargetPath,proto3" json:"virtual_target_path,omitempty"`
|
VirtualTargetPath string `protobuf:"bytes,12,opt,name=virtual_target_path,json=virtualTargetPath,proto3" json:"virtual_target_path,omitempty"`
|
||||||
|
SessionId string `protobuf:"bytes,13,opt,name=session_id,json=sessionId,proto3" json:"session_id,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *FsEvent) Reset() {
|
func (x *FsEvent) Reset() {
|
||||||
|
@ -160,6 +161,13 @@ func (x *FsEvent) GetVirtualTargetPath() string {
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (x *FsEvent) GetSessionId() string {
|
||||||
|
if x != nil {
|
||||||
|
return x.SessionId
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
type ProviderEvent struct {
|
type ProviderEvent struct {
|
||||||
state protoimpl.MessageState
|
state protoimpl.MessageState
|
||||||
sizeCache protoimpl.SizeCache
|
sizeCache protoimpl.SizeCache
|
||||||
|
@ -262,7 +270,7 @@ var file_notifier_proto_notifier_proto_rawDesc = []byte{
|
||||||
0x2f, 0x6e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x65, 0x72, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12,
|
0x2f, 0x6e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x65, 0x72, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12,
|
||||||
0x05, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x1b, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x70,
|
0x05, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x1b, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x70,
|
||||||
0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x65, 0x6d, 0x70, 0x74, 0x79, 0x2e, 0x70, 0x72,
|
0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x65, 0x6d, 0x70, 0x74, 0x79, 0x2e, 0x70, 0x72,
|
||||||
0x6f, 0x74, 0x6f, 0x22, 0xe7, 0x02, 0x0a, 0x07, 0x46, 0x73, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x12,
|
0x6f, 0x74, 0x6f, 0x22, 0x86, 0x03, 0x0a, 0x07, 0x46, 0x73, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x12,
|
||||||
0x1c, 0x0a, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, 0x01, 0x20, 0x01,
|
0x1c, 0x0a, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, 0x01, 0x20, 0x01,
|
||||||
0x28, 0x03, 0x52, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x12, 0x16, 0x0a,
|
0x28, 0x03, 0x52, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x12, 0x16, 0x0a,
|
||||||
0x06, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x61,
|
0x06, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x61,
|
||||||
|
@ -284,31 +292,33 @@ var file_notifier_proto_notifier_proto_rawDesc = []byte{
|
||||||
0x52, 0x0b, 0x76, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x50, 0x61, 0x74, 0x68, 0x12, 0x2e, 0x0a,
|
0x52, 0x0b, 0x76, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x50, 0x61, 0x74, 0x68, 0x12, 0x2e, 0x0a,
|
||||||
0x13, 0x76, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x5f, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x5f,
|
0x13, 0x76, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x5f, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x5f,
|
||||||
0x70, 0x61, 0x74, 0x68, 0x18, 0x0c, 0x20, 0x01, 0x28, 0x09, 0x52, 0x11, 0x76, 0x69, 0x72, 0x74,
|
0x70, 0x61, 0x74, 0x68, 0x18, 0x0c, 0x20, 0x01, 0x28, 0x09, 0x52, 0x11, 0x76, 0x69, 0x72, 0x74,
|
||||||
0x75, 0x61, 0x6c, 0x54, 0x61, 0x72, 0x67, 0x65, 0x74, 0x50, 0x61, 0x74, 0x68, 0x22, 0xd4, 0x01,
|
0x75, 0x61, 0x6c, 0x54, 0x61, 0x72, 0x67, 0x65, 0x74, 0x50, 0x61, 0x74, 0x68, 0x12, 0x1d, 0x0a,
|
||||||
0x0a, 0x0d, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x12,
|
0x0a, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x0d, 0x20, 0x01, 0x28,
|
||||||
0x1c, 0x0a, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, 0x01, 0x20, 0x01,
|
0x09, 0x52, 0x09, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x22, 0xd4, 0x01, 0x0a,
|
||||||
0x28, 0x03, 0x52, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x12, 0x16, 0x0a,
|
0x0d, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x12, 0x1c,
|
||||||
0x06, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x61,
|
0x0a, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, 0x01, 0x20, 0x01, 0x28,
|
||||||
0x63, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x1f, 0x0a, 0x0b, 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x5f,
|
0x03, 0x52, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x12, 0x16, 0x0a, 0x06,
|
||||||
0x74, 0x79, 0x70, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x6f, 0x62, 0x6a, 0x65,
|
0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x61, 0x63,
|
||||||
0x63, 0x74, 0x54, 0x79, 0x70, 0x65, 0x12, 0x1a, 0x0a, 0x08, 0x75, 0x73, 0x65, 0x72, 0x6e, 0x61,
|
0x74, 0x69, 0x6f, 0x6e, 0x12, 0x1f, 0x0a, 0x0b, 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x5f, 0x74,
|
||||||
0x6d, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x75, 0x73, 0x65, 0x72, 0x6e, 0x61,
|
0x79, 0x70, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x6f, 0x62, 0x6a, 0x65, 0x63,
|
||||||
0x6d, 0x65, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x70, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02,
|
0x74, 0x54, 0x79, 0x70, 0x65, 0x12, 0x1a, 0x0a, 0x08, 0x75, 0x73, 0x65, 0x72, 0x6e, 0x61, 0x6d,
|
||||||
0x69, 0x70, 0x12, 0x1f, 0x0a, 0x0b, 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x5f, 0x6e, 0x61, 0x6d,
|
0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x75, 0x73, 0x65, 0x72, 0x6e, 0x61, 0x6d,
|
||||||
0x65, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x4e,
|
0x65, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x70, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69,
|
||||||
0x61, 0x6d, 0x65, 0x12, 0x1f, 0x0a, 0x0b, 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x5f, 0x64, 0x61,
|
0x70, 0x12, 0x1f, 0x0a, 0x0b, 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x5f, 0x6e, 0x61, 0x6d, 0x65,
|
||||||
0x74, 0x61, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0a, 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74,
|
0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x4e, 0x61,
|
||||||
0x44, 0x61, 0x74, 0x61, 0x32, 0x84, 0x01, 0x0a, 0x08, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x65,
|
0x6d, 0x65, 0x12, 0x1f, 0x0a, 0x0b, 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x5f, 0x64, 0x61, 0x74,
|
||||||
0x72, 0x12, 0x35, 0x0a, 0x0b, 0x53, 0x65, 0x6e, 0x64, 0x46, 0x73, 0x45, 0x76, 0x65, 0x6e, 0x74,
|
0x61, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0a, 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x44,
|
||||||
0x12, 0x0e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x46, 0x73, 0x45, 0x76, 0x65, 0x6e, 0x74,
|
0x61, 0x74, 0x61, 0x32, 0x84, 0x01, 0x0a, 0x08, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x65, 0x72,
|
||||||
0x1a, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62,
|
0x12, 0x35, 0x0a, 0x0b, 0x53, 0x65, 0x6e, 0x64, 0x46, 0x73, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x12,
|
||||||
0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x12, 0x41, 0x0a, 0x11, 0x53, 0x65, 0x6e, 0x64,
|
0x0e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x46, 0x73, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x1a,
|
||||||
0x50, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x12, 0x14, 0x2e,
|
0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75,
|
||||||
0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x45, 0x76,
|
0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x12, 0x41, 0x0a, 0x11, 0x53, 0x65, 0x6e, 0x64, 0x50,
|
||||||
0x65, 0x6e, 0x74, 0x1a, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f,
|
0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x12, 0x14, 0x2e, 0x70,
|
||||||
0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x42, 0x1b, 0x5a, 0x19, 0x73,
|
0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x45, 0x76, 0x65,
|
||||||
0x64, 0x6b, 0x2f, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x2f, 0x6e, 0x6f, 0x74, 0x69, 0x66, 0x69,
|
0x6e, 0x74, 0x1a, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74,
|
||||||
0x65, 0x72, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
|
0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x42, 0x1b, 0x5a, 0x19, 0x73, 0x64,
|
||||||
|
0x6b, 0x2f, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x2f, 0x6e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x65,
|
||||||
|
0x72, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
|
||||||
}
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
|
|
@ -18,6 +18,7 @@ message FsEvent {
|
||||||
string ip = 10;
|
string ip = 10;
|
||||||
string virtual_path = 11;
|
string virtual_path = 11;
|
||||||
string virtual_target_path = 12;
|
string virtual_target_path = 12;
|
||||||
|
string session_id = 13;
|
||||||
}
|
}
|
||||||
|
|
||||||
message ProviderEvent {
|
message ProviderEvent {
|
||||||
|
|
|
@ -187,14 +187,14 @@ func (m *Manager) validateConfigs() error {
|
||||||
|
|
||||||
// NotifyFsEvent sends the fs event notifications using any defined notifier plugins
|
// NotifyFsEvent sends the fs event notifications using any defined notifier plugins
|
||||||
func (m *Manager) NotifyFsEvent(timestamp int64, action, username, fsPath, fsTargetPath, sshCmd, protocol, ip,
|
func (m *Manager) NotifyFsEvent(timestamp int64, action, username, fsPath, fsTargetPath, sshCmd, protocol, ip,
|
||||||
virtualPath, virtualTargetPath string, fileSize int64, err error,
|
virtualPath, virtualTargetPath, sessionID string, fileSize int64, err error,
|
||||||
) {
|
) {
|
||||||
m.notifLock.RLock()
|
m.notifLock.RLock()
|
||||||
defer m.notifLock.RUnlock()
|
defer m.notifLock.RUnlock()
|
||||||
|
|
||||||
for _, n := range m.notifiers {
|
for _, n := range m.notifiers {
|
||||||
n.notifyFsAction(timestamp, action, username, fsPath, fsTargetPath, sshCmd, protocol, ip, virtualPath, virtualTargetPath,
|
n.notifyFsAction(timestamp, action, username, fsPath, fsTargetPath, sshCmd, protocol, ip, virtualPath,
|
||||||
fileSize, err)
|
virtualTargetPath, sessionID, fileSize, err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -73,7 +73,7 @@ func (c *Connection) Fileread(request *sftp.Request) (io.ReaderAt, error) {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := common.ExecutePreAction(&c.User, common.OperationPreDownload, p, request.Filepath, c.GetProtocol(), c.GetRemoteIP(), 0, 0); err != nil {
|
if err := common.ExecutePreAction(c.BaseConnection, common.OperationPreDownload, p, request.Filepath, 0, 0); err != nil {
|
||||||
c.Log(logger.LevelDebug, "download for file %#v denied by pre action: %v", request.Filepath, err)
|
c.Log(logger.LevelDebug, "download for file %#v denied by pre action: %v", request.Filepath, err)
|
||||||
return nil, c.GetPermissionDeniedError()
|
return nil, c.GetPermissionDeniedError()
|
||||||
}
|
}
|
||||||
|
@ -349,7 +349,7 @@ func (c *Connection) handleSFTPUploadToNewFile(fs vfs.Fs, resolvedPath, filePath
|
||||||
return nil, c.GetQuotaExceededError()
|
return nil, c.GetQuotaExceededError()
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := common.ExecutePreAction(&c.User, common.OperationPreUpload, resolvedPath, requestPath, c.GetProtocol(), c.GetRemoteIP(), 0, 0); err != nil {
|
if err := common.ExecutePreAction(c.BaseConnection, common.OperationPreUpload, resolvedPath, requestPath, 0, 0); err != nil {
|
||||||
c.Log(logger.LevelDebug, "upload for file %#v denied by pre action: %v", requestPath, err)
|
c.Log(logger.LevelDebug, "upload for file %#v denied by pre action: %v", requestPath, err)
|
||||||
return nil, c.GetPermissionDeniedError()
|
return nil, c.GetPermissionDeniedError()
|
||||||
}
|
}
|
||||||
|
@ -396,7 +396,7 @@ func (c *Connection) handleSFTPUploadToExistingFile(fs vfs.Fs, pflags sftp.FileO
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := common.ExecutePreAction(&c.User, common.OperationPreUpload, resolvedPath, requestPath, c.GetProtocol(), c.GetRemoteIP(), fileSize, osFlags); err != nil {
|
if err := common.ExecutePreAction(c.BaseConnection, common.OperationPreUpload, resolvedPath, requestPath, fileSize, osFlags); err != nil {
|
||||||
c.Log(logger.LevelDebug, "upload for file %#v denied by pre action: %v", requestPath, err)
|
c.Log(logger.LevelDebug, "upload for file %#v denied by pre action: %v", requestPath, err)
|
||||||
return nil, c.GetPermissionDeniedError()
|
return nil, c.GetPermissionDeniedError()
|
||||||
}
|
}
|
||||||
|
|
|
@ -219,8 +219,8 @@ func (c *scpCommand) handleUploadFile(fs vfs.Fs, resolvedPath, filePath string,
|
||||||
c.sendErrorMessage(fs, err)
|
c.sendErrorMessage(fs, err)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
err := common.ExecutePreAction(&c.connection.User, common.OperationPreUpload, resolvedPath, requestPath,
|
err := common.ExecutePreAction(c.connection.BaseConnection, common.OperationPreUpload, resolvedPath, requestPath,
|
||||||
c.connection.GetProtocol(), c.connection.GetRemoteIP(), fileSize, os.O_TRUNC)
|
fileSize, os.O_TRUNC)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.connection.Log(logger.LevelDebug, "upload for file %#v denied by pre action: %v", requestPath, err)
|
c.connection.Log(logger.LevelDebug, "upload for file %#v denied by pre action: %v", requestPath, err)
|
||||||
err = c.connection.GetPermissionDeniedError()
|
err = c.connection.GetPermissionDeniedError()
|
||||||
|
@ -515,7 +515,7 @@ func (c *scpCommand) handleDownload(filePath string) error {
|
||||||
return common.ErrPermissionDenied
|
return common.ErrPermissionDenied
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := common.ExecutePreAction(&c.connection.User, common.OperationPreDownload, p, filePath, c.connection.GetProtocol(), c.connection.GetRemoteIP(), 0, 0); err != nil {
|
if err := common.ExecutePreAction(c.connection.BaseConnection, common.OperationPreDownload, p, filePath, 0, 0); err != nil {
|
||||||
c.connection.Log(logger.LevelDebug, "download for file %#v denied by pre action: %v", filePath, err)
|
c.connection.Log(logger.LevelDebug, "download for file %#v denied by pre action: %v", filePath, err)
|
||||||
c.sendErrorMessage(fs, common.ErrPermissionDenied)
|
c.sendErrorMessage(fs, common.ErrPermissionDenied)
|
||||||
return common.ErrPermissionDenied
|
return common.ErrPermissionDenied
|
||||||
|
|
|
@ -751,8 +751,8 @@ func (c *sshCommand) sendExitStatus(err error) {
|
||||||
targetPath = p
|
targetPath = p
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
common.ExecuteActionNotification(&c.connection.User, common.OperationSSHCmd, cmdPath, vCmdPath, targetPath,
|
common.ExecuteActionNotification(c.connection.BaseConnection, common.OperationSSHCmd, cmdPath, vCmdPath, targetPath,
|
||||||
vTargetPath, c.command, common.ProtocolSSH, c.connection.GetRemoteIP(), 0, err)
|
vTargetPath, c.command, 0, err)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
logger.CommandLog(sshCommandLogSender, cmdPath, targetPath, c.connection.User.Username, "", c.connection.ID,
|
logger.CommandLog(sshCommandLogSender, cmdPath, targetPath, c.connection.User.Username, "", c.connection.ID,
|
||||||
common.ProtocolSSH, -1, -1, "", "", c.connection.command, -1, c.connection.GetLocalAddress(),
|
common.ProtocolSSH, -1, -1, "", "", c.connection.command, -1, c.connection.GetLocalAddress(),
|
||||||
|
|
|
@ -147,8 +147,7 @@ func (f *webDavFile) Read(p []byte) (n int, err error) {
|
||||||
f.Connection.Log(logger.LevelWarn, "reading file %#v is not allowed", f.GetVirtualPath())
|
f.Connection.Log(logger.LevelWarn, "reading file %#v is not allowed", f.GetVirtualPath())
|
||||||
return 0, f.Connection.GetPermissionDeniedError()
|
return 0, f.Connection.GetPermissionDeniedError()
|
||||||
}
|
}
|
||||||
err := common.ExecutePreAction(&f.Connection.User, common.OperationPreDownload, f.GetFsPath(), f.GetVirtualPath(),
|
err := common.ExecutePreAction(f.Connection, common.OperationPreDownload, f.GetFsPath(), f.GetVirtualPath(), 0, 0)
|
||||||
f.Connection.GetProtocol(), f.Connection.GetRemoteIP(), 0, 0)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
f.Connection.Log(logger.LevelDebug, "download for file %#v denied by pre action: %v", f.GetVirtualPath(), err)
|
f.Connection.Log(logger.LevelDebug, "download for file %#v denied by pre action: %v", f.GetVirtualPath(), err)
|
||||||
return 0, f.Connection.GetPermissionDeniedError()
|
return 0, f.Connection.GetPermissionDeniedError()
|
||||||
|
|
|
@ -199,7 +199,7 @@ func (c *Connection) handleUploadToNewFile(fs vfs.Fs, resolvedPath, filePath, re
|
||||||
c.Log(logger.LevelInfo, "denying file write due to quota limits")
|
c.Log(logger.LevelInfo, "denying file write due to quota limits")
|
||||||
return nil, common.ErrQuotaExceeded
|
return nil, common.ErrQuotaExceeded
|
||||||
}
|
}
|
||||||
if err := common.ExecutePreAction(&c.User, common.OperationPreUpload, resolvedPath, requestPath, c.GetProtocol(), c.GetRemoteIP(), 0, 0); err != nil {
|
if err := common.ExecutePreAction(c.BaseConnection, common.OperationPreUpload, resolvedPath, requestPath, 0, 0); err != nil {
|
||||||
c.Log(logger.LevelDebug, "upload for file %#v denied by pre action: %v", requestPath, err)
|
c.Log(logger.LevelDebug, "upload for file %#v denied by pre action: %v", requestPath, err)
|
||||||
return nil, c.GetPermissionDeniedError()
|
return nil, c.GetPermissionDeniedError()
|
||||||
}
|
}
|
||||||
|
@ -228,7 +228,7 @@ func (c *Connection) handleUploadToExistingFile(fs vfs.Fs, resolvedPath, filePat
|
||||||
c.Log(logger.LevelInfo, "denying file write due to quota limits")
|
c.Log(logger.LevelInfo, "denying file write due to quota limits")
|
||||||
return nil, common.ErrQuotaExceeded
|
return nil, common.ErrQuotaExceeded
|
||||||
}
|
}
|
||||||
if err := common.ExecutePreAction(&c.User, common.OperationPreUpload, resolvedPath, requestPath, c.GetProtocol(), c.GetRemoteIP(),
|
if err := common.ExecutePreAction(c.BaseConnection, common.OperationPreUpload, resolvedPath, requestPath,
|
||||||
fileSize, os.O_TRUNC); err != nil {
|
fileSize, os.O_TRUNC); err != nil {
|
||||||
c.Log(logger.LevelDebug, "upload for file %#v denied by pre action: %v", requestPath, err)
|
c.Log(logger.LevelDebug, "upload for file %#v denied by pre action: %v", requestPath, err)
|
||||||
return nil, c.GetPermissionDeniedError()
|
return nil, c.GetPermissionDeniedError()
|
||||||
|
|
Loading…
Reference in a new issue