webadmin.go 62 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002
  1. package httpd
  2. import (
  3. "errors"
  4. "fmt"
  5. "html/template"
  6. "io"
  7. "net/http"
  8. "net/url"
  9. "os"
  10. "path/filepath"
  11. "strconv"
  12. "strings"
  13. "time"
  14. "github.com/go-chi/render"
  15. "github.com/sftpgo/sdk"
  16. sdkkms "github.com/sftpgo/sdk/kms"
  17. "github.com/drakkan/sftpgo/v2/common"
  18. "github.com/drakkan/sftpgo/v2/dataprovider"
  19. "github.com/drakkan/sftpgo/v2/kms"
  20. "github.com/drakkan/sftpgo/v2/mfa"
  21. "github.com/drakkan/sftpgo/v2/smtp"
  22. "github.com/drakkan/sftpgo/v2/util"
  23. "github.com/drakkan/sftpgo/v2/version"
  24. "github.com/drakkan/sftpgo/v2/vfs"
  25. )
  26. type userPageMode int
  27. const (
  28. userPageModeAdd userPageMode = iota + 1
  29. userPageModeUpdate
  30. userPageModeTemplate
  31. )
  32. type folderPageMode int
  33. const (
  34. folderPageModeAdd folderPageMode = iota + 1
  35. folderPageModeUpdate
  36. folderPageModeTemplate
  37. )
  38. const (
  39. templateAdminDir = "webadmin"
  40. templateBase = "base.html"
  41. templateBaseLogin = "baselogin.html"
  42. templateFsConfig = "fsconfig.html"
  43. templateUsers = "users.html"
  44. templateUser = "user.html"
  45. templateAdmins = "admins.html"
  46. templateAdmin = "admin.html"
  47. templateConnections = "connections.html"
  48. templateFolders = "folders.html"
  49. templateFolder = "folder.html"
  50. templateMessage = "message.html"
  51. templateStatus = "status.html"
  52. templateLogin = "login.html"
  53. templateDefender = "defender.html"
  54. templateProfile = "profile.html"
  55. templateChangePwd = "changepassword.html"
  56. templateMaintenance = "maintenance.html"
  57. templateMFA = "mfa.html"
  58. templateSetup = "adminsetup.html"
  59. pageUsersTitle = "Users"
  60. pageAdminsTitle = "Admins"
  61. pageConnectionsTitle = "Connections"
  62. pageStatusTitle = "Status"
  63. pageFoldersTitle = "Folders"
  64. pageProfileTitle = "My profile"
  65. pageChangePwdTitle = "Change password"
  66. pageMaintenanceTitle = "Maintenance"
  67. pageDefenderTitle = "Defender"
  68. pageForgotPwdTitle = "SFTPGo Admin - Forgot password"
  69. pageResetPwdTitle = "SFTPGo Admin - Reset password"
  70. pageSetupTitle = "Create first admin user"
  71. defaultQueryLimit = 500
  72. )
  73. var (
  74. adminTemplates = make(map[string]*template.Template)
  75. )
  76. type basePage struct {
  77. Title string
  78. CurrentURL string
  79. UsersURL string
  80. UserURL string
  81. UserTemplateURL string
  82. AdminsURL string
  83. AdminURL string
  84. QuotaScanURL string
  85. ConnectionsURL string
  86. FoldersURL string
  87. FolderURL string
  88. FolderTemplateURL string
  89. DefenderURL string
  90. LogoutURL string
  91. ProfileURL string
  92. ChangePwdURL string
  93. MFAURL string
  94. FolderQuotaScanURL string
  95. StatusURL string
  96. MaintenanceURL string
  97. StaticURL string
  98. UsersTitle string
  99. AdminsTitle string
  100. ConnectionsTitle string
  101. FoldersTitle string
  102. StatusTitle string
  103. MaintenanceTitle string
  104. DefenderTitle string
  105. Version string
  106. CSRFToken string
  107. HasDefender bool
  108. LoggedAdmin *dataprovider.Admin
  109. }
  110. type usersPage struct {
  111. basePage
  112. Users []dataprovider.User
  113. }
  114. type adminsPage struct {
  115. basePage
  116. Admins []dataprovider.Admin
  117. }
  118. type foldersPage struct {
  119. basePage
  120. Folders []vfs.BaseVirtualFolder
  121. }
  122. type connectionsPage struct {
  123. basePage
  124. Connections []*common.ConnectionStatus
  125. }
  126. type statusPage struct {
  127. basePage
  128. Status ServicesStatus
  129. }
  130. type fsWrapper struct {
  131. vfs.Filesystem
  132. IsUserPage bool
  133. HasUsersBaseDir bool
  134. DirPath string
  135. }
  136. type userPage struct {
  137. basePage
  138. User *dataprovider.User
  139. RootPerms []string
  140. Error string
  141. ValidPerms []string
  142. ValidLoginMethods []string
  143. ValidProtocols []string
  144. WebClientOptions []string
  145. RootDirPerms []string
  146. RedactedSecret string
  147. Mode userPageMode
  148. VirtualFolders []vfs.BaseVirtualFolder
  149. CanImpersonate bool
  150. FsWrapper fsWrapper
  151. }
  152. type adminPage struct {
  153. basePage
  154. Admin *dataprovider.Admin
  155. Error string
  156. IsAdd bool
  157. }
  158. type profilePage struct {
  159. basePage
  160. Error string
  161. AllowAPIKeyAuth bool
  162. Email string
  163. Description string
  164. }
  165. type changePasswordPage struct {
  166. basePage
  167. Error string
  168. }
  169. type mfaPage struct {
  170. basePage
  171. TOTPConfigs []string
  172. TOTPConfig dataprovider.AdminTOTPConfig
  173. GenerateTOTPURL string
  174. ValidateTOTPURL string
  175. SaveTOTPURL string
  176. RecCodesURL string
  177. }
  178. type maintenancePage struct {
  179. basePage
  180. BackupPath string
  181. RestorePath string
  182. Error string
  183. }
  184. type defenderHostsPage struct {
  185. basePage
  186. DefenderHostsURL string
  187. }
  188. type setupPage struct {
  189. basePage
  190. Username string
  191. Error string
  192. }
  193. type folderPage struct {
  194. basePage
  195. Folder vfs.BaseVirtualFolder
  196. Error string
  197. Mode folderPageMode
  198. FsWrapper fsWrapper
  199. }
  200. type messagePage struct {
  201. basePage
  202. Error string
  203. Success string
  204. }
  205. type userTemplateFields struct {
  206. Username string
  207. Password string
  208. PublicKey string
  209. }
  210. func loadAdminTemplates(templatesPath string) {
  211. usersPaths := []string{
  212. filepath.Join(templatesPath, templateAdminDir, templateBase),
  213. filepath.Join(templatesPath, templateAdminDir, templateUsers),
  214. }
  215. userPaths := []string{
  216. filepath.Join(templatesPath, templateAdminDir, templateBase),
  217. filepath.Join(templatesPath, templateAdminDir, templateFsConfig),
  218. filepath.Join(templatesPath, templateAdminDir, templateUser),
  219. }
  220. adminsPaths := []string{
  221. filepath.Join(templatesPath, templateAdminDir, templateBase),
  222. filepath.Join(templatesPath, templateAdminDir, templateAdmins),
  223. }
  224. adminPaths := []string{
  225. filepath.Join(templatesPath, templateAdminDir, templateBase),
  226. filepath.Join(templatesPath, templateAdminDir, templateAdmin),
  227. }
  228. profilePaths := []string{
  229. filepath.Join(templatesPath, templateAdminDir, templateBase),
  230. filepath.Join(templatesPath, templateAdminDir, templateProfile),
  231. }
  232. changePwdPaths := []string{
  233. filepath.Join(templatesPath, templateAdminDir, templateBase),
  234. filepath.Join(templatesPath, templateAdminDir, templateChangePwd),
  235. }
  236. connectionsPaths := []string{
  237. filepath.Join(templatesPath, templateAdminDir, templateBase),
  238. filepath.Join(templatesPath, templateAdminDir, templateConnections),
  239. }
  240. messagePaths := []string{
  241. filepath.Join(templatesPath, templateAdminDir, templateBase),
  242. filepath.Join(templatesPath, templateAdminDir, templateMessage),
  243. }
  244. foldersPaths := []string{
  245. filepath.Join(templatesPath, templateAdminDir, templateBase),
  246. filepath.Join(templatesPath, templateAdminDir, templateFolders),
  247. }
  248. folderPaths := []string{
  249. filepath.Join(templatesPath, templateAdminDir, templateBase),
  250. filepath.Join(templatesPath, templateAdminDir, templateFsConfig),
  251. filepath.Join(templatesPath, templateAdminDir, templateFolder),
  252. }
  253. statusPaths := []string{
  254. filepath.Join(templatesPath, templateAdminDir, templateBase),
  255. filepath.Join(templatesPath, templateAdminDir, templateStatus),
  256. }
  257. loginPaths := []string{
  258. filepath.Join(templatesPath, templateAdminDir, templateBaseLogin),
  259. filepath.Join(templatesPath, templateAdminDir, templateLogin),
  260. }
  261. maintenancePaths := []string{
  262. filepath.Join(templatesPath, templateAdminDir, templateBase),
  263. filepath.Join(templatesPath, templateAdminDir, templateMaintenance),
  264. }
  265. defenderPaths := []string{
  266. filepath.Join(templatesPath, templateAdminDir, templateBase),
  267. filepath.Join(templatesPath, templateAdminDir, templateDefender),
  268. }
  269. mfaPaths := []string{
  270. filepath.Join(templatesPath, templateAdminDir, templateBase),
  271. filepath.Join(templatesPath, templateAdminDir, templateMFA),
  272. }
  273. twoFactorPaths := []string{
  274. filepath.Join(templatesPath, templateAdminDir, templateBaseLogin),
  275. filepath.Join(templatesPath, templateAdminDir, templateTwoFactor),
  276. }
  277. twoFactorRecoveryPaths := []string{
  278. filepath.Join(templatesPath, templateAdminDir, templateBaseLogin),
  279. filepath.Join(templatesPath, templateAdminDir, templateTwoFactorRecovery),
  280. }
  281. setupPaths := []string{
  282. filepath.Join(templatesPath, templateAdminDir, templateBaseLogin),
  283. filepath.Join(templatesPath, templateAdminDir, templateSetup),
  284. }
  285. forgotPwdPaths := []string{
  286. filepath.Join(templatesPath, templateCommonDir, templateForgotPassword),
  287. }
  288. resetPwdPaths := []string{
  289. filepath.Join(templatesPath, templateCommonDir, templateResetPassword),
  290. }
  291. fsBaseTpl := template.New("fsBaseTemplate").Funcs(template.FuncMap{
  292. "ListFSProviders": func() []sdk.FilesystemProvider {
  293. return []sdk.FilesystemProvider{sdk.LocalFilesystemProvider, sdk.CryptedFilesystemProvider,
  294. sdk.S3FilesystemProvider, sdk.GCSFilesystemProvider,
  295. sdk.AzureBlobFilesystemProvider, sdk.SFTPFilesystemProvider,
  296. }
  297. },
  298. })
  299. usersTmpl := util.LoadTemplate(nil, usersPaths...)
  300. userTmpl := util.LoadTemplate(fsBaseTpl, userPaths...)
  301. adminsTmpl := util.LoadTemplate(nil, adminsPaths...)
  302. adminTmpl := util.LoadTemplate(nil, adminPaths...)
  303. connectionsTmpl := util.LoadTemplate(nil, connectionsPaths...)
  304. messageTmpl := util.LoadTemplate(nil, messagePaths...)
  305. foldersTmpl := util.LoadTemplate(nil, foldersPaths...)
  306. folderTmpl := util.LoadTemplate(fsBaseTpl, folderPaths...)
  307. statusTmpl := util.LoadTemplate(nil, statusPaths...)
  308. loginTmpl := util.LoadTemplate(nil, loginPaths...)
  309. profileTmpl := util.LoadTemplate(nil, profilePaths...)
  310. changePwdTmpl := util.LoadTemplate(nil, changePwdPaths...)
  311. maintenanceTmpl := util.LoadTemplate(nil, maintenancePaths...)
  312. defenderTmpl := util.LoadTemplate(nil, defenderPaths...)
  313. mfaTmpl := util.LoadTemplate(nil, mfaPaths...)
  314. twoFactorTmpl := util.LoadTemplate(nil, twoFactorPaths...)
  315. twoFactorRecoveryTmpl := util.LoadTemplate(nil, twoFactorRecoveryPaths...)
  316. setupTmpl := util.LoadTemplate(nil, setupPaths...)
  317. forgotPwdTmpl := util.LoadTemplate(nil, forgotPwdPaths...)
  318. resetPwdTmpl := util.LoadTemplate(nil, resetPwdPaths...)
  319. adminTemplates[templateUsers] = usersTmpl
  320. adminTemplates[templateUser] = userTmpl
  321. adminTemplates[templateAdmins] = adminsTmpl
  322. adminTemplates[templateAdmin] = adminTmpl
  323. adminTemplates[templateConnections] = connectionsTmpl
  324. adminTemplates[templateMessage] = messageTmpl
  325. adminTemplates[templateFolders] = foldersTmpl
  326. adminTemplates[templateFolder] = folderTmpl
  327. adminTemplates[templateStatus] = statusTmpl
  328. adminTemplates[templateLogin] = loginTmpl
  329. adminTemplates[templateProfile] = profileTmpl
  330. adminTemplates[templateChangePwd] = changePwdTmpl
  331. adminTemplates[templateMaintenance] = maintenanceTmpl
  332. adminTemplates[templateDefender] = defenderTmpl
  333. adminTemplates[templateMFA] = mfaTmpl
  334. adminTemplates[templateTwoFactor] = twoFactorTmpl
  335. adminTemplates[templateTwoFactorRecovery] = twoFactorRecoveryTmpl
  336. adminTemplates[templateSetup] = setupTmpl
  337. adminTemplates[templateForgotPassword] = forgotPwdTmpl
  338. adminTemplates[templateResetPassword] = resetPwdTmpl
  339. }
  340. func getBasePageData(title, currentURL string, r *http.Request) basePage {
  341. var csrfToken string
  342. if currentURL != "" {
  343. csrfToken = createCSRFToken()
  344. }
  345. return basePage{
  346. Title: title,
  347. CurrentURL: currentURL,
  348. UsersURL: webUsersPath,
  349. UserURL: webUserPath,
  350. UserTemplateURL: webTemplateUser,
  351. AdminsURL: webAdminsPath,
  352. AdminURL: webAdminPath,
  353. FoldersURL: webFoldersPath,
  354. FolderURL: webFolderPath,
  355. FolderTemplateURL: webTemplateFolder,
  356. DefenderURL: webDefenderPath,
  357. LogoutURL: webLogoutPath,
  358. ProfileURL: webAdminProfilePath,
  359. ChangePwdURL: webChangeAdminPwdPath,
  360. MFAURL: webAdminMFAPath,
  361. QuotaScanURL: webQuotaScanPath,
  362. ConnectionsURL: webConnectionsPath,
  363. StatusURL: webStatusPath,
  364. FolderQuotaScanURL: webScanVFolderPath,
  365. MaintenanceURL: webMaintenancePath,
  366. StaticURL: webStaticFilesPath,
  367. UsersTitle: pageUsersTitle,
  368. AdminsTitle: pageAdminsTitle,
  369. ConnectionsTitle: pageConnectionsTitle,
  370. FoldersTitle: pageFoldersTitle,
  371. StatusTitle: pageStatusTitle,
  372. MaintenanceTitle: pageMaintenanceTitle,
  373. DefenderTitle: pageDefenderTitle,
  374. Version: version.GetAsString(),
  375. LoggedAdmin: getAdminFromToken(r),
  376. HasDefender: common.Config.DefenderConfig.Enabled,
  377. CSRFToken: csrfToken,
  378. }
  379. }
  380. func renderAdminTemplate(w http.ResponseWriter, tmplName string, data interface{}) {
  381. err := adminTemplates[tmplName].ExecuteTemplate(w, tmplName, data)
  382. if err != nil {
  383. http.Error(w, err.Error(), http.StatusInternalServerError)
  384. }
  385. }
  386. func renderMessagePage(w http.ResponseWriter, r *http.Request, title, body string, statusCode int, err error, message string) {
  387. var errorString string
  388. if body != "" {
  389. errorString = body + " "
  390. }
  391. if err != nil {
  392. errorString += err.Error()
  393. }
  394. data := messagePage{
  395. basePage: getBasePageData(title, "", r),
  396. Error: errorString,
  397. Success: message,
  398. }
  399. w.WriteHeader(statusCode)
  400. renderAdminTemplate(w, templateMessage, data)
  401. }
  402. func renderInternalServerErrorPage(w http.ResponseWriter, r *http.Request, err error) {
  403. renderMessagePage(w, r, page500Title, page500Body, http.StatusInternalServerError, err, "")
  404. }
  405. func renderBadRequestPage(w http.ResponseWriter, r *http.Request, err error) {
  406. renderMessagePage(w, r, page400Title, "", http.StatusBadRequest, err, "")
  407. }
  408. func renderForbiddenPage(w http.ResponseWriter, r *http.Request, body string) {
  409. renderMessagePage(w, r, page403Title, "", http.StatusForbidden, nil, body)
  410. }
  411. func renderNotFoundPage(w http.ResponseWriter, r *http.Request, err error) {
  412. renderMessagePage(w, r, page404Title, page404Body, http.StatusNotFound, err, "")
  413. }
  414. func renderForgotPwdPage(w http.ResponseWriter, error string) {
  415. data := forgotPwdPage{
  416. CurrentURL: webAdminForgotPwdPath,
  417. Error: error,
  418. CSRFToken: createCSRFToken(),
  419. StaticURL: webStaticFilesPath,
  420. Title: pageForgotPwdTitle,
  421. }
  422. renderAdminTemplate(w, templateForgotPassword, data)
  423. }
  424. func renderResetPwdPage(w http.ResponseWriter, error string) {
  425. data := resetPwdPage{
  426. CurrentURL: webAdminResetPwdPath,
  427. Error: error,
  428. CSRFToken: createCSRFToken(),
  429. StaticURL: webStaticFilesPath,
  430. Title: pageResetPwdTitle,
  431. }
  432. renderAdminTemplate(w, templateResetPassword, data)
  433. }
  434. func renderTwoFactorPage(w http.ResponseWriter, error string) {
  435. data := twoFactorPage{
  436. CurrentURL: webAdminTwoFactorPath,
  437. Version: version.Get().Version,
  438. Error: error,
  439. CSRFToken: createCSRFToken(),
  440. StaticURL: webStaticFilesPath,
  441. RecoveryURL: webAdminTwoFactorRecoveryPath,
  442. }
  443. renderAdminTemplate(w, templateTwoFactor, data)
  444. }
  445. func renderTwoFactorRecoveryPage(w http.ResponseWriter, error string) {
  446. data := twoFactorPage{
  447. CurrentURL: webAdminTwoFactorRecoveryPath,
  448. Version: version.Get().Version,
  449. Error: error,
  450. CSRFToken: createCSRFToken(),
  451. StaticURL: webStaticFilesPath,
  452. }
  453. renderAdminTemplate(w, templateTwoFactorRecovery, data)
  454. }
  455. func renderMFAPage(w http.ResponseWriter, r *http.Request) {
  456. data := mfaPage{
  457. basePage: getBasePageData(pageMFATitle, webAdminMFAPath, r),
  458. TOTPConfigs: mfa.GetAvailableTOTPConfigNames(),
  459. GenerateTOTPURL: webAdminTOTPGeneratePath,
  460. ValidateTOTPURL: webAdminTOTPValidatePath,
  461. SaveTOTPURL: webAdminTOTPSavePath,
  462. RecCodesURL: webAdminRecoveryCodesPath,
  463. }
  464. admin, err := dataprovider.AdminExists(data.LoggedAdmin.Username)
  465. if err != nil {
  466. renderInternalServerErrorPage(w, r, err)
  467. return
  468. }
  469. data.TOTPConfig = admin.Filters.TOTPConfig
  470. renderAdminTemplate(w, templateMFA, data)
  471. }
  472. func renderProfilePage(w http.ResponseWriter, r *http.Request, error string) {
  473. data := profilePage{
  474. basePage: getBasePageData(pageProfileTitle, webAdminProfilePath, r),
  475. Error: error,
  476. }
  477. admin, err := dataprovider.AdminExists(data.LoggedAdmin.Username)
  478. if err != nil {
  479. renderInternalServerErrorPage(w, r, err)
  480. return
  481. }
  482. data.AllowAPIKeyAuth = admin.Filters.AllowAPIKeyAuth
  483. data.Email = admin.Email
  484. data.Description = admin.Description
  485. renderAdminTemplate(w, templateProfile, data)
  486. }
  487. func renderChangePasswordPage(w http.ResponseWriter, r *http.Request, error string) {
  488. data := changePasswordPage{
  489. basePage: getBasePageData(pageChangePwdTitle, webChangeAdminPwdPath, r),
  490. Error: error,
  491. }
  492. renderAdminTemplate(w, templateChangePwd, data)
  493. }
  494. func renderMaintenancePage(w http.ResponseWriter, r *http.Request, error string) {
  495. data := maintenancePage{
  496. basePage: getBasePageData(pageMaintenanceTitle, webMaintenancePath, r),
  497. BackupPath: webBackupPath,
  498. RestorePath: webRestorePath,
  499. Error: error,
  500. }
  501. renderAdminTemplate(w, templateMaintenance, data)
  502. }
  503. func renderAdminSetupPage(w http.ResponseWriter, r *http.Request, username, error string) {
  504. data := setupPage{
  505. basePage: getBasePageData(pageSetupTitle, webAdminSetupPath, r),
  506. Username: username,
  507. Error: error,
  508. }
  509. renderAdminTemplate(w, templateSetup, data)
  510. }
  511. func renderAddUpdateAdminPage(w http.ResponseWriter, r *http.Request, admin *dataprovider.Admin,
  512. error string, isAdd bool) {
  513. currentURL := webAdminPath
  514. title := "Add a new admin"
  515. if !isAdd {
  516. currentURL = fmt.Sprintf("%v/%v", webAdminPath, url.PathEscape(admin.Username))
  517. title = "Update admin"
  518. }
  519. data := adminPage{
  520. basePage: getBasePageData(title, currentURL, r),
  521. Admin: admin,
  522. Error: error,
  523. IsAdd: isAdd,
  524. }
  525. renderAdminTemplate(w, templateAdmin, data)
  526. }
  527. func renderUserPage(w http.ResponseWriter, r *http.Request, user *dataprovider.User, mode userPageMode, error string) {
  528. folders, err := getWebVirtualFolders(w, r, defaultQueryLimit)
  529. if err != nil {
  530. return
  531. }
  532. user.SetEmptySecretsIfNil()
  533. var title, currentURL string
  534. switch mode {
  535. case userPageModeAdd:
  536. title = "Add a new user"
  537. currentURL = webUserPath
  538. case userPageModeUpdate:
  539. title = "Update user"
  540. currentURL = fmt.Sprintf("%v/%v", webUserPath, url.PathEscape(user.Username))
  541. case userPageModeTemplate:
  542. title = "User template"
  543. currentURL = webTemplateUser
  544. }
  545. if user.Password != "" && user.IsPasswordHashed() && mode == userPageModeUpdate {
  546. user.Password = redactedSecret
  547. }
  548. user.FsConfig.RedactedSecret = redactedSecret
  549. data := userPage{
  550. basePage: getBasePageData(title, currentURL, r),
  551. Mode: mode,
  552. Error: error,
  553. User: user,
  554. ValidPerms: dataprovider.ValidPerms,
  555. ValidLoginMethods: dataprovider.ValidLoginMethods,
  556. ValidProtocols: dataprovider.ValidProtocols,
  557. WebClientOptions: sdk.WebClientOptions,
  558. RootDirPerms: user.GetPermissionsForPath("/"),
  559. VirtualFolders: folders,
  560. CanImpersonate: os.Getuid() == 0,
  561. FsWrapper: fsWrapper{
  562. Filesystem: user.FsConfig,
  563. IsUserPage: true,
  564. HasUsersBaseDir: dataprovider.HasUsersBaseDir(),
  565. DirPath: user.HomeDir,
  566. },
  567. }
  568. renderAdminTemplate(w, templateUser, data)
  569. }
  570. func renderFolderPage(w http.ResponseWriter, r *http.Request, folder vfs.BaseVirtualFolder, mode folderPageMode, error string) {
  571. var title, currentURL string
  572. switch mode {
  573. case folderPageModeAdd:
  574. title = "Add a new folder"
  575. currentURL = webFolderPath
  576. case folderPageModeUpdate:
  577. title = "Update folder"
  578. currentURL = fmt.Sprintf("%v/%v", webFolderPath, url.PathEscape(folder.Name))
  579. case folderPageModeTemplate:
  580. title = "Folder template"
  581. currentURL = webTemplateFolder
  582. }
  583. folder.FsConfig.RedactedSecret = redactedSecret
  584. folder.FsConfig.SetEmptySecretsIfNil()
  585. data := folderPage{
  586. basePage: getBasePageData(title, currentURL, r),
  587. Error: error,
  588. Folder: folder,
  589. Mode: mode,
  590. FsWrapper: fsWrapper{
  591. Filesystem: folder.FsConfig,
  592. IsUserPage: false,
  593. HasUsersBaseDir: false,
  594. DirPath: folder.MappedPath,
  595. },
  596. }
  597. renderAdminTemplate(w, templateFolder, data)
  598. }
  599. func getFoldersForTemplate(r *http.Request) []string {
  600. var res []string
  601. folderNames := r.Form["tpl_foldername"]
  602. folders := make(map[string]bool)
  603. for _, name := range folderNames {
  604. name = strings.TrimSpace(name)
  605. if name == "" {
  606. continue
  607. }
  608. if _, ok := folders[name]; ok {
  609. continue
  610. }
  611. folders[name] = true
  612. res = append(res, name)
  613. }
  614. return res
  615. }
  616. func getUsersForTemplate(r *http.Request) []userTemplateFields {
  617. var res []userTemplateFields
  618. tplUsernames := r.Form["tpl_username"]
  619. tplPasswords := r.Form["tpl_password"]
  620. tplPublicKeys := r.Form["tpl_public_keys"]
  621. users := make(map[string]bool)
  622. for idx, username := range tplUsernames {
  623. username = strings.TrimSpace(username)
  624. password := ""
  625. publicKey := ""
  626. if len(tplPasswords) > idx {
  627. password = strings.TrimSpace(tplPasswords[idx])
  628. }
  629. if len(tplPublicKeys) > idx {
  630. publicKey = strings.TrimSpace(tplPublicKeys[idx])
  631. }
  632. if username == "" || (password == "" && publicKey == "") {
  633. continue
  634. }
  635. if _, ok := users[username]; ok {
  636. continue
  637. }
  638. users[username] = true
  639. res = append(res, userTemplateFields{
  640. Username: username,
  641. Password: password,
  642. PublicKey: publicKey,
  643. })
  644. }
  645. return res
  646. }
  647. func getVirtualFoldersFromPostFields(r *http.Request) []vfs.VirtualFolder {
  648. var virtualFolders []vfs.VirtualFolder
  649. folderPaths := r.Form["vfolder_path"]
  650. folderNames := r.Form["vfolder_name"]
  651. folderQuotaSizes := r.Form["vfolder_quota_size"]
  652. folderQuotaFiles := r.Form["vfolder_quota_files"]
  653. for idx, p := range folderPaths {
  654. p = strings.TrimSpace(p)
  655. name := ""
  656. if len(folderNames) > idx {
  657. name = folderNames[idx]
  658. }
  659. if p != "" && name != "" {
  660. vfolder := vfs.VirtualFolder{
  661. BaseVirtualFolder: vfs.BaseVirtualFolder{
  662. Name: name,
  663. },
  664. VirtualPath: p,
  665. QuotaFiles: -1,
  666. QuotaSize: -1,
  667. }
  668. if len(folderQuotaSizes) > idx {
  669. quotaSize, err := strconv.ParseInt(strings.TrimSpace(folderQuotaSizes[idx]), 10, 64)
  670. if err == nil {
  671. vfolder.QuotaSize = quotaSize
  672. }
  673. }
  674. if len(folderQuotaFiles) > idx {
  675. quotaFiles, err := strconv.Atoi(strings.TrimSpace(folderQuotaFiles[idx]))
  676. if err == nil {
  677. vfolder.QuotaFiles = quotaFiles
  678. }
  679. }
  680. virtualFolders = append(virtualFolders, vfolder)
  681. }
  682. }
  683. return virtualFolders
  684. }
  685. func getUserPermissionsFromPostFields(r *http.Request) map[string][]string {
  686. permissions := make(map[string][]string)
  687. permissions["/"] = r.Form["permissions"]
  688. for k := range r.Form {
  689. if strings.HasPrefix(k, "sub_perm_path") {
  690. p := strings.TrimSpace(r.Form.Get(k))
  691. if p != "" {
  692. idx := strings.TrimPrefix(k, "sub_perm_path")
  693. permissions[p] = r.Form[fmt.Sprintf("sub_perm_permissions%v", idx)]
  694. }
  695. }
  696. }
  697. return permissions
  698. }
  699. func getBandwidthLimitsFromPostFields(r *http.Request) ([]sdk.BandwidthLimit, error) {
  700. var result []sdk.BandwidthLimit
  701. for k := range r.Form {
  702. if strings.HasPrefix(k, "bandwidth_limit_sources") {
  703. sources := getSliceFromDelimitedValues(r.Form.Get(k), ",")
  704. if len(sources) > 0 {
  705. bwLimit := sdk.BandwidthLimit{
  706. Sources: sources,
  707. }
  708. idx := strings.TrimPrefix(k, "bandwidth_limit_sources")
  709. ul := r.Form.Get(fmt.Sprintf("upload_bandwidth_source%v", idx))
  710. dl := r.Form.Get(fmt.Sprintf("download_bandwidth_source%v", idx))
  711. if ul != "" {
  712. bandwidthUL, err := strconv.ParseInt(ul, 10, 64)
  713. if err != nil {
  714. return result, fmt.Errorf("invalid upload_bandwidth_source%v %#v: %w", idx, ul, err)
  715. }
  716. bwLimit.UploadBandwidth = bandwidthUL
  717. }
  718. if dl != "" {
  719. bandwidthDL, err := strconv.ParseInt(dl, 10, 64)
  720. if err != nil {
  721. return result, fmt.Errorf("invalid download_bandwidth_source%v %#v: %w", idx, ul, err)
  722. }
  723. bwLimit.DownloadBandwidth = bandwidthDL
  724. }
  725. result = append(result, bwLimit)
  726. }
  727. }
  728. }
  729. return result, nil
  730. }
  731. func getFilePatternsFromPostField(r *http.Request) []sdk.PatternsFilter {
  732. var result []sdk.PatternsFilter
  733. allowedPatterns := make(map[string][]string)
  734. deniedPatterns := make(map[string][]string)
  735. for k := range r.Form {
  736. if strings.HasPrefix(k, "pattern_path") {
  737. p := strings.TrimSpace(r.Form.Get(k))
  738. idx := strings.TrimPrefix(k, "pattern_path")
  739. filters := strings.TrimSpace(r.Form.Get(fmt.Sprintf("patterns%v", idx)))
  740. filters = strings.ReplaceAll(filters, " ", "")
  741. patternType := r.Form.Get(fmt.Sprintf("pattern_type%v", idx))
  742. if p != "" && filters != "" {
  743. if patternType == "allowed" {
  744. allowedPatterns[p] = append(allowedPatterns[p], strings.Split(filters, ",")...)
  745. } else {
  746. deniedPatterns[p] = append(deniedPatterns[p], strings.Split(filters, ",")...)
  747. }
  748. }
  749. }
  750. }
  751. for dirAllowed, allowPatterns := range allowedPatterns {
  752. filter := sdk.PatternsFilter{
  753. Path: dirAllowed,
  754. AllowedPatterns: util.RemoveDuplicates(allowPatterns),
  755. }
  756. for dirDenied, denPatterns := range deniedPatterns {
  757. if dirAllowed == dirDenied {
  758. filter.DeniedPatterns = util.RemoveDuplicates(denPatterns)
  759. break
  760. }
  761. }
  762. result = append(result, filter)
  763. }
  764. for dirDenied, denPatterns := range deniedPatterns {
  765. found := false
  766. for _, res := range result {
  767. if res.Path == dirDenied {
  768. found = true
  769. break
  770. }
  771. }
  772. if !found {
  773. result = append(result, sdk.PatternsFilter{
  774. Path: dirDenied,
  775. DeniedPatterns: denPatterns,
  776. })
  777. }
  778. }
  779. return result
  780. }
  781. func getFiltersFromUserPostFields(r *http.Request) (sdk.BaseUserFilters, error) {
  782. var filters sdk.BaseUserFilters
  783. bwLimits, err := getBandwidthLimitsFromPostFields(r)
  784. if err != nil {
  785. return filters, err
  786. }
  787. filters.BandwidthLimits = bwLimits
  788. filters.AllowedIP = getSliceFromDelimitedValues(r.Form.Get("allowed_ip"), ",")
  789. filters.DeniedIP = getSliceFromDelimitedValues(r.Form.Get("denied_ip"), ",")
  790. filters.DeniedLoginMethods = r.Form["ssh_login_methods"]
  791. filters.DeniedProtocols = r.Form["denied_protocols"]
  792. filters.FilePatterns = getFilePatternsFromPostField(r)
  793. filters.TLSUsername = sdk.TLSUsername(r.Form.Get("tls_username"))
  794. filters.WebClient = r.Form["web_client_options"]
  795. hooks := r.Form["hooks"]
  796. if util.IsStringInSlice("external_auth_disabled", hooks) {
  797. filters.Hooks.ExternalAuthDisabled = true
  798. }
  799. if util.IsStringInSlice("pre_login_disabled", hooks) {
  800. filters.Hooks.PreLoginDisabled = true
  801. }
  802. if util.IsStringInSlice("check_password_disabled", hooks) {
  803. filters.Hooks.CheckPasswordDisabled = true
  804. }
  805. filters.DisableFsChecks = len(r.Form.Get("disable_fs_checks")) > 0
  806. filters.AllowAPIKeyAuth = len(r.Form.Get("allow_api_key_auth")) > 0
  807. return filters, nil
  808. }
  809. func getSecretFromFormField(r *http.Request, field string) *kms.Secret {
  810. secret := kms.NewPlainSecret(r.Form.Get(field))
  811. if strings.TrimSpace(secret.GetPayload()) == redactedSecret {
  812. secret.SetStatus(sdkkms.SecretStatusRedacted)
  813. }
  814. if strings.TrimSpace(secret.GetPayload()) == "" {
  815. secret.SetStatus("")
  816. }
  817. return secret
  818. }
  819. func getS3Config(r *http.Request) (vfs.S3FsConfig, error) {
  820. var err error
  821. config := vfs.S3FsConfig{}
  822. config.Bucket = r.Form.Get("s3_bucket")
  823. config.Region = r.Form.Get("s3_region")
  824. config.AccessKey = r.Form.Get("s3_access_key")
  825. config.AccessSecret = getSecretFromFormField(r, "s3_access_secret")
  826. config.Endpoint = r.Form.Get("s3_endpoint")
  827. config.StorageClass = r.Form.Get("s3_storage_class")
  828. config.ACL = r.Form.Get("s3_acl")
  829. config.KeyPrefix = r.Form.Get("s3_key_prefix")
  830. config.UploadPartSize, err = strconv.ParseInt(r.Form.Get("s3_upload_part_size"), 10, 64)
  831. if err != nil {
  832. return config, err
  833. }
  834. config.UploadConcurrency, err = strconv.Atoi(r.Form.Get("s3_upload_concurrency"))
  835. if err != nil {
  836. return config, err
  837. }
  838. config.DownloadPartSize, err = strconv.ParseInt(r.Form.Get("s3_download_part_size"), 10, 64)
  839. if err != nil {
  840. return config, err
  841. }
  842. config.DownloadConcurrency, err = strconv.Atoi(r.Form.Get("s3_download_concurrency"))
  843. if err != nil {
  844. return config, err
  845. }
  846. config.ForcePathStyle = r.Form.Get("s3_force_path_style") != ""
  847. config.DownloadPartMaxTime, err = strconv.Atoi(r.Form.Get("s3_download_part_max_time"))
  848. return config, err
  849. }
  850. func getGCSConfig(r *http.Request) (vfs.GCSFsConfig, error) {
  851. var err error
  852. config := vfs.GCSFsConfig{}
  853. config.Bucket = r.Form.Get("gcs_bucket")
  854. config.StorageClass = r.Form.Get("gcs_storage_class")
  855. config.ACL = r.Form.Get("gcs_acl")
  856. config.KeyPrefix = r.Form.Get("gcs_key_prefix")
  857. autoCredentials := r.Form.Get("gcs_auto_credentials")
  858. if autoCredentials != "" {
  859. config.AutomaticCredentials = 1
  860. } else {
  861. config.AutomaticCredentials = 0
  862. }
  863. credentials, _, err := r.FormFile("gcs_credential_file")
  864. if err == http.ErrMissingFile {
  865. return config, nil
  866. }
  867. if err != nil {
  868. return config, err
  869. }
  870. defer credentials.Close()
  871. fileBytes, err := io.ReadAll(credentials)
  872. if err != nil || len(fileBytes) == 0 {
  873. if len(fileBytes) == 0 {
  874. err = errors.New("credentials file size must be greater than 0")
  875. }
  876. return config, err
  877. }
  878. config.Credentials = kms.NewPlainSecret(string(fileBytes))
  879. config.AutomaticCredentials = 0
  880. return config, err
  881. }
  882. func getSFTPConfig(r *http.Request) (vfs.SFTPFsConfig, error) {
  883. var err error
  884. config := vfs.SFTPFsConfig{}
  885. config.Endpoint = r.Form.Get("sftp_endpoint")
  886. config.Username = r.Form.Get("sftp_username")
  887. config.Password = getSecretFromFormField(r, "sftp_password")
  888. config.PrivateKey = getSecretFromFormField(r, "sftp_private_key")
  889. fingerprintsFormValue := r.Form.Get("sftp_fingerprints")
  890. config.Fingerprints = getSliceFromDelimitedValues(fingerprintsFormValue, "\n")
  891. config.Prefix = r.Form.Get("sftp_prefix")
  892. config.DisableCouncurrentReads = len(r.Form.Get("sftp_disable_concurrent_reads")) > 0
  893. config.BufferSize, err = strconv.ParseInt(r.Form.Get("sftp_buffer_size"), 10, 64)
  894. return config, err
  895. }
  896. func getAzureConfig(r *http.Request) (vfs.AzBlobFsConfig, error) {
  897. var err error
  898. config := vfs.AzBlobFsConfig{}
  899. config.Container = r.Form.Get("az_container")
  900. config.AccountName = r.Form.Get("az_account_name")
  901. config.AccountKey = getSecretFromFormField(r, "az_account_key")
  902. config.SASURL = getSecretFromFormField(r, "az_sas_url")
  903. config.Endpoint = r.Form.Get("az_endpoint")
  904. config.KeyPrefix = r.Form.Get("az_key_prefix")
  905. config.AccessTier = r.Form.Get("az_access_tier")
  906. config.UseEmulator = len(r.Form.Get("az_use_emulator")) > 0
  907. config.UploadPartSize, err = strconv.ParseInt(r.Form.Get("az_upload_part_size"), 10, 64)
  908. if err != nil {
  909. return config, err
  910. }
  911. config.UploadConcurrency, err = strconv.Atoi(r.Form.Get("az_upload_concurrency"))
  912. return config, err
  913. }
  914. func getFsConfigFromPostFields(r *http.Request) (vfs.Filesystem, error) {
  915. var fs vfs.Filesystem
  916. fs.Provider = sdk.GetProviderByName(r.Form.Get("fs_provider"))
  917. switch fs.Provider {
  918. case sdk.S3FilesystemProvider:
  919. config, err := getS3Config(r)
  920. if err != nil {
  921. return fs, err
  922. }
  923. fs.S3Config = config
  924. case sdk.AzureBlobFilesystemProvider:
  925. config, err := getAzureConfig(r)
  926. if err != nil {
  927. return fs, err
  928. }
  929. fs.AzBlobConfig = config
  930. case sdk.GCSFilesystemProvider:
  931. config, err := getGCSConfig(r)
  932. if err != nil {
  933. return fs, err
  934. }
  935. fs.GCSConfig = config
  936. case sdk.CryptedFilesystemProvider:
  937. fs.CryptConfig.Passphrase = getSecretFromFormField(r, "crypt_passphrase")
  938. case sdk.SFTPFilesystemProvider:
  939. config, err := getSFTPConfig(r)
  940. if err != nil {
  941. return fs, err
  942. }
  943. fs.SFTPConfig = config
  944. }
  945. return fs, nil
  946. }
  947. func getAdminFromPostFields(r *http.Request) (dataprovider.Admin, error) {
  948. var admin dataprovider.Admin
  949. err := r.ParseForm()
  950. if err != nil {
  951. return admin, err
  952. }
  953. status, err := strconv.Atoi(r.Form.Get("status"))
  954. if err != nil {
  955. return admin, err
  956. }
  957. admin.Username = r.Form.Get("username")
  958. admin.Password = r.Form.Get("password")
  959. admin.Permissions = r.Form["permissions"]
  960. admin.Email = r.Form.Get("email")
  961. admin.Status = status
  962. admin.Filters.AllowList = getSliceFromDelimitedValues(r.Form.Get("allowed_ip"), ",")
  963. admin.Filters.AllowAPIKeyAuth = len(r.Form.Get("allow_api_key_auth")) > 0
  964. admin.AdditionalInfo = r.Form.Get("additional_info")
  965. admin.Description = r.Form.Get("description")
  966. return admin, nil
  967. }
  968. func replacePlaceholders(field string, replacements map[string]string) string {
  969. for k, v := range replacements {
  970. field = strings.ReplaceAll(field, k, v)
  971. }
  972. return field
  973. }
  974. func getFolderFromTemplate(folder vfs.BaseVirtualFolder, name string) vfs.BaseVirtualFolder {
  975. folder.Name = name
  976. replacements := make(map[string]string)
  977. replacements["%name%"] = folder.Name
  978. folder.MappedPath = replacePlaceholders(folder.MappedPath, replacements)
  979. folder.Description = replacePlaceholders(folder.Description, replacements)
  980. switch folder.FsConfig.Provider {
  981. case sdk.CryptedFilesystemProvider:
  982. folder.FsConfig.CryptConfig = getCryptFsFromTemplate(folder.FsConfig.CryptConfig, replacements)
  983. case sdk.S3FilesystemProvider:
  984. folder.FsConfig.S3Config = getS3FsFromTemplate(folder.FsConfig.S3Config, replacements)
  985. case sdk.GCSFilesystemProvider:
  986. folder.FsConfig.GCSConfig = getGCSFsFromTemplate(folder.FsConfig.GCSConfig, replacements)
  987. case sdk.AzureBlobFilesystemProvider:
  988. folder.FsConfig.AzBlobConfig = getAzBlobFsFromTemplate(folder.FsConfig.AzBlobConfig, replacements)
  989. case sdk.SFTPFilesystemProvider:
  990. folder.FsConfig.SFTPConfig = getSFTPFsFromTemplate(folder.FsConfig.SFTPConfig, replacements)
  991. }
  992. return folder
  993. }
  994. func getCryptFsFromTemplate(fsConfig vfs.CryptFsConfig, replacements map[string]string) vfs.CryptFsConfig {
  995. if fsConfig.Passphrase != nil {
  996. if fsConfig.Passphrase.IsPlain() {
  997. payload := replacePlaceholders(fsConfig.Passphrase.GetPayload(), replacements)
  998. fsConfig.Passphrase = kms.NewPlainSecret(payload)
  999. }
  1000. }
  1001. return fsConfig
  1002. }
  1003. func getS3FsFromTemplate(fsConfig vfs.S3FsConfig, replacements map[string]string) vfs.S3FsConfig {
  1004. fsConfig.KeyPrefix = replacePlaceholders(fsConfig.KeyPrefix, replacements)
  1005. fsConfig.AccessKey = replacePlaceholders(fsConfig.AccessKey, replacements)
  1006. if fsConfig.AccessSecret != nil && fsConfig.AccessSecret.IsPlain() {
  1007. payload := replacePlaceholders(fsConfig.AccessSecret.GetPayload(), replacements)
  1008. fsConfig.AccessSecret = kms.NewPlainSecret(payload)
  1009. }
  1010. return fsConfig
  1011. }
  1012. func getGCSFsFromTemplate(fsConfig vfs.GCSFsConfig, replacements map[string]string) vfs.GCSFsConfig {
  1013. fsConfig.KeyPrefix = replacePlaceholders(fsConfig.KeyPrefix, replacements)
  1014. return fsConfig
  1015. }
  1016. func getAzBlobFsFromTemplate(fsConfig vfs.AzBlobFsConfig, replacements map[string]string) vfs.AzBlobFsConfig {
  1017. fsConfig.KeyPrefix = replacePlaceholders(fsConfig.KeyPrefix, replacements)
  1018. fsConfig.AccountName = replacePlaceholders(fsConfig.AccountName, replacements)
  1019. if fsConfig.AccountKey != nil && fsConfig.AccountKey.IsPlain() {
  1020. payload := replacePlaceholders(fsConfig.AccountKey.GetPayload(), replacements)
  1021. fsConfig.AccountKey = kms.NewPlainSecret(payload)
  1022. }
  1023. return fsConfig
  1024. }
  1025. func getSFTPFsFromTemplate(fsConfig vfs.SFTPFsConfig, replacements map[string]string) vfs.SFTPFsConfig {
  1026. fsConfig.Prefix = replacePlaceholders(fsConfig.Prefix, replacements)
  1027. fsConfig.Username = replacePlaceholders(fsConfig.Username, replacements)
  1028. if fsConfig.Password != nil && fsConfig.Password.IsPlain() {
  1029. payload := replacePlaceholders(fsConfig.Password.GetPayload(), replacements)
  1030. fsConfig.Password = kms.NewPlainSecret(payload)
  1031. }
  1032. return fsConfig
  1033. }
  1034. func getUserFromTemplate(user dataprovider.User, template userTemplateFields) dataprovider.User {
  1035. user.Username = template.Username
  1036. user.Password = template.Password
  1037. user.PublicKeys = nil
  1038. if template.PublicKey != "" {
  1039. user.PublicKeys = append(user.PublicKeys, template.PublicKey)
  1040. }
  1041. replacements := make(map[string]string)
  1042. replacements["%username%"] = user.Username
  1043. user.Password = replacePlaceholders(user.Password, replacements)
  1044. replacements["%password%"] = user.Password
  1045. user.HomeDir = replacePlaceholders(user.HomeDir, replacements)
  1046. var vfolders []vfs.VirtualFolder
  1047. for _, vfolder := range user.VirtualFolders {
  1048. vfolder.Name = replacePlaceholders(vfolder.Name, replacements)
  1049. vfolder.VirtualPath = replacePlaceholders(vfolder.VirtualPath, replacements)
  1050. vfolders = append(vfolders, vfolder)
  1051. }
  1052. user.VirtualFolders = vfolders
  1053. user.Description = replacePlaceholders(user.Description, replacements)
  1054. user.AdditionalInfo = replacePlaceholders(user.AdditionalInfo, replacements)
  1055. switch user.FsConfig.Provider {
  1056. case sdk.CryptedFilesystemProvider:
  1057. user.FsConfig.CryptConfig = getCryptFsFromTemplate(user.FsConfig.CryptConfig, replacements)
  1058. case sdk.S3FilesystemProvider:
  1059. user.FsConfig.S3Config = getS3FsFromTemplate(user.FsConfig.S3Config, replacements)
  1060. case sdk.GCSFilesystemProvider:
  1061. user.FsConfig.GCSConfig = getGCSFsFromTemplate(user.FsConfig.GCSConfig, replacements)
  1062. case sdk.AzureBlobFilesystemProvider:
  1063. user.FsConfig.AzBlobConfig = getAzBlobFsFromTemplate(user.FsConfig.AzBlobConfig, replacements)
  1064. case sdk.SFTPFilesystemProvider:
  1065. user.FsConfig.SFTPConfig = getSFTPFsFromTemplate(user.FsConfig.SFTPConfig, replacements)
  1066. }
  1067. return user
  1068. }
  1069. func getUserFromPostFields(r *http.Request) (dataprovider.User, error) {
  1070. var user dataprovider.User
  1071. err := r.ParseMultipartForm(maxRequestSize)
  1072. if err != nil {
  1073. return user, err
  1074. }
  1075. defer r.MultipartForm.RemoveAll() //nolint:errcheck
  1076. uid, err := strconv.Atoi(r.Form.Get("uid"))
  1077. if err != nil {
  1078. return user, err
  1079. }
  1080. gid, err := strconv.Atoi(r.Form.Get("gid"))
  1081. if err != nil {
  1082. return user, err
  1083. }
  1084. maxSessions, err := strconv.Atoi(r.Form.Get("max_sessions"))
  1085. if err != nil {
  1086. return user, err
  1087. }
  1088. quotaSize, err := strconv.ParseInt(r.Form.Get("quota_size"), 10, 64)
  1089. if err != nil {
  1090. return user, err
  1091. }
  1092. quotaFiles, err := strconv.Atoi(r.Form.Get("quota_files"))
  1093. if err != nil {
  1094. return user, err
  1095. }
  1096. bandwidthUL, err := strconv.ParseInt(r.Form.Get("upload_bandwidth"), 10, 64)
  1097. if err != nil {
  1098. return user, err
  1099. }
  1100. bandwidthDL, err := strconv.ParseInt(r.Form.Get("download_bandwidth"), 10, 64)
  1101. if err != nil {
  1102. return user, err
  1103. }
  1104. status, err := strconv.Atoi(r.Form.Get("status"))
  1105. if err != nil {
  1106. return user, err
  1107. }
  1108. expirationDateMillis := int64(0)
  1109. expirationDateString := r.Form.Get("expiration_date")
  1110. if strings.TrimSpace(expirationDateString) != "" {
  1111. expirationDate, err := time.Parse(webDateTimeFormat, expirationDateString)
  1112. if err != nil {
  1113. return user, err
  1114. }
  1115. expirationDateMillis = util.GetTimeAsMsSinceEpoch(expirationDate)
  1116. }
  1117. fsConfig, err := getFsConfigFromPostFields(r)
  1118. if err != nil {
  1119. return user, err
  1120. }
  1121. filters, err := getFiltersFromUserPostFields(r)
  1122. if err != nil {
  1123. return user, err
  1124. }
  1125. user = dataprovider.User{
  1126. BaseUser: sdk.BaseUser{
  1127. Username: r.Form.Get("username"),
  1128. Email: r.Form.Get("email"),
  1129. Password: r.Form.Get("password"),
  1130. PublicKeys: r.Form["public_keys"],
  1131. HomeDir: r.Form.Get("home_dir"),
  1132. UID: uid,
  1133. GID: gid,
  1134. Permissions: getUserPermissionsFromPostFields(r),
  1135. MaxSessions: maxSessions,
  1136. QuotaSize: quotaSize,
  1137. QuotaFiles: quotaFiles,
  1138. UploadBandwidth: bandwidthUL,
  1139. DownloadBandwidth: bandwidthDL,
  1140. Status: status,
  1141. ExpirationDate: expirationDateMillis,
  1142. AdditionalInfo: r.Form.Get("additional_info"),
  1143. Description: r.Form.Get("description"),
  1144. },
  1145. Filters: dataprovider.UserFilters{
  1146. BaseUserFilters: filters,
  1147. },
  1148. VirtualFolders: getVirtualFoldersFromPostFields(r),
  1149. FsConfig: fsConfig,
  1150. }
  1151. maxFileSize, err := strconv.ParseInt(r.Form.Get("max_upload_file_size"), 10, 64)
  1152. user.Filters.MaxUploadFileSize = maxFileSize
  1153. return user, err
  1154. }
  1155. func handleWebAdminForgotPwd(w http.ResponseWriter, r *http.Request) {
  1156. r.Body = http.MaxBytesReader(w, r.Body, maxRequestSize)
  1157. if !smtp.IsEnabled() {
  1158. renderNotFoundPage(w, r, errors.New("this page does not exist"))
  1159. return
  1160. }
  1161. renderForgotPwdPage(w, "")
  1162. }
  1163. func handleWebAdminForgotPwdPost(w http.ResponseWriter, r *http.Request) {
  1164. r.Body = http.MaxBytesReader(w, r.Body, maxRequestSize)
  1165. err := r.ParseForm()
  1166. if err != nil {
  1167. renderForgotPwdPage(w, err.Error())
  1168. return
  1169. }
  1170. if err := verifyCSRFToken(r.Form.Get(csrfFormToken)); err != nil {
  1171. renderForbiddenPage(w, r, err.Error())
  1172. return
  1173. }
  1174. username := r.Form.Get("username")
  1175. err = handleForgotPassword(r, username, true)
  1176. if err != nil {
  1177. if e, ok := err.(*util.ValidationError); ok {
  1178. renderForgotPwdPage(w, e.GetErrorString())
  1179. return
  1180. }
  1181. renderForgotPwdPage(w, err.Error())
  1182. return
  1183. }
  1184. http.Redirect(w, r, webAdminResetPwdPath, http.StatusFound)
  1185. }
  1186. func handleWebAdminPasswordReset(w http.ResponseWriter, r *http.Request) {
  1187. r.Body = http.MaxBytesReader(w, r.Body, maxLoginBodySize)
  1188. if !smtp.IsEnabled() {
  1189. renderNotFoundPage(w, r, errors.New("this page does not exist"))
  1190. return
  1191. }
  1192. renderResetPwdPage(w, "")
  1193. }
  1194. func handleWebAdminTwoFactor(w http.ResponseWriter, r *http.Request) {
  1195. r.Body = http.MaxBytesReader(w, r.Body, maxRequestSize)
  1196. renderTwoFactorPage(w, "")
  1197. }
  1198. func handleWebAdminTwoFactorRecovery(w http.ResponseWriter, r *http.Request) {
  1199. r.Body = http.MaxBytesReader(w, r.Body, maxRequestSize)
  1200. renderTwoFactorRecoveryPage(w, "")
  1201. }
  1202. func handleWebAdminMFA(w http.ResponseWriter, r *http.Request) {
  1203. r.Body = http.MaxBytesReader(w, r.Body, maxRequestSize)
  1204. renderMFAPage(w, r)
  1205. }
  1206. func handleWebAdminProfile(w http.ResponseWriter, r *http.Request) {
  1207. r.Body = http.MaxBytesReader(w, r.Body, maxRequestSize)
  1208. renderProfilePage(w, r, "")
  1209. }
  1210. func handleWebAdminChangePwd(w http.ResponseWriter, r *http.Request) {
  1211. r.Body = http.MaxBytesReader(w, r.Body, maxRequestSize)
  1212. renderChangePasswordPage(w, r, "")
  1213. }
  1214. func handleWebAdminChangePwdPost(w http.ResponseWriter, r *http.Request) {
  1215. r.Body = http.MaxBytesReader(w, r.Body, maxRequestSize)
  1216. err := r.ParseForm()
  1217. if err != nil {
  1218. renderChangePasswordPage(w, r, err.Error())
  1219. return
  1220. }
  1221. if err := verifyCSRFToken(r.Form.Get(csrfFormToken)); err != nil {
  1222. renderForbiddenPage(w, r, err.Error())
  1223. return
  1224. }
  1225. err = doChangeAdminPassword(r, r.Form.Get("current_password"), r.Form.Get("new_password1"),
  1226. r.Form.Get("new_password2"))
  1227. if err != nil {
  1228. renderChangePasswordPage(w, r, err.Error())
  1229. return
  1230. }
  1231. handleWebLogout(w, r)
  1232. }
  1233. func handleWebAdminProfilePost(w http.ResponseWriter, r *http.Request) {
  1234. r.Body = http.MaxBytesReader(w, r.Body, maxRequestSize)
  1235. err := r.ParseForm()
  1236. if err != nil {
  1237. renderProfilePage(w, r, err.Error())
  1238. return
  1239. }
  1240. if err := verifyCSRFToken(r.Form.Get(csrfFormToken)); err != nil {
  1241. renderForbiddenPage(w, r, err.Error())
  1242. return
  1243. }
  1244. claims, err := getTokenClaims(r)
  1245. if err != nil || claims.Username == "" {
  1246. renderProfilePage(w, r, "Invalid token claims")
  1247. return
  1248. }
  1249. admin, err := dataprovider.AdminExists(claims.Username)
  1250. if err != nil {
  1251. renderProfilePage(w, r, err.Error())
  1252. return
  1253. }
  1254. admin.Filters.AllowAPIKeyAuth = len(r.Form.Get("allow_api_key_auth")) > 0
  1255. admin.Email = r.Form.Get("email")
  1256. admin.Description = r.Form.Get("description")
  1257. err = dataprovider.UpdateAdmin(&admin, dataprovider.ActionExecutorSelf, util.GetIPFromRemoteAddress(r.RemoteAddr))
  1258. if err != nil {
  1259. renderProfilePage(w, r, err.Error())
  1260. return
  1261. }
  1262. renderMessagePage(w, r, "Profile updated", "", http.StatusOK, nil,
  1263. "Your profile has been successfully updated")
  1264. }
  1265. func handleWebLogout(w http.ResponseWriter, r *http.Request) {
  1266. r.Body = http.MaxBytesReader(w, r.Body, maxRequestSize)
  1267. c := jwtTokenClaims{}
  1268. c.removeCookie(w, r, webBaseAdminPath)
  1269. http.Redirect(w, r, webLoginPath, http.StatusFound)
  1270. }
  1271. func handleWebMaintenance(w http.ResponseWriter, r *http.Request) {
  1272. r.Body = http.MaxBytesReader(w, r.Body, maxRequestSize)
  1273. renderMaintenancePage(w, r, "")
  1274. }
  1275. func handleWebRestore(w http.ResponseWriter, r *http.Request) {
  1276. r.Body = http.MaxBytesReader(w, r.Body, MaxRestoreSize)
  1277. claims, err := getTokenClaims(r)
  1278. if err != nil || claims.Username == "" {
  1279. renderBadRequestPage(w, r, errors.New("invalid token claims"))
  1280. return
  1281. }
  1282. err = r.ParseMultipartForm(MaxRestoreSize)
  1283. if err != nil {
  1284. renderMaintenancePage(w, r, err.Error())
  1285. return
  1286. }
  1287. defer r.MultipartForm.RemoveAll() //nolint:errcheck
  1288. if err := verifyCSRFToken(r.Form.Get(csrfFormToken)); err != nil {
  1289. renderForbiddenPage(w, r, err.Error())
  1290. return
  1291. }
  1292. restoreMode, err := strconv.Atoi(r.Form.Get("mode"))
  1293. if err != nil {
  1294. renderMaintenancePage(w, r, err.Error())
  1295. return
  1296. }
  1297. scanQuota, err := strconv.Atoi(r.Form.Get("quota"))
  1298. if err != nil {
  1299. renderMaintenancePage(w, r, err.Error())
  1300. return
  1301. }
  1302. backupFile, _, err := r.FormFile("backup_file")
  1303. if err != nil {
  1304. renderMaintenancePage(w, r, err.Error())
  1305. return
  1306. }
  1307. defer backupFile.Close()
  1308. backupContent, err := io.ReadAll(backupFile)
  1309. if err != nil || len(backupContent) == 0 {
  1310. if len(backupContent) == 0 {
  1311. err = errors.New("backup file size must be greater than 0")
  1312. }
  1313. renderMaintenancePage(w, r, err.Error())
  1314. return
  1315. }
  1316. if err := restoreBackup(backupContent, "", scanQuota, restoreMode, claims.Username, util.GetIPFromRemoteAddress(r.RemoteAddr)); err != nil {
  1317. renderMaintenancePage(w, r, err.Error())
  1318. return
  1319. }
  1320. renderMessagePage(w, r, "Data restored", "", http.StatusOK, nil, "Your backup was successfully restored")
  1321. }
  1322. func handleGetWebAdmins(w http.ResponseWriter, r *http.Request) {
  1323. r.Body = http.MaxBytesReader(w, r.Body, maxRequestSize)
  1324. limit := defaultQueryLimit
  1325. if _, ok := r.URL.Query()["qlimit"]; ok {
  1326. var err error
  1327. limit, err = strconv.Atoi(r.URL.Query().Get("qlimit"))
  1328. if err != nil {
  1329. limit = defaultQueryLimit
  1330. }
  1331. }
  1332. admins := make([]dataprovider.Admin, 0, limit)
  1333. for {
  1334. a, err := dataprovider.GetAdmins(limit, len(admins), dataprovider.OrderASC)
  1335. if err != nil {
  1336. renderInternalServerErrorPage(w, r, err)
  1337. return
  1338. }
  1339. admins = append(admins, a...)
  1340. if len(a) < limit {
  1341. break
  1342. }
  1343. }
  1344. data := adminsPage{
  1345. basePage: getBasePageData(pageAdminsTitle, webAdminsPath, r),
  1346. Admins: admins,
  1347. }
  1348. renderAdminTemplate(w, templateAdmins, data)
  1349. }
  1350. func handleWebAdminSetupGet(w http.ResponseWriter, r *http.Request) {
  1351. r.Body = http.MaxBytesReader(w, r.Body, maxLoginBodySize)
  1352. if dataprovider.HasAdmin() {
  1353. http.Redirect(w, r, webLoginPath, http.StatusFound)
  1354. return
  1355. }
  1356. renderAdminSetupPage(w, r, "", "")
  1357. }
  1358. func handleWebAddAdminGet(w http.ResponseWriter, r *http.Request) {
  1359. r.Body = http.MaxBytesReader(w, r.Body, maxRequestSize)
  1360. admin := &dataprovider.Admin{Status: 1}
  1361. renderAddUpdateAdminPage(w, r, admin, "", true)
  1362. }
  1363. func handleWebUpdateAdminGet(w http.ResponseWriter, r *http.Request) {
  1364. r.Body = http.MaxBytesReader(w, r.Body, maxRequestSize)
  1365. username := getURLParam(r, "username")
  1366. admin, err := dataprovider.AdminExists(username)
  1367. if err == nil {
  1368. renderAddUpdateAdminPage(w, r, &admin, "", false)
  1369. } else if _, ok := err.(*util.RecordNotFoundError); ok {
  1370. renderNotFoundPage(w, r, err)
  1371. } else {
  1372. renderInternalServerErrorPage(w, r, err)
  1373. }
  1374. }
  1375. func handleWebAddAdminPost(w http.ResponseWriter, r *http.Request) {
  1376. r.Body = http.MaxBytesReader(w, r.Body, maxRequestSize)
  1377. claims, err := getTokenClaims(r)
  1378. if err != nil || claims.Username == "" {
  1379. renderBadRequestPage(w, r, errors.New("invalid token claims"))
  1380. return
  1381. }
  1382. admin, err := getAdminFromPostFields(r)
  1383. if err != nil {
  1384. renderAddUpdateAdminPage(w, r, &admin, err.Error(), true)
  1385. return
  1386. }
  1387. if err := verifyCSRFToken(r.Form.Get(csrfFormToken)); err != nil {
  1388. renderForbiddenPage(w, r, err.Error())
  1389. return
  1390. }
  1391. err = dataprovider.AddAdmin(&admin, claims.Username, util.GetIPFromRemoteAddress(r.Method))
  1392. if err != nil {
  1393. renderAddUpdateAdminPage(w, r, &admin, err.Error(), true)
  1394. return
  1395. }
  1396. http.Redirect(w, r, webAdminsPath, http.StatusSeeOther)
  1397. }
  1398. func handleWebUpdateAdminPost(w http.ResponseWriter, r *http.Request) {
  1399. r.Body = http.MaxBytesReader(w, r.Body, maxRequestSize)
  1400. username := getURLParam(r, "username")
  1401. admin, err := dataprovider.AdminExists(username)
  1402. if _, ok := err.(*util.RecordNotFoundError); ok {
  1403. renderNotFoundPage(w, r, err)
  1404. return
  1405. } else if err != nil {
  1406. renderInternalServerErrorPage(w, r, err)
  1407. return
  1408. }
  1409. updatedAdmin, err := getAdminFromPostFields(r)
  1410. if err != nil {
  1411. renderAddUpdateAdminPage(w, r, &updatedAdmin, err.Error(), false)
  1412. return
  1413. }
  1414. if err := verifyCSRFToken(r.Form.Get(csrfFormToken)); err != nil {
  1415. renderForbiddenPage(w, r, err.Error())
  1416. return
  1417. }
  1418. updatedAdmin.ID = admin.ID
  1419. updatedAdmin.Username = admin.Username
  1420. if updatedAdmin.Password == "" {
  1421. updatedAdmin.Password = admin.Password
  1422. }
  1423. updatedAdmin.Filters.TOTPConfig = admin.Filters.TOTPConfig
  1424. updatedAdmin.Filters.RecoveryCodes = admin.Filters.RecoveryCodes
  1425. claims, err := getTokenClaims(r)
  1426. if err != nil || claims.Username == "" {
  1427. renderAddUpdateAdminPage(w, r, &updatedAdmin, fmt.Sprintf("Invalid token claims: %v", err), false)
  1428. return
  1429. }
  1430. if username == claims.Username {
  1431. if claims.isCriticalPermRemoved(updatedAdmin.Permissions) {
  1432. renderAddUpdateAdminPage(w, r, &updatedAdmin, "You cannot remove these permissions to yourself", false)
  1433. return
  1434. }
  1435. if updatedAdmin.Status == 0 {
  1436. renderAddUpdateAdminPage(w, r, &updatedAdmin, "You cannot disable yourself", false)
  1437. return
  1438. }
  1439. }
  1440. err = dataprovider.UpdateAdmin(&updatedAdmin, claims.Username, util.GetIPFromRemoteAddress(r.RemoteAddr))
  1441. if err != nil {
  1442. renderAddUpdateAdminPage(w, r, &admin, err.Error(), false)
  1443. return
  1444. }
  1445. http.Redirect(w, r, webAdminsPath, http.StatusSeeOther)
  1446. }
  1447. func handleWebDefenderPage(w http.ResponseWriter, r *http.Request) {
  1448. r.Body = http.MaxBytesReader(w, r.Body, maxRequestSize)
  1449. data := defenderHostsPage{
  1450. basePage: getBasePageData(pageDefenderTitle, webDefenderPath, r),
  1451. DefenderHostsURL: webDefenderHostsPath,
  1452. }
  1453. renderAdminTemplate(w, templateDefender, data)
  1454. }
  1455. func handleGetWebUsers(w http.ResponseWriter, r *http.Request) {
  1456. r.Body = http.MaxBytesReader(w, r.Body, maxRequestSize)
  1457. limit := defaultQueryLimit
  1458. if _, ok := r.URL.Query()["qlimit"]; ok {
  1459. var err error
  1460. limit, err = strconv.Atoi(r.URL.Query().Get("qlimit"))
  1461. if err != nil {
  1462. limit = defaultQueryLimit
  1463. }
  1464. }
  1465. users := make([]dataprovider.User, 0, limit)
  1466. for {
  1467. u, err := dataprovider.GetUsers(limit, len(users), dataprovider.OrderASC)
  1468. if err != nil {
  1469. renderInternalServerErrorPage(w, r, err)
  1470. return
  1471. }
  1472. users = append(users, u...)
  1473. if len(u) < limit {
  1474. break
  1475. }
  1476. }
  1477. data := usersPage{
  1478. basePage: getBasePageData(pageUsersTitle, webUsersPath, r),
  1479. Users: users,
  1480. }
  1481. renderAdminTemplate(w, templateUsers, data)
  1482. }
  1483. func handleWebTemplateFolderGet(w http.ResponseWriter, r *http.Request) {
  1484. r.Body = http.MaxBytesReader(w, r.Body, maxRequestSize)
  1485. if r.URL.Query().Get("from") != "" {
  1486. name := r.URL.Query().Get("from")
  1487. folder, err := dataprovider.GetFolderByName(name)
  1488. if err == nil {
  1489. renderFolderPage(w, r, folder, folderPageModeTemplate, "")
  1490. } else if _, ok := err.(*util.RecordNotFoundError); ok {
  1491. renderNotFoundPage(w, r, err)
  1492. } else {
  1493. renderInternalServerErrorPage(w, r, err)
  1494. }
  1495. } else {
  1496. folder := vfs.BaseVirtualFolder{}
  1497. renderFolderPage(w, r, folder, folderPageModeTemplate, "")
  1498. }
  1499. }
  1500. func handleWebTemplateFolderPost(w http.ResponseWriter, r *http.Request) {
  1501. r.Body = http.MaxBytesReader(w, r.Body, maxRequestSize)
  1502. templateFolder := vfs.BaseVirtualFolder{}
  1503. err := r.ParseMultipartForm(maxRequestSize)
  1504. if err != nil {
  1505. renderMessagePage(w, r, "Error parsing folders fields", "", http.StatusBadRequest, err, "")
  1506. return
  1507. }
  1508. defer r.MultipartForm.RemoveAll() //nolint:errcheck
  1509. if err := verifyCSRFToken(r.Form.Get(csrfFormToken)); err != nil {
  1510. renderForbiddenPage(w, r, err.Error())
  1511. return
  1512. }
  1513. templateFolder.MappedPath = r.Form.Get("mapped_path")
  1514. templateFolder.Description = r.Form.Get("description")
  1515. fsConfig, err := getFsConfigFromPostFields(r)
  1516. if err != nil {
  1517. renderMessagePage(w, r, "Error parsing folders fields", "", http.StatusBadRequest, err, "")
  1518. return
  1519. }
  1520. templateFolder.FsConfig = fsConfig
  1521. var dump dataprovider.BackupData
  1522. dump.Version = dataprovider.DumpVersion
  1523. foldersFields := getFoldersForTemplate(r)
  1524. for _, tmpl := range foldersFields {
  1525. f := getFolderFromTemplate(templateFolder, tmpl)
  1526. if err := dataprovider.ValidateFolder(&f); err != nil {
  1527. renderMessagePage(w, r, fmt.Sprintf("Error validating folder %#v", f.Name), "", http.StatusBadRequest, err, "")
  1528. return
  1529. }
  1530. dump.Folders = append(dump.Folders, f)
  1531. }
  1532. if len(dump.Folders) == 0 {
  1533. renderMessagePage(w, r, "No folders to export", "No valid folders found, export is not possible", http.StatusBadRequest, nil, "")
  1534. return
  1535. }
  1536. w.Header().Set("Content-Disposition", fmt.Sprintf("attachment; filename=\"sftpgo-%v-folders-from-template.json\"", len(dump.Folders)))
  1537. render.JSON(w, r, dump)
  1538. }
  1539. func handleWebTemplateUserGet(w http.ResponseWriter, r *http.Request) {
  1540. r.Body = http.MaxBytesReader(w, r.Body, maxRequestSize)
  1541. if r.URL.Query().Get("from") != "" {
  1542. username := r.URL.Query().Get("from")
  1543. user, err := dataprovider.UserExists(username)
  1544. if err == nil {
  1545. user.SetEmptySecrets()
  1546. user.Email = ""
  1547. user.Description = ""
  1548. renderUserPage(w, r, &user, userPageModeTemplate, "")
  1549. } else if _, ok := err.(*util.RecordNotFoundError); ok {
  1550. renderNotFoundPage(w, r, err)
  1551. } else {
  1552. renderInternalServerErrorPage(w, r, err)
  1553. }
  1554. } else {
  1555. user := dataprovider.User{BaseUser: sdk.BaseUser{Status: 1}}
  1556. renderUserPage(w, r, &user, userPageModeTemplate, "")
  1557. }
  1558. }
  1559. func handleWebTemplateUserPost(w http.ResponseWriter, r *http.Request) {
  1560. r.Body = http.MaxBytesReader(w, r.Body, maxRequestSize)
  1561. templateUser, err := getUserFromPostFields(r)
  1562. if err != nil {
  1563. renderMessagePage(w, r, "Error parsing user fields", "", http.StatusBadRequest, err, "")
  1564. return
  1565. }
  1566. if err := verifyCSRFToken(r.Form.Get(csrfFormToken)); err != nil {
  1567. renderForbiddenPage(w, r, err.Error())
  1568. return
  1569. }
  1570. var dump dataprovider.BackupData
  1571. dump.Version = dataprovider.DumpVersion
  1572. userTmplFields := getUsersForTemplate(r)
  1573. for _, tmpl := range userTmplFields {
  1574. u := getUserFromTemplate(templateUser, tmpl)
  1575. if err := dataprovider.ValidateUser(&u); err != nil {
  1576. renderMessagePage(w, r, fmt.Sprintf("Error validating user %#v", u.Username), "", http.StatusBadRequest, err, "")
  1577. return
  1578. }
  1579. dump.Users = append(dump.Users, u)
  1580. for _, folder := range u.VirtualFolders {
  1581. if !dump.HasFolder(folder.Name) {
  1582. dump.Folders = append(dump.Folders, folder.BaseVirtualFolder)
  1583. }
  1584. }
  1585. }
  1586. if len(dump.Users) == 0 {
  1587. renderMessagePage(w, r, "No users to export", "No valid users found, export is not possible", http.StatusBadRequest, nil, "")
  1588. return
  1589. }
  1590. w.Header().Set("Content-Disposition", fmt.Sprintf("attachment; filename=\"sftpgo-%v-users-from-template.json\"", len(dump.Users)))
  1591. render.JSON(w, r, dump)
  1592. }
  1593. func handleWebAddUserGet(w http.ResponseWriter, r *http.Request) {
  1594. r.Body = http.MaxBytesReader(w, r.Body, maxRequestSize)
  1595. if r.URL.Query().Get("clone-from") != "" {
  1596. username := r.URL.Query().Get("clone-from")
  1597. user, err := dataprovider.UserExists(username)
  1598. if err == nil {
  1599. user.ID = 0
  1600. user.Username = ""
  1601. user.Password = ""
  1602. user.PublicKeys = nil
  1603. user.SetEmptySecrets()
  1604. renderUserPage(w, r, &user, userPageModeAdd, "")
  1605. } else if _, ok := err.(*util.RecordNotFoundError); ok {
  1606. renderNotFoundPage(w, r, err)
  1607. } else {
  1608. renderInternalServerErrorPage(w, r, err)
  1609. }
  1610. } else {
  1611. user := dataprovider.User{BaseUser: sdk.BaseUser{
  1612. Status: 1,
  1613. Permissions: map[string][]string{
  1614. "/": {dataprovider.PermAny},
  1615. },
  1616. }}
  1617. renderUserPage(w, r, &user, userPageModeAdd, "")
  1618. }
  1619. }
  1620. func handleWebUpdateUserGet(w http.ResponseWriter, r *http.Request) {
  1621. r.Body = http.MaxBytesReader(w, r.Body, maxRequestSize)
  1622. username := getURLParam(r, "username")
  1623. user, err := dataprovider.UserExists(username)
  1624. if err == nil {
  1625. renderUserPage(w, r, &user, userPageModeUpdate, "")
  1626. } else if _, ok := err.(*util.RecordNotFoundError); ok {
  1627. renderNotFoundPage(w, r, err)
  1628. } else {
  1629. renderInternalServerErrorPage(w, r, err)
  1630. }
  1631. }
  1632. func handleWebAddUserPost(w http.ResponseWriter, r *http.Request) {
  1633. r.Body = http.MaxBytesReader(w, r.Body, maxRequestSize)
  1634. claims, err := getTokenClaims(r)
  1635. if err != nil || claims.Username == "" {
  1636. renderBadRequestPage(w, r, errors.New("invalid token claims"))
  1637. return
  1638. }
  1639. user, err := getUserFromPostFields(r)
  1640. if err != nil {
  1641. renderUserPage(w, r, &user, userPageModeAdd, err.Error())
  1642. return
  1643. }
  1644. if err := verifyCSRFToken(r.Form.Get(csrfFormToken)); err != nil {
  1645. renderForbiddenPage(w, r, err.Error())
  1646. return
  1647. }
  1648. err = dataprovider.AddUser(&user, claims.Username, util.GetIPFromRemoteAddress(r.RemoteAddr))
  1649. if err == nil {
  1650. http.Redirect(w, r, webUsersPath, http.StatusSeeOther)
  1651. } else {
  1652. renderUserPage(w, r, &user, userPageModeAdd, err.Error())
  1653. }
  1654. }
  1655. func handleWebUpdateUserPost(w http.ResponseWriter, r *http.Request) {
  1656. r.Body = http.MaxBytesReader(w, r.Body, maxRequestSize)
  1657. claims, err := getTokenClaims(r)
  1658. if err != nil || claims.Username == "" {
  1659. renderBadRequestPage(w, r, errors.New("invalid token claims"))
  1660. return
  1661. }
  1662. username := getURLParam(r, "username")
  1663. user, err := dataprovider.UserExists(username)
  1664. if _, ok := err.(*util.RecordNotFoundError); ok {
  1665. renderNotFoundPage(w, r, err)
  1666. return
  1667. } else if err != nil {
  1668. renderInternalServerErrorPage(w, r, err)
  1669. return
  1670. }
  1671. updatedUser, err := getUserFromPostFields(r)
  1672. if err != nil {
  1673. renderUserPage(w, r, &user, userPageModeUpdate, err.Error())
  1674. return
  1675. }
  1676. if err := verifyCSRFToken(r.Form.Get(csrfFormToken)); err != nil {
  1677. renderForbiddenPage(w, r, err.Error())
  1678. return
  1679. }
  1680. updatedUser.ID = user.ID
  1681. updatedUser.Username = user.Username
  1682. updatedUser.Filters.RecoveryCodes = user.Filters.RecoveryCodes
  1683. updatedUser.Filters.TOTPConfig = user.Filters.TOTPConfig
  1684. updatedUser.SetEmptySecretsIfNil()
  1685. if updatedUser.Password == redactedSecret {
  1686. updatedUser.Password = user.Password
  1687. }
  1688. updateEncryptedSecrets(&updatedUser.FsConfig, user.FsConfig.S3Config.AccessSecret, user.FsConfig.AzBlobConfig.AccountKey,
  1689. user.FsConfig.AzBlobConfig.SASURL, user.FsConfig.GCSConfig.Credentials, user.FsConfig.CryptConfig.Passphrase,
  1690. user.FsConfig.SFTPConfig.Password, user.FsConfig.SFTPConfig.PrivateKey)
  1691. err = dataprovider.UpdateUser(&updatedUser, claims.Username, util.GetIPFromRemoteAddress(r.RemoteAddr))
  1692. if err == nil {
  1693. if len(r.Form.Get("disconnect")) > 0 {
  1694. disconnectUser(user.Username)
  1695. }
  1696. http.Redirect(w, r, webUsersPath, http.StatusSeeOther)
  1697. } else {
  1698. renderUserPage(w, r, &user, userPageModeUpdate, err.Error())
  1699. }
  1700. }
  1701. func handleWebGetStatus(w http.ResponseWriter, r *http.Request) {
  1702. r.Body = http.MaxBytesReader(w, r.Body, maxRequestSize)
  1703. data := statusPage{
  1704. basePage: getBasePageData(pageStatusTitle, webStatusPath, r),
  1705. Status: getServicesStatus(),
  1706. }
  1707. renderAdminTemplate(w, templateStatus, data)
  1708. }
  1709. func handleWebGetConnections(w http.ResponseWriter, r *http.Request) {
  1710. r.Body = http.MaxBytesReader(w, r.Body, maxRequestSize)
  1711. connectionStats := common.Connections.GetStats()
  1712. data := connectionsPage{
  1713. basePage: getBasePageData(pageConnectionsTitle, webConnectionsPath, r),
  1714. Connections: connectionStats,
  1715. }
  1716. renderAdminTemplate(w, templateConnections, data)
  1717. }
  1718. func handleWebAddFolderGet(w http.ResponseWriter, r *http.Request) {
  1719. r.Body = http.MaxBytesReader(w, r.Body, maxRequestSize)
  1720. renderFolderPage(w, r, vfs.BaseVirtualFolder{}, folderPageModeAdd, "")
  1721. }
  1722. func handleWebAddFolderPost(w http.ResponseWriter, r *http.Request) {
  1723. r.Body = http.MaxBytesReader(w, r.Body, maxRequestSize)
  1724. folder := vfs.BaseVirtualFolder{}
  1725. err := r.ParseMultipartForm(maxRequestSize)
  1726. if err != nil {
  1727. renderFolderPage(w, r, folder, folderPageModeAdd, err.Error())
  1728. return
  1729. }
  1730. defer r.MultipartForm.RemoveAll() //nolint:errcheck
  1731. if err := verifyCSRFToken(r.Form.Get(csrfFormToken)); err != nil {
  1732. renderForbiddenPage(w, r, err.Error())
  1733. return
  1734. }
  1735. folder.MappedPath = r.Form.Get("mapped_path")
  1736. folder.Name = r.Form.Get("name")
  1737. folder.Description = r.Form.Get("description")
  1738. fsConfig, err := getFsConfigFromPostFields(r)
  1739. if err != nil {
  1740. renderFolderPage(w, r, folder, folderPageModeAdd, err.Error())
  1741. return
  1742. }
  1743. folder.FsConfig = fsConfig
  1744. err = dataprovider.AddFolder(&folder)
  1745. if err == nil {
  1746. http.Redirect(w, r, webFoldersPath, http.StatusSeeOther)
  1747. } else {
  1748. renderFolderPage(w, r, folder, folderPageModeAdd, err.Error())
  1749. }
  1750. }
  1751. func handleWebUpdateFolderGet(w http.ResponseWriter, r *http.Request) {
  1752. r.Body = http.MaxBytesReader(w, r.Body, maxRequestSize)
  1753. name := getURLParam(r, "name")
  1754. folder, err := dataprovider.GetFolderByName(name)
  1755. if err == nil {
  1756. renderFolderPage(w, r, folder, folderPageModeUpdate, "")
  1757. } else if _, ok := err.(*util.RecordNotFoundError); ok {
  1758. renderNotFoundPage(w, r, err)
  1759. } else {
  1760. renderInternalServerErrorPage(w, r, err)
  1761. }
  1762. }
  1763. func handleWebUpdateFolderPost(w http.ResponseWriter, r *http.Request) {
  1764. r.Body = http.MaxBytesReader(w, r.Body, maxRequestSize)
  1765. claims, err := getTokenClaims(r)
  1766. if err != nil || claims.Username == "" {
  1767. renderBadRequestPage(w, r, errors.New("invalid token claims"))
  1768. return
  1769. }
  1770. name := getURLParam(r, "name")
  1771. folder, err := dataprovider.GetFolderByName(name)
  1772. if _, ok := err.(*util.RecordNotFoundError); ok {
  1773. renderNotFoundPage(w, r, err)
  1774. return
  1775. } else if err != nil {
  1776. renderInternalServerErrorPage(w, r, err)
  1777. return
  1778. }
  1779. err = r.ParseMultipartForm(maxRequestSize)
  1780. if err != nil {
  1781. renderFolderPage(w, r, folder, folderPageModeUpdate, err.Error())
  1782. return
  1783. }
  1784. defer r.MultipartForm.RemoveAll() //nolint:errcheck
  1785. if err := verifyCSRFToken(r.Form.Get(csrfFormToken)); err != nil {
  1786. renderForbiddenPage(w, r, err.Error())
  1787. return
  1788. }
  1789. fsConfig, err := getFsConfigFromPostFields(r)
  1790. if err != nil {
  1791. renderFolderPage(w, r, folder, folderPageModeUpdate, err.Error())
  1792. return
  1793. }
  1794. updatedFolder := &vfs.BaseVirtualFolder{
  1795. MappedPath: r.Form.Get("mapped_path"),
  1796. Description: r.Form.Get("description"),
  1797. }
  1798. updatedFolder.ID = folder.ID
  1799. updatedFolder.Name = folder.Name
  1800. updatedFolder.FsConfig = fsConfig
  1801. updatedFolder.FsConfig.SetEmptySecretsIfNil()
  1802. updateEncryptedSecrets(&updatedFolder.FsConfig, folder.FsConfig.S3Config.AccessSecret, folder.FsConfig.AzBlobConfig.AccountKey,
  1803. folder.FsConfig.AzBlobConfig.SASURL, folder.FsConfig.GCSConfig.Credentials, folder.FsConfig.CryptConfig.Passphrase,
  1804. folder.FsConfig.SFTPConfig.Password, folder.FsConfig.SFTPConfig.PrivateKey)
  1805. err = dataprovider.UpdateFolder(updatedFolder, folder.Users, claims.Username, util.GetIPFromRemoteAddress(r.RemoteAddr))
  1806. if err != nil {
  1807. renderFolderPage(w, r, folder, folderPageModeUpdate, err.Error())
  1808. return
  1809. }
  1810. http.Redirect(w, r, webFoldersPath, http.StatusSeeOther)
  1811. }
  1812. func getWebVirtualFolders(w http.ResponseWriter, r *http.Request, limit int) ([]vfs.BaseVirtualFolder, error) {
  1813. folders := make([]vfs.BaseVirtualFolder, 0, limit)
  1814. for {
  1815. f, err := dataprovider.GetFolders(limit, len(folders), dataprovider.OrderASC)
  1816. if err != nil {
  1817. renderInternalServerErrorPage(w, r, err)
  1818. return folders, err
  1819. }
  1820. folders = append(folders, f...)
  1821. if len(f) < limit {
  1822. break
  1823. }
  1824. }
  1825. return folders, nil
  1826. }
  1827. func handleWebGetFolders(w http.ResponseWriter, r *http.Request) {
  1828. r.Body = http.MaxBytesReader(w, r.Body, maxRequestSize)
  1829. limit := defaultQueryLimit
  1830. if _, ok := r.URL.Query()["qlimit"]; ok {
  1831. var err error
  1832. limit, err = strconv.Atoi(r.URL.Query().Get("qlimit"))
  1833. if err != nil {
  1834. limit = defaultQueryLimit
  1835. }
  1836. }
  1837. folders, err := getWebVirtualFolders(w, r, limit)
  1838. if err != nil {
  1839. return
  1840. }
  1841. data := foldersPage{
  1842. basePage: getBasePageData(pageFoldersTitle, webFoldersPath, r),
  1843. Folders: folders,
  1844. }
  1845. renderAdminTemplate(w, templateFolders, data)
  1846. }