filesystem.go 14 KB

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