filesystem.go 13 KB

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