filesystem.go 13 KB

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