mirror of
https://github.com/drakkan/sftpgo.git
synced 2024-11-21 15:10:23 +00:00
sftp actions: add a parameter to distinguish local and remote files
This commit is contained in:
parent
5f4efc9148
commit
6884ce3f3e
6 changed files with 16 additions and 12 deletions
|
@ -425,6 +425,7 @@ The `command` can also read the following environment variables:
|
||||||
- `SFTPGO_ACTION_TARGET`, non empty for `rename` `SFTPGO_ACTION`
|
- `SFTPGO_ACTION_TARGET`, non empty for `rename` `SFTPGO_ACTION`
|
||||||
- `SFTPGO_ACTION_SSH_CMD`, non empty for `ssh_cmd` `SFTPGO_ACTION`
|
- `SFTPGO_ACTION_SSH_CMD`, non empty for `ssh_cmd` `SFTPGO_ACTION`
|
||||||
- `SFTPGO_ACTION_FILE_SIZE`, non empty for `upload`, `download` and `delete` `SFTPGO_ACTION`
|
- `SFTPGO_ACTION_FILE_SIZE`, non empty for `upload`, `download` and `delete` `SFTPGO_ACTION`
|
||||||
|
- `SFTPGO_ACTION_LOCAL_FILE`, `true` if the affected file is stored on the local filesystem, otherwise `false`
|
||||||
|
|
||||||
Previous global environment variables aren't cleared when the script is called.
|
Previous global environment variables aren't cleared when the script is called.
|
||||||
The `command` must finish within 30 seconds.
|
The `command` must finish within 30 seconds.
|
||||||
|
@ -434,6 +435,7 @@ The `http_notification_url`, if defined, will contain the following, percent enc
|
||||||
- `action`
|
- `action`
|
||||||
- `username`
|
- `username`
|
||||||
- `path`
|
- `path`
|
||||||
|
- `local_file`, `true` if the affected file is stored on the local filesystem, otherwise `false`
|
||||||
- `target_path`, added for `rename` action
|
- `target_path`, added for `rename` action
|
||||||
- `ssh_cmd`, added for `ssh_cmd` action
|
- `ssh_cmd`, added for `ssh_cmd` action
|
||||||
- `file_size`, added for `upload`, `download`, `delete` actions
|
- `file_size`, added for `upload`, `download`, `delete` actions
|
||||||
|
|
|
@ -314,7 +314,7 @@ func (c Connection) handleSFTPRename(sourcePath string, targetPath string, reque
|
||||||
return vfs.GetSFTPError(c.fs, err)
|
return vfs.GetSFTPError(c.fs, err)
|
||||||
}
|
}
|
||||||
logger.CommandLog(renameLogSender, sourcePath, targetPath, c.User.Username, "", c.ID, c.protocol, -1, -1, "", "", "")
|
logger.CommandLog(renameLogSender, sourcePath, targetPath, c.User.Username, "", c.ID, c.protocol, -1, -1, "", "", "")
|
||||||
go executeAction(operationRename, c.User.Username, sourcePath, targetPath, "", 0)
|
go executeAction(operationRename, c.User.Username, sourcePath, targetPath, "", 0, vfs.IsLocalOsFs(c.fs))
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -404,7 +404,7 @@ func (c Connection) handleSFTPRemove(filePath string, request *sftp.Request) err
|
||||||
if fi.Mode()&os.ModeSymlink != os.ModeSymlink {
|
if fi.Mode()&os.ModeSymlink != os.ModeSymlink {
|
||||||
dataprovider.UpdateUserQuota(dataProvider, c.User, -1, -size, false)
|
dataprovider.UpdateUserQuota(dataProvider, c.User, -1, -size, false)
|
||||||
}
|
}
|
||||||
go executeAction(operationDelete, c.User.Username, filePath, "", "", fi.Size())
|
go executeAction(operationDelete, c.User.Username, filePath, "", "", fi.Size(), vfs.IsLocalOsFs(c.fs))
|
||||||
|
|
||||||
return sftp.ErrSSHFxOk
|
return sftp.ErrSSHFxOk
|
||||||
}
|
}
|
||||||
|
|
|
@ -130,17 +130,17 @@ func TestWrongActions(t *testing.T) {
|
||||||
Command: badCommand,
|
Command: badCommand,
|
||||||
HTTPNotificationURL: "",
|
HTTPNotificationURL: "",
|
||||||
}
|
}
|
||||||
err := executeAction(operationDownload, "username", "path", "", "", 0)
|
err := executeAction(operationDownload, "username", "path", "", "", 0, true)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
t.Errorf("action with bad command must fail")
|
t.Errorf("action with bad command must fail")
|
||||||
}
|
}
|
||||||
err = executeAction(operationDelete, "username", "path", "", "", 0)
|
err = executeAction(operationDelete, "username", "path", "", "", 0, true)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("action not configured must silently fail")
|
t.Errorf("action not configured must silently fail")
|
||||||
}
|
}
|
||||||
actions.Command = ""
|
actions.Command = ""
|
||||||
actions.HTTPNotificationURL = "http://foo\x7f.com/"
|
actions.HTTPNotificationURL = "http://foo\x7f.com/"
|
||||||
err = executeAction(operationDownload, "username", "path", "", "", 0)
|
err = executeAction(operationDownload, "username", "path", "", "", 0, true)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
t.Errorf("action with bad url must fail")
|
t.Errorf("action with bad url must fail")
|
||||||
}
|
}
|
||||||
|
|
|
@ -415,7 +415,7 @@ func isAtomicUploadEnabled() bool {
|
||||||
return uploadMode == uploadModeAtomic || uploadMode == uploadModeAtomicWithResume
|
return uploadMode == uploadModeAtomic || uploadMode == uploadModeAtomicWithResume
|
||||||
}
|
}
|
||||||
|
|
||||||
func executeNotificationCommand(operation, username, path, target, sshCmd, fileSize string) error {
|
func executeNotificationCommand(operation, username, path, target, sshCmd, fileSize, isLocalFile string) error {
|
||||||
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
|
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
cmd := exec.CommandContext(ctx, actions.Command, operation, username, path, target, sshCmd)
|
cmd := exec.CommandContext(ctx, actions.Command, operation, username, path, target, sshCmd)
|
||||||
|
@ -426,6 +426,7 @@ func executeNotificationCommand(operation, username, path, target, sshCmd, fileS
|
||||||
fmt.Sprintf("SFTPGO_ACTION_TARGET=%v", target),
|
fmt.Sprintf("SFTPGO_ACTION_TARGET=%v", target),
|
||||||
fmt.Sprintf("SFTPGO_ACTION_SSH_CMD=%v", sshCmd),
|
fmt.Sprintf("SFTPGO_ACTION_SSH_CMD=%v", sshCmd),
|
||||||
fmt.Sprintf("SFTPGO_ACTION_FILE_SIZE=%v", fileSize),
|
fmt.Sprintf("SFTPGO_ACTION_FILE_SIZE=%v", fileSize),
|
||||||
|
fmt.Sprintf("SFTPGO_ACTION_LOCAL_FILE=%v", isLocalFile),
|
||||||
)
|
)
|
||||||
startTime := time.Now()
|
startTime := time.Now()
|
||||||
err := cmd.Run()
|
err := cmd.Run()
|
||||||
|
@ -435,7 +436,7 @@ func executeNotificationCommand(operation, username, path, target, sshCmd, fileS
|
||||||
}
|
}
|
||||||
|
|
||||||
// executed in a goroutine
|
// executed in a goroutine
|
||||||
func executeAction(operation, username, path, target, sshCmd string, fileSize int64) error {
|
func executeAction(operation, username, path, target, sshCmd string, fileSize int64, isLocalFile bool) error {
|
||||||
if !utils.IsStringInSlice(operation, actions.ExecuteOn) {
|
if !utils.IsStringInSlice(operation, actions.ExecuteOn) {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -448,9 +449,9 @@ func executeAction(operation, username, path, target, sshCmd string, fileSize in
|
||||||
// we are in a goroutine but if we have to send an HTTP notification we don't want to wait for the
|
// we are in a goroutine but if we have to send an HTTP notification we don't want to wait for the
|
||||||
// end of the command
|
// end of the command
|
||||||
if len(actions.HTTPNotificationURL) > 0 {
|
if len(actions.HTTPNotificationURL) > 0 {
|
||||||
go executeNotificationCommand(operation, username, path, target, sshCmd, size)
|
go executeNotificationCommand(operation, username, path, target, sshCmd, size, fmt.Sprintf("%t", isLocalFile))
|
||||||
} else {
|
} else {
|
||||||
err = executeNotificationCommand(operation, username, path, target, sshCmd, size)
|
err = executeNotificationCommand(operation, username, path, target, sshCmd, size, fmt.Sprintf("%t", isLocalFile))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if len(actions.HTTPNotificationURL) > 0 {
|
if len(actions.HTTPNotificationURL) > 0 {
|
||||||
|
@ -470,6 +471,7 @@ func executeAction(operation, username, path, target, sshCmd string, fileSize in
|
||||||
if len(size) > 0 {
|
if len(size) > 0 {
|
||||||
q.Add("file_size", size)
|
q.Add("file_size", size)
|
||||||
}
|
}
|
||||||
|
q.Add("local_file", fmt.Sprintf("%t", isLocalFile))
|
||||||
url.RawQuery = q.Encode()
|
url.RawQuery = q.Encode()
|
||||||
startTime := time.Now()
|
startTime := time.Now()
|
||||||
httpClient := &http.Client{
|
httpClient := &http.Client{
|
||||||
|
|
|
@ -402,7 +402,7 @@ func (c *sshCommand) sendExitStatus(err error) {
|
||||||
realPath = p
|
realPath = p
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
go executeAction(operationSSHCmd, c.connection.User.Username, realPath, "", c.command, 0)
|
go executeAction(operationSSHCmd, c.connection.User.Username, realPath, "", c.command, 0, vfs.IsLocalOsFs(c.connection.fs))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -152,10 +152,10 @@ func (t *Transfer) 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.path, elapsed, t.bytesSent, t.user.Username, t.connectionID, t.protocol)
|
logger.TransferLog(downloadLogSender, t.path, elapsed, t.bytesSent, t.user.Username, t.connectionID, t.protocol)
|
||||||
go executeAction(operationDownload, t.user.Username, t.path, "", "", t.bytesSent)
|
go executeAction(operationDownload, t.user.Username, t.path, "", "", t.bytesSent, (t.file != nil))
|
||||||
} else {
|
} else {
|
||||||
logger.TransferLog(uploadLogSender, t.path, elapsed, t.bytesReceived, t.user.Username, t.connectionID, t.protocol)
|
logger.TransferLog(uploadLogSender, t.path, elapsed, t.bytesReceived, t.user.Username, t.connectionID, t.protocol)
|
||||||
go executeAction(operationUpload, t.user.Username, t.path, "", "", t.bytesReceived+t.minWriteOffset)
|
go executeAction(operationUpload, t.user.Username, t.path, "", "", t.bytesReceived+t.minWriteOffset, (t.file != nil))
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
logger.Warn(logSender, t.connectionID, "transfer error: %v, path: %#v", t.transferError, t.path)
|
logger.Warn(logSender, t.connectionID, "transfer error: %v, path: %#v", t.transferError, t.path)
|
||||||
|
|
Loading…
Reference in a new issue