filesystem.go 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362
  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 vfs
  15. import (
  16. "github.com/sftpgo/sdk"
  17. "github.com/drakkan/sftpgo/v2/internal/kms"
  18. )
  19. // Filesystem defines filesystem details
  20. type Filesystem struct {
  21. RedactedSecret string `json:"-"`
  22. Provider sdk.FilesystemProvider `json:"provider"`
  23. S3Config S3FsConfig `json:"s3config,omitempty"`
  24. GCSConfig GCSFsConfig `json:"gcsconfig,omitempty"`
  25. AzBlobConfig AzBlobFsConfig `json:"azblobconfig,omitempty"`
  26. CryptConfig CryptFsConfig `json:"cryptconfig,omitempty"`
  27. SFTPConfig SFTPFsConfig `json:"sftpconfig,omitempty"`
  28. HTTPConfig HTTPFsConfig `json:"httpconfig,omitempty"`
  29. }
  30. // SetEmptySecrets sets the secrets to empty
  31. func (f *Filesystem) SetEmptySecrets() {
  32. f.S3Config.AccessSecret = kms.NewEmptySecret()
  33. f.GCSConfig.Credentials = kms.NewEmptySecret()
  34. f.AzBlobConfig.AccountKey = kms.NewEmptySecret()
  35. f.AzBlobConfig.SASURL = kms.NewEmptySecret()
  36. f.CryptConfig.Passphrase = kms.NewEmptySecret()
  37. f.SFTPConfig.Password = kms.NewEmptySecret()
  38. f.SFTPConfig.PrivateKey = kms.NewEmptySecret()
  39. f.SFTPConfig.KeyPassphrase = kms.NewEmptySecret()
  40. f.HTTPConfig.Password = kms.NewEmptySecret()
  41. f.HTTPConfig.APIKey = kms.NewEmptySecret()
  42. }
  43. // SetEmptySecretsIfNil sets the secrets to empty if nil
  44. func (f *Filesystem) SetEmptySecretsIfNil() {
  45. if f.S3Config.AccessSecret == nil {
  46. f.S3Config.AccessSecret = kms.NewEmptySecret()
  47. }
  48. if f.GCSConfig.Credentials == nil {
  49. f.GCSConfig.Credentials = kms.NewEmptySecret()
  50. }
  51. if f.AzBlobConfig.AccountKey == nil {
  52. f.AzBlobConfig.AccountKey = kms.NewEmptySecret()
  53. }
  54. if f.AzBlobConfig.SASURL == nil {
  55. f.AzBlobConfig.SASURL = kms.NewEmptySecret()
  56. }
  57. if f.CryptConfig.Passphrase == nil {
  58. f.CryptConfig.Passphrase = kms.NewEmptySecret()
  59. }
  60. if f.SFTPConfig.Password == nil {
  61. f.SFTPConfig.Password = kms.NewEmptySecret()
  62. }
  63. if f.SFTPConfig.PrivateKey == nil {
  64. f.SFTPConfig.PrivateKey = kms.NewEmptySecret()
  65. }
  66. if f.SFTPConfig.KeyPassphrase == nil {
  67. f.SFTPConfig.KeyPassphrase = kms.NewEmptySecret()
  68. }
  69. if f.HTTPConfig.Password == nil {
  70. f.HTTPConfig.Password = kms.NewEmptySecret()
  71. }
  72. if f.HTTPConfig.APIKey == nil {
  73. f.HTTPConfig.APIKey = kms.NewEmptySecret()
  74. }
  75. }
  76. // SetNilSecretsIfEmpty set the secrets to nil if empty.
  77. // This is useful before rendering as JSON so the empty fields
  78. // will not be serialized.
  79. func (f *Filesystem) SetNilSecretsIfEmpty() {
  80. if f.S3Config.AccessSecret != nil && f.S3Config.AccessSecret.IsEmpty() {
  81. f.S3Config.AccessSecret = nil
  82. }
  83. if f.GCSConfig.Credentials != nil && f.GCSConfig.Credentials.IsEmpty() {
  84. f.GCSConfig.Credentials = nil
  85. }
  86. if f.AzBlobConfig.AccountKey != nil && f.AzBlobConfig.AccountKey.IsEmpty() {
  87. f.AzBlobConfig.AccountKey = nil
  88. }
  89. if f.AzBlobConfig.SASURL != nil && f.AzBlobConfig.SASURL.IsEmpty() {
  90. f.AzBlobConfig.SASURL = nil
  91. }
  92. if f.CryptConfig.Passphrase != nil && f.CryptConfig.Passphrase.IsEmpty() {
  93. f.CryptConfig.Passphrase = nil
  94. }
  95. f.SFTPConfig.setNilSecretsIfEmpty()
  96. f.HTTPConfig.setNilSecretsIfEmpty()
  97. }
  98. // IsEqual returns true if the fs is equal to other
  99. func (f *Filesystem) IsEqual(other Filesystem) bool {
  100. if f.Provider != other.Provider {
  101. return false
  102. }
  103. switch f.Provider {
  104. case sdk.S3FilesystemProvider:
  105. return f.S3Config.isEqual(other.S3Config)
  106. case sdk.GCSFilesystemProvider:
  107. return f.GCSConfig.isEqual(other.GCSConfig)
  108. case sdk.AzureBlobFilesystemProvider:
  109. return f.AzBlobConfig.isEqual(other.AzBlobConfig)
  110. case sdk.CryptedFilesystemProvider:
  111. return f.CryptConfig.isEqual(other.CryptConfig)
  112. case sdk.SFTPFilesystemProvider:
  113. return f.SFTPConfig.isEqual(other.SFTPConfig)
  114. case sdk.HTTPFilesystemProvider:
  115. return f.HTTPConfig.isEqual(other.HTTPConfig)
  116. default:
  117. return true
  118. }
  119. }
  120. // IsSameResource returns true if fs point to the same resource as other
  121. func (f *Filesystem) IsSameResource(other Filesystem) bool {
  122. if f.Provider != other.Provider {
  123. return false
  124. }
  125. switch f.Provider {
  126. case sdk.S3FilesystemProvider:
  127. return f.S3Config.isSameResource(other.S3Config)
  128. case sdk.GCSFilesystemProvider:
  129. return f.GCSConfig.isSameResource(other.GCSConfig)
  130. case sdk.AzureBlobFilesystemProvider:
  131. return f.AzBlobConfig.isSameResource(other.AzBlobConfig)
  132. case sdk.CryptedFilesystemProvider:
  133. return f.CryptConfig.isSameResource(other.CryptConfig)
  134. case sdk.SFTPFilesystemProvider:
  135. return f.SFTPConfig.isSameResource(other.SFTPConfig)
  136. case sdk.HTTPFilesystemProvider:
  137. return f.HTTPConfig.isSameResource(other.HTTPConfig)
  138. default:
  139. return true
  140. }
  141. }
  142. // Validate verifies the FsConfig matching the configured provider and sets all other
  143. // Filesystem.*Config to their zero value if successful
  144. func (f *Filesystem) Validate(additionalData string) error {
  145. switch f.Provider {
  146. case sdk.S3FilesystemProvider:
  147. if err := f.S3Config.ValidateAndEncryptCredentials(additionalData); err != nil {
  148. return err
  149. }
  150. f.GCSConfig = GCSFsConfig{}
  151. f.AzBlobConfig = AzBlobFsConfig{}
  152. f.CryptConfig = CryptFsConfig{}
  153. f.SFTPConfig = SFTPFsConfig{}
  154. f.HTTPConfig = HTTPFsConfig{}
  155. return nil
  156. case sdk.GCSFilesystemProvider:
  157. if err := f.GCSConfig.ValidateAndEncryptCredentials(additionalData); err != nil {
  158. return err
  159. }
  160. f.S3Config = S3FsConfig{}
  161. f.AzBlobConfig = AzBlobFsConfig{}
  162. f.CryptConfig = CryptFsConfig{}
  163. f.SFTPConfig = SFTPFsConfig{}
  164. f.HTTPConfig = HTTPFsConfig{}
  165. return nil
  166. case sdk.AzureBlobFilesystemProvider:
  167. if err := f.AzBlobConfig.ValidateAndEncryptCredentials(additionalData); err != nil {
  168. return err
  169. }
  170. f.S3Config = S3FsConfig{}
  171. f.GCSConfig = GCSFsConfig{}
  172. f.CryptConfig = CryptFsConfig{}
  173. f.SFTPConfig = SFTPFsConfig{}
  174. f.HTTPConfig = HTTPFsConfig{}
  175. return nil
  176. case sdk.CryptedFilesystemProvider:
  177. if err := f.CryptConfig.ValidateAndEncryptCredentials(additionalData); err != nil {
  178. return err
  179. }
  180. f.S3Config = S3FsConfig{}
  181. f.GCSConfig = GCSFsConfig{}
  182. f.AzBlobConfig = AzBlobFsConfig{}
  183. f.SFTPConfig = SFTPFsConfig{}
  184. f.HTTPConfig = HTTPFsConfig{}
  185. return nil
  186. case sdk.SFTPFilesystemProvider:
  187. if err := f.SFTPConfig.ValidateAndEncryptCredentials(additionalData); err != nil {
  188. return err
  189. }
  190. f.S3Config = S3FsConfig{}
  191. f.GCSConfig = GCSFsConfig{}
  192. f.AzBlobConfig = AzBlobFsConfig{}
  193. f.CryptConfig = CryptFsConfig{}
  194. f.HTTPConfig = HTTPFsConfig{}
  195. return nil
  196. case sdk.HTTPFilesystemProvider:
  197. if err := f.HTTPConfig.ValidateAndEncryptCredentials(additionalData); err != nil {
  198. return err
  199. }
  200. f.S3Config = S3FsConfig{}
  201. f.GCSConfig = GCSFsConfig{}
  202. f.AzBlobConfig = AzBlobFsConfig{}
  203. f.CryptConfig = CryptFsConfig{}
  204. f.SFTPConfig = SFTPFsConfig{}
  205. return nil
  206. default:
  207. f.Provider = sdk.LocalFilesystemProvider
  208. f.S3Config = S3FsConfig{}
  209. f.GCSConfig = GCSFsConfig{}
  210. f.AzBlobConfig = AzBlobFsConfig{}
  211. f.CryptConfig = CryptFsConfig{}
  212. f.SFTPConfig = SFTPFsConfig{}
  213. f.HTTPConfig = HTTPFsConfig{}
  214. return nil
  215. }
  216. }
  217. // HasRedactedSecret returns true if configured the filesystem configuration has a redacted secret
  218. func (f *Filesystem) HasRedactedSecret() bool {
  219. // TODO move vfs specific code into each *FsConfig struct
  220. switch f.Provider {
  221. case sdk.S3FilesystemProvider:
  222. return f.S3Config.AccessSecret.IsRedacted()
  223. case sdk.GCSFilesystemProvider:
  224. return f.GCSConfig.Credentials.IsRedacted()
  225. case sdk.AzureBlobFilesystemProvider:
  226. if f.AzBlobConfig.AccountKey.IsRedacted() {
  227. return true
  228. }
  229. return f.AzBlobConfig.SASURL.IsRedacted()
  230. case sdk.CryptedFilesystemProvider:
  231. return f.CryptConfig.Passphrase.IsRedacted()
  232. case sdk.SFTPFilesystemProvider:
  233. if f.SFTPConfig.Password.IsRedacted() {
  234. return true
  235. }
  236. if f.SFTPConfig.PrivateKey.IsRedacted() {
  237. return true
  238. }
  239. return f.SFTPConfig.KeyPassphrase.IsRedacted()
  240. case sdk.HTTPFilesystemProvider:
  241. if f.HTTPConfig.Password.IsRedacted() {
  242. return true
  243. }
  244. return f.HTTPConfig.APIKey.IsRedacted()
  245. }
  246. return false
  247. }
  248. // HideConfidentialData hides filesystem confidential data
  249. func (f *Filesystem) HideConfidentialData() {
  250. switch f.Provider {
  251. case sdk.S3FilesystemProvider:
  252. f.S3Config.HideConfidentialData()
  253. case sdk.GCSFilesystemProvider:
  254. f.GCSConfig.HideConfidentialData()
  255. case sdk.AzureBlobFilesystemProvider:
  256. f.AzBlobConfig.HideConfidentialData()
  257. case sdk.CryptedFilesystemProvider:
  258. f.CryptConfig.HideConfidentialData()
  259. case sdk.SFTPFilesystemProvider:
  260. f.SFTPConfig.HideConfidentialData()
  261. case sdk.HTTPFilesystemProvider:
  262. f.HTTPConfig.HideConfidentialData()
  263. }
  264. }
  265. // GetACopy returns a filesystem copy
  266. func (f *Filesystem) GetACopy() Filesystem {
  267. f.SetEmptySecretsIfNil()
  268. fs := Filesystem{
  269. Provider: f.Provider,
  270. S3Config: S3FsConfig{
  271. BaseS3FsConfig: sdk.BaseS3FsConfig{
  272. Bucket: f.S3Config.Bucket,
  273. Region: f.S3Config.Region,
  274. AccessKey: f.S3Config.AccessKey,
  275. RoleARN: f.S3Config.RoleARN,
  276. Endpoint: f.S3Config.Endpoint,
  277. StorageClass: f.S3Config.StorageClass,
  278. ACL: f.S3Config.ACL,
  279. KeyPrefix: f.S3Config.KeyPrefix,
  280. UploadPartSize: f.S3Config.UploadPartSize,
  281. UploadConcurrency: f.S3Config.UploadConcurrency,
  282. DownloadPartSize: f.S3Config.DownloadPartSize,
  283. DownloadConcurrency: f.S3Config.DownloadConcurrency,
  284. DownloadPartMaxTime: f.S3Config.DownloadPartMaxTime,
  285. UploadPartMaxTime: f.S3Config.UploadPartMaxTime,
  286. ForcePathStyle: f.S3Config.ForcePathStyle,
  287. },
  288. AccessSecret: f.S3Config.AccessSecret.Clone(),
  289. },
  290. GCSConfig: GCSFsConfig{
  291. BaseGCSFsConfig: sdk.BaseGCSFsConfig{
  292. Bucket: f.GCSConfig.Bucket,
  293. AutomaticCredentials: f.GCSConfig.AutomaticCredentials,
  294. StorageClass: f.GCSConfig.StorageClass,
  295. ACL: f.GCSConfig.ACL,
  296. KeyPrefix: f.GCSConfig.KeyPrefix,
  297. },
  298. Credentials: f.GCSConfig.Credentials.Clone(),
  299. },
  300. AzBlobConfig: AzBlobFsConfig{
  301. BaseAzBlobFsConfig: sdk.BaseAzBlobFsConfig{
  302. Container: f.AzBlobConfig.Container,
  303. AccountName: f.AzBlobConfig.AccountName,
  304. Endpoint: f.AzBlobConfig.Endpoint,
  305. KeyPrefix: f.AzBlobConfig.KeyPrefix,
  306. UploadPartSize: f.AzBlobConfig.UploadPartSize,
  307. UploadConcurrency: f.AzBlobConfig.UploadConcurrency,
  308. DownloadPartSize: f.AzBlobConfig.DownloadPartSize,
  309. DownloadConcurrency: f.AzBlobConfig.DownloadConcurrency,
  310. UseEmulator: f.AzBlobConfig.UseEmulator,
  311. AccessTier: f.AzBlobConfig.AccessTier,
  312. },
  313. AccountKey: f.AzBlobConfig.AccountKey.Clone(),
  314. SASURL: f.AzBlobConfig.SASURL.Clone(),
  315. },
  316. CryptConfig: CryptFsConfig{
  317. Passphrase: f.CryptConfig.Passphrase.Clone(),
  318. },
  319. SFTPConfig: SFTPFsConfig{
  320. BaseSFTPFsConfig: sdk.BaseSFTPFsConfig{
  321. Endpoint: f.SFTPConfig.Endpoint,
  322. Username: f.SFTPConfig.Username,
  323. Prefix: f.SFTPConfig.Prefix,
  324. DisableCouncurrentReads: f.SFTPConfig.DisableCouncurrentReads,
  325. BufferSize: f.SFTPConfig.BufferSize,
  326. EqualityCheckMode: f.SFTPConfig.EqualityCheckMode,
  327. },
  328. Password: f.SFTPConfig.Password.Clone(),
  329. PrivateKey: f.SFTPConfig.PrivateKey.Clone(),
  330. KeyPassphrase: f.SFTPConfig.KeyPassphrase.Clone(),
  331. },
  332. HTTPConfig: HTTPFsConfig{
  333. BaseHTTPFsConfig: sdk.BaseHTTPFsConfig{
  334. Endpoint: f.HTTPConfig.Endpoint,
  335. Username: f.HTTPConfig.Username,
  336. SkipTLSVerify: f.HTTPConfig.SkipTLSVerify,
  337. EqualityCheckMode: f.HTTPConfig.EqualityCheckMode,
  338. },
  339. Password: f.HTTPConfig.Password.Clone(),
  340. APIKey: f.HTTPConfig.APIKey.Clone(),
  341. },
  342. }
  343. if len(f.SFTPConfig.Fingerprints) > 0 {
  344. fs.SFTPConfig.Fingerprints = make([]string, len(f.SFTPConfig.Fingerprints))
  345. copy(fs.SFTPConfig.Fingerprints, f.SFTPConfig.Fingerprints)
  346. }
  347. return fs
  348. }