webadmin.go 65 KB

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