Pārlūkot izejas kodu

sftp actions: add a parameter to distinguish local and remote files

Nicola Murino 5 gadi atpakaļ
vecāks
revīzija
6884ce3f3e
6 mainītis faili ar 16 papildinājumiem un 12 dzēšanām
  1. 2 0
      README.md
  2. 2 2
      sftpd/handler.go
  3. 3 3
      sftpd/internal_test.go
  4. 6 4
      sftpd/sftpd.go
  5. 1 1
      sftpd/ssh_cmd.go
  6. 2 2
      sftpd/transfer.go

+ 2 - 0
README.md

@@ -425,6 +425,7 @@ The `command` can also read the following environment variables:
 - `SFTPGO_ACTION_TARGET`, non empty for `rename` `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_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.
 The `command` must finish within 30 seconds.
@@ -434,6 +435,7 @@ The `http_notification_url`, if defined, will contain the following, percent enc
 - `action`
 - `username`
 - `path`
+- `local_file`, `true` if the affected file is stored on the local filesystem, otherwise `false`
 - `target_path`, added for `rename` action
 - `ssh_cmd`, added for `ssh_cmd` action
 - `file_size`, added for `upload`, `download`, `delete` actions

+ 2 - 2
sftpd/handler.go

@@ -314,7 +314,7 @@ func (c Connection) handleSFTPRename(sourcePath string, targetPath string, reque
 		return vfs.GetSFTPError(c.fs, err)
 	}
 	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
 }
 
@@ -404,7 +404,7 @@ func (c Connection) handleSFTPRemove(filePath string, request *sftp.Request) err
 	if fi.Mode()&os.ModeSymlink != os.ModeSymlink {
 		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
 }

+ 3 - 3
sftpd/internal_test.go

@@ -130,17 +130,17 @@ func TestWrongActions(t *testing.T) {
 		Command:             badCommand,
 		HTTPNotificationURL: "",
 	}
-	err := executeAction(operationDownload, "username", "path", "", "", 0)
+	err := executeAction(operationDownload, "username", "path", "", "", 0, true)
 	if err == nil {
 		t.Errorf("action with bad command must fail")
 	}
-	err = executeAction(operationDelete, "username", "path", "", "", 0)
+	err = executeAction(operationDelete, "username", "path", "", "", 0, true)
 	if err != nil {
 		t.Errorf("action not configured must silently fail")
 	}
 	actions.Command = ""
 	actions.HTTPNotificationURL = "http://foo\x7f.com/"
-	err = executeAction(operationDownload, "username", "path", "", "", 0)
+	err = executeAction(operationDownload, "username", "path", "", "", 0, true)
 	if err == nil {
 		t.Errorf("action with bad url must fail")
 	}

+ 6 - 4
sftpd/sftpd.go

@@ -415,7 +415,7 @@ func isAtomicUploadEnabled() bool {
 	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)
 	defer cancel()
 	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_SSH_CMD=%v", sshCmd),
 		fmt.Sprintf("SFTPGO_ACTION_FILE_SIZE=%v", fileSize),
+		fmt.Sprintf("SFTPGO_ACTION_LOCAL_FILE=%v", isLocalFile),
 	)
 	startTime := time.Now()
 	err := cmd.Run()
@@ -435,7 +436,7 @@ func executeNotificationCommand(operation, username, path, target, sshCmd, fileS
 }
 
 // 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) {
 		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
 		// end of the command
 		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 {
-			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 {
@@ -470,6 +471,7 @@ func executeAction(operation, username, path, target, sshCmd string, fileSize in
 			if len(size) > 0 {
 				q.Add("file_size", size)
 			}
+			q.Add("local_file", fmt.Sprintf("%t", isLocalFile))
 			url.RawQuery = q.Encode()
 			startTime := time.Now()
 			httpClient := &http.Client{

+ 1 - 1
sftpd/ssh_cmd.go

@@ -402,7 +402,7 @@ func (c *sshCommand) sendExitStatus(err error) {
 				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))
 	}
 }
 

+ 2 - 2
sftpd/transfer.go

@@ -152,10 +152,10 @@ func (t *Transfer) Close() error {
 		elapsed := time.Since(t.start).Nanoseconds() / 1000000
 		if t.transferType == transferDownload {
 			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 {
 			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 {
 		logger.Warn(logSender, t.connectionID, "transfer error: %v, path: %#v", t.transferError, t.path)