webadmin.go 69 KB

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