webadmin.go 56 KB

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