filesystem.go 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309
  1. package vfs
  2. import (
  3. "fmt"
  4. "github.com/sftpgo/sdk"
  5. "github.com/drakkan/sftpgo/v2/kms"
  6. "github.com/drakkan/sftpgo/v2/util"
  7. )
  8. // ValidatorHelper implements methods we need for Filesystem.ValidateConfig.
  9. // It is implemented by vfs.Folder and dataprovider.User
  10. type ValidatorHelper interface {
  11. GetGCSCredentialsFilePath() string
  12. GetEncryptionAdditionalData() string
  13. }
  14. // Filesystem defines filesystem details
  15. type Filesystem struct {
  16. RedactedSecret string `json:"-"`
  17. Provider sdk.FilesystemProvider `json:"provider"`
  18. S3Config S3FsConfig `json:"s3config,omitempty"`
  19. GCSConfig GCSFsConfig `json:"gcsconfig,omitempty"`
  20. AzBlobConfig AzBlobFsConfig `json:"azblobconfig,omitempty"`
  21. CryptConfig CryptFsConfig `json:"cryptconfig,omitempty"`
  22. SFTPConfig SFTPFsConfig `json:"sftpconfig,omitempty"`
  23. }
  24. // SetEmptySecrets sets the secrets to empty
  25. func (f *Filesystem) SetEmptySecrets() {
  26. f.S3Config.AccessSecret = kms.NewEmptySecret()
  27. f.GCSConfig.Credentials = kms.NewEmptySecret()
  28. f.AzBlobConfig.AccountKey = kms.NewEmptySecret()
  29. f.AzBlobConfig.SASURL = kms.NewEmptySecret()
  30. f.CryptConfig.Passphrase = kms.NewEmptySecret()
  31. f.SFTPConfig.Password = kms.NewEmptySecret()
  32. f.SFTPConfig.PrivateKey = kms.NewEmptySecret()
  33. }
  34. // SetEmptySecretsIfNil sets the secrets to empty if nil
  35. func (f *Filesystem) SetEmptySecretsIfNil() {
  36. if f.S3Config.AccessSecret == nil {
  37. f.S3Config.AccessSecret = kms.NewEmptySecret()
  38. }
  39. if f.GCSConfig.Credentials == nil {
  40. f.GCSConfig.Credentials = kms.NewEmptySecret()
  41. }
  42. if f.AzBlobConfig.AccountKey == nil {
  43. f.AzBlobConfig.AccountKey = kms.NewEmptySecret()
  44. }
  45. if f.AzBlobConfig.SASURL == nil {
  46. f.AzBlobConfig.SASURL = kms.NewEmptySecret()
  47. }
  48. if f.CryptConfig.Passphrase == nil {
  49. f.CryptConfig.Passphrase = kms.NewEmptySecret()
  50. }
  51. if f.SFTPConfig.Password == nil {
  52. f.SFTPConfig.Password = kms.NewEmptySecret()
  53. }
  54. if f.SFTPConfig.PrivateKey == nil {
  55. f.SFTPConfig.PrivateKey = kms.NewEmptySecret()
  56. }
  57. }
  58. // SetNilSecretsIfEmpty set the secrets to nil if empty.
  59. // This is useful before rendering as JSON so the empty fields
  60. // will not be serialized.
  61. func (f *Filesystem) SetNilSecretsIfEmpty() {
  62. if f.S3Config.AccessSecret != nil && f.S3Config.AccessSecret.IsEmpty() {
  63. f.S3Config.AccessSecret = nil
  64. }
  65. if f.GCSConfig.Credentials != nil && f.GCSConfig.Credentials.IsEmpty() {
  66. f.GCSConfig.Credentials = nil
  67. }
  68. if f.AzBlobConfig.AccountKey != nil && f.AzBlobConfig.AccountKey.IsEmpty() {
  69. f.AzBlobConfig.AccountKey = nil
  70. }
  71. if f.AzBlobConfig.SASURL != nil && f.AzBlobConfig.SASURL.IsEmpty() {
  72. f.AzBlobConfig.SASURL = nil
  73. }
  74. if f.CryptConfig.Passphrase != nil && f.CryptConfig.Passphrase.IsEmpty() {
  75. f.CryptConfig.Passphrase = nil
  76. }
  77. if f.SFTPConfig.Password != nil && f.SFTPConfig.Password.IsEmpty() {
  78. f.SFTPConfig.Password = nil
  79. }
  80. if f.SFTPConfig.PrivateKey != nil && f.SFTPConfig.PrivateKey.IsEmpty() {
  81. f.SFTPConfig.PrivateKey = nil
  82. }
  83. }
  84. // IsEqual returns true if the fs is equal to other
  85. func (f *Filesystem) IsEqual(other *Filesystem) bool {
  86. if f.Provider != other.Provider {
  87. return false
  88. }
  89. switch f.Provider {
  90. case sdk.S3FilesystemProvider:
  91. return f.S3Config.isEqual(&other.S3Config)
  92. case sdk.GCSFilesystemProvider:
  93. return f.GCSConfig.isEqual(&other.GCSConfig)
  94. case sdk.AzureBlobFilesystemProvider:
  95. return f.AzBlobConfig.isEqual(&other.AzBlobConfig)
  96. case sdk.CryptedFilesystemProvider:
  97. return f.CryptConfig.isEqual(&other.CryptConfig)
  98. case sdk.SFTPFilesystemProvider:
  99. return f.SFTPConfig.isEqual(&other.SFTPConfig)
  100. default:
  101. return true
  102. }
  103. }
  104. // Validate verifies the FsConfig matching the configured provider and sets all other
  105. // Filesystem.*Config to their zero value if successful
  106. func (f *Filesystem) Validate(helper ValidatorHelper) error {
  107. switch f.Provider {
  108. case sdk.S3FilesystemProvider:
  109. if err := f.S3Config.Validate(); err != nil {
  110. return util.NewValidationError(fmt.Sprintf("could not validate s3config: %v", err))
  111. }
  112. if err := f.S3Config.EncryptCredentials(helper.GetEncryptionAdditionalData()); err != nil {
  113. return util.NewValidationError(fmt.Sprintf("could not encrypt s3 access secret: %v", err))
  114. }
  115. f.GCSConfig = GCSFsConfig{}
  116. f.AzBlobConfig = AzBlobFsConfig{}
  117. f.CryptConfig = CryptFsConfig{}
  118. f.SFTPConfig = SFTPFsConfig{}
  119. return nil
  120. case sdk.GCSFilesystemProvider:
  121. if err := f.GCSConfig.Validate(helper.GetGCSCredentialsFilePath()); err != nil {
  122. return util.NewValidationError(fmt.Sprintf("could not validate GCS config: %v", err))
  123. }
  124. f.S3Config = S3FsConfig{}
  125. f.AzBlobConfig = AzBlobFsConfig{}
  126. f.CryptConfig = CryptFsConfig{}
  127. f.SFTPConfig = SFTPFsConfig{}
  128. return nil
  129. case sdk.AzureBlobFilesystemProvider:
  130. if err := f.AzBlobConfig.Validate(); err != nil {
  131. return util.NewValidationError(fmt.Sprintf("could not validate Azure Blob config: %v", err))
  132. }
  133. if err := f.AzBlobConfig.EncryptCredentials(helper.GetEncryptionAdditionalData()); err != nil {
  134. return util.NewValidationError(fmt.Sprintf("could not encrypt Azure blob account key: %v", err))
  135. }
  136. f.S3Config = S3FsConfig{}
  137. f.GCSConfig = GCSFsConfig{}
  138. f.CryptConfig = CryptFsConfig{}
  139. f.SFTPConfig = SFTPFsConfig{}
  140. return nil
  141. case sdk.CryptedFilesystemProvider:
  142. if err := f.CryptConfig.Validate(); err != nil {
  143. return util.NewValidationError(fmt.Sprintf("could not validate Crypt fs config: %v", err))
  144. }
  145. if err := f.CryptConfig.EncryptCredentials(helper.GetEncryptionAdditionalData()); err != nil {
  146. return util.NewValidationError(fmt.Sprintf("could not encrypt Crypt fs passphrase: %v", err))
  147. }
  148. f.S3Config = S3FsConfig{}
  149. f.GCSConfig = GCSFsConfig{}
  150. f.AzBlobConfig = AzBlobFsConfig{}
  151. f.SFTPConfig = SFTPFsConfig{}
  152. return nil
  153. case sdk.SFTPFilesystemProvider:
  154. if err := f.SFTPConfig.Validate(); err != nil {
  155. return util.NewValidationError(fmt.Sprintf("could not validate SFTP fs config: %v", err))
  156. }
  157. if err := f.SFTPConfig.EncryptCredentials(helper.GetEncryptionAdditionalData()); err != nil {
  158. return util.NewValidationError(fmt.Sprintf("could not encrypt SFTP fs credentials: %v", err))
  159. }
  160. f.S3Config = S3FsConfig{}
  161. f.GCSConfig = GCSFsConfig{}
  162. f.AzBlobConfig = AzBlobFsConfig{}
  163. f.CryptConfig = CryptFsConfig{}
  164. return nil
  165. default:
  166. f.Provider = sdk.LocalFilesystemProvider
  167. f.S3Config = S3FsConfig{}
  168. f.GCSConfig = GCSFsConfig{}
  169. f.AzBlobConfig = AzBlobFsConfig{}
  170. f.CryptConfig = CryptFsConfig{}
  171. f.SFTPConfig = SFTPFsConfig{}
  172. return nil
  173. }
  174. }
  175. // HasRedactedSecret returns true if configured the filesystem configuration has a redacted secret
  176. func (f *Filesystem) HasRedactedSecret() bool {
  177. // TODO move vfs specific code into each *FsConfig struct
  178. switch f.Provider {
  179. case sdk.S3FilesystemProvider:
  180. if f.S3Config.AccessSecret.IsRedacted() {
  181. return true
  182. }
  183. case sdk.GCSFilesystemProvider:
  184. if f.GCSConfig.Credentials.IsRedacted() {
  185. return true
  186. }
  187. case sdk.AzureBlobFilesystemProvider:
  188. if f.AzBlobConfig.AccountKey.IsRedacted() {
  189. return true
  190. }
  191. if f.AzBlobConfig.SASURL.IsRedacted() {
  192. return true
  193. }
  194. case sdk.CryptedFilesystemProvider:
  195. if f.CryptConfig.Passphrase.IsRedacted() {
  196. return true
  197. }
  198. case sdk.SFTPFilesystemProvider:
  199. if f.SFTPConfig.Password.IsRedacted() {
  200. return true
  201. }
  202. if f.SFTPConfig.PrivateKey.IsRedacted() {
  203. return true
  204. }
  205. }
  206. return false
  207. }
  208. // HideConfidentialData hides filesystem confidential data
  209. func (f *Filesystem) HideConfidentialData() {
  210. switch f.Provider {
  211. case sdk.S3FilesystemProvider:
  212. f.S3Config.HideConfidentialData()
  213. case sdk.GCSFilesystemProvider:
  214. f.GCSConfig.HideConfidentialData()
  215. case sdk.AzureBlobFilesystemProvider:
  216. f.AzBlobConfig.HideConfidentialData()
  217. case sdk.CryptedFilesystemProvider:
  218. f.CryptConfig.HideConfidentialData()
  219. case sdk.SFTPFilesystemProvider:
  220. f.SFTPConfig.HideConfidentialData()
  221. }
  222. }
  223. // GetACopy returns a filesystem copy
  224. func (f *Filesystem) GetACopy() Filesystem {
  225. f.SetEmptySecretsIfNil()
  226. fs := Filesystem{
  227. Provider: f.Provider,
  228. S3Config: S3FsConfig{
  229. BaseS3FsConfig: sdk.BaseS3FsConfig{
  230. Bucket: f.S3Config.Bucket,
  231. Region: f.S3Config.Region,
  232. AccessKey: f.S3Config.AccessKey,
  233. RoleARN: f.S3Config.RoleARN,
  234. Endpoint: f.S3Config.Endpoint,
  235. StorageClass: f.S3Config.StorageClass,
  236. ACL: f.S3Config.ACL,
  237. KeyPrefix: f.S3Config.KeyPrefix,
  238. UploadPartSize: f.S3Config.UploadPartSize,
  239. UploadConcurrency: f.S3Config.UploadConcurrency,
  240. DownloadPartSize: f.S3Config.DownloadPartSize,
  241. DownloadConcurrency: f.S3Config.DownloadConcurrency,
  242. DownloadPartMaxTime: f.S3Config.DownloadPartMaxTime,
  243. UploadPartMaxTime: f.S3Config.UploadPartMaxTime,
  244. ForcePathStyle: f.S3Config.ForcePathStyle,
  245. },
  246. AccessSecret: f.S3Config.AccessSecret.Clone(),
  247. },
  248. GCSConfig: GCSFsConfig{
  249. BaseGCSFsConfig: sdk.BaseGCSFsConfig{
  250. Bucket: f.GCSConfig.Bucket,
  251. CredentialFile: f.GCSConfig.CredentialFile,
  252. AutomaticCredentials: f.GCSConfig.AutomaticCredentials,
  253. StorageClass: f.GCSConfig.StorageClass,
  254. ACL: f.GCSConfig.ACL,
  255. KeyPrefix: f.GCSConfig.KeyPrefix,
  256. },
  257. Credentials: f.GCSConfig.Credentials.Clone(),
  258. },
  259. AzBlobConfig: AzBlobFsConfig{
  260. BaseAzBlobFsConfig: sdk.BaseAzBlobFsConfig{
  261. Container: f.AzBlobConfig.Container,
  262. AccountName: f.AzBlobConfig.AccountName,
  263. Endpoint: f.AzBlobConfig.Endpoint,
  264. KeyPrefix: f.AzBlobConfig.KeyPrefix,
  265. UploadPartSize: f.AzBlobConfig.UploadPartSize,
  266. UploadConcurrency: f.AzBlobConfig.UploadConcurrency,
  267. DownloadPartSize: f.AzBlobConfig.DownloadPartSize,
  268. DownloadConcurrency: f.AzBlobConfig.DownloadConcurrency,
  269. UseEmulator: f.AzBlobConfig.UseEmulator,
  270. AccessTier: f.AzBlobConfig.AccessTier,
  271. },
  272. AccountKey: f.AzBlobConfig.AccountKey.Clone(),
  273. SASURL: f.AzBlobConfig.SASURL.Clone(),
  274. },
  275. CryptConfig: CryptFsConfig{
  276. Passphrase: f.CryptConfig.Passphrase.Clone(),
  277. },
  278. SFTPConfig: SFTPFsConfig{
  279. BaseSFTPFsConfig: sdk.BaseSFTPFsConfig{
  280. Endpoint: f.SFTPConfig.Endpoint,
  281. Username: f.SFTPConfig.Username,
  282. Prefix: f.SFTPConfig.Prefix,
  283. DisableCouncurrentReads: f.SFTPConfig.DisableCouncurrentReads,
  284. BufferSize: f.SFTPConfig.BufferSize,
  285. },
  286. Password: f.SFTPConfig.Password.Clone(),
  287. PrivateKey: f.SFTPConfig.PrivateKey.Clone(),
  288. },
  289. }
  290. if len(f.SFTPConfig.Fingerprints) > 0 {
  291. fs.SFTPConfig.Fingerprints = make([]string, len(f.SFTPConfig.Fingerprints))
  292. copy(fs.SFTPConfig.Fingerprints, f.SFTPConfig.Fingerprints)
  293. }
  294. return fs
  295. }