command.go 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115
  1. // Copyright (C) 2019-2022 Nicola Murino
  2. //
  3. // This program is free software: you can redistribute it and/or modify
  4. // it under the terms of the GNU Affero General Public License as published
  5. // by the Free Software Foundation, version 3.
  6. //
  7. // This program is distributed in the hope that it will be useful,
  8. // but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  10. // GNU Affero General Public License for more details.
  11. //
  12. // You should have received a copy of the GNU Affero General Public License
  13. // along with this program. If not, see <https://www.gnu.org/licenses/>.
  14. // Package command provides command configuration for SFTPGo hooks
  15. package command
  16. import (
  17. "fmt"
  18. "os"
  19. "strings"
  20. "time"
  21. )
  22. const (
  23. minTimeout = 1
  24. maxTimeout = 300
  25. defaultTimeout = 30
  26. )
  27. var (
  28. config Config
  29. )
  30. // Command define the configuration for a specific commands
  31. type Command struct {
  32. // Path is the command path as defined in the hook configuration
  33. Path string `json:"path" mapstructure:"path"`
  34. // Timeout specifies a time limit, in seconds, for the command execution.
  35. // This value overrides the global timeout if set.
  36. // Do not use variables with the SFTPGO_ prefix to avoid conflicts with env
  37. // vars that SFTPGo sets
  38. Timeout int `json:"timeout" mapstructure:"timeout"`
  39. // Env defines additional environment variable for the commands.
  40. // Each entry is of the form "key=value".
  41. // These values are added to the global environment variables if any
  42. Env []string `json:"env" mapstructure:"env"`
  43. }
  44. // Config defines the configuration for external commands such as
  45. // program based hooks
  46. type Config struct {
  47. // Timeout specifies a global time limit, in seconds, for the external commands execution
  48. Timeout int `json:"timeout" mapstructure:"timeout"`
  49. // Env defines additional environment variable for the commands.
  50. // Each entry is of the form "key=value".
  51. // Do not use variables with the SFTPGO_ prefix to avoid conflicts with env
  52. // vars that SFTPGo sets
  53. Env []string `json:"env" mapstructure:"env"`
  54. // Commands defines configuration for specific commands
  55. Commands []Command `json:"commands" mapstructure:"commands"`
  56. }
  57. func init() {
  58. config = Config{
  59. Timeout: defaultTimeout,
  60. }
  61. }
  62. // Initialize configures commands
  63. func (c Config) Initialize() error {
  64. if c.Timeout < minTimeout || c.Timeout > maxTimeout {
  65. return fmt.Errorf("invalid timeout %v", c.Timeout)
  66. }
  67. for _, env := range c.Env {
  68. if len(strings.Split(env, "=")) != 2 {
  69. return fmt.Errorf("invalid env var %#v", env)
  70. }
  71. }
  72. for idx, cmd := range c.Commands {
  73. if cmd.Path == "" {
  74. return fmt.Errorf("invalid path %#v", cmd.Path)
  75. }
  76. if cmd.Timeout == 0 {
  77. c.Commands[idx].Timeout = c.Timeout
  78. } else {
  79. if cmd.Timeout < minTimeout || cmd.Timeout > maxTimeout {
  80. return fmt.Errorf("invalid timeout %v for command %#v", cmd.Timeout, cmd.Path)
  81. }
  82. }
  83. for _, env := range cmd.Env {
  84. if len(strings.Split(env, "=")) != 2 {
  85. return fmt.Errorf("invalid env var %#v for command %#v", env, cmd.Path)
  86. }
  87. }
  88. }
  89. config = c
  90. return nil
  91. }
  92. // GetConfig returns the configuration for the specified command
  93. func GetConfig(command string) (time.Duration, []string) {
  94. env := os.Environ()
  95. timeout := time.Duration(config.Timeout) * time.Second
  96. env = append(env, config.Env...)
  97. for _, cmd := range config.Commands {
  98. if cmd.Path == command {
  99. timeout = time.Duration(cmd.Timeout) * time.Second
  100. env = append(env, cmd.Env...)
  101. break
  102. }
  103. }
  104. return timeout, env
  105. }