webadmin.go 65 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089
  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. return filters, nil
  869. }
  870. func getSecretFromFormField(r *http.Request, field string) *kms.Secret {
  871. secret := kms.NewPlainSecret(r.Form.Get(field))
  872. if strings.TrimSpace(secret.GetPayload()) == redactedSecret {
  873. secret.SetStatus(sdkkms.SecretStatusRedacted)
  874. }
  875. if strings.TrimSpace(secret.GetPayload()) == "" {
  876. secret.SetStatus("")
  877. }
  878. return secret
  879. }
  880. func getS3Config(r *http.Request) (vfs.S3FsConfig, error) {
  881. var err error
  882. config := vfs.S3FsConfig{}
  883. config.Bucket = r.Form.Get("s3_bucket")
  884. config.Region = r.Form.Get("s3_region")
  885. config.AccessKey = r.Form.Get("s3_access_key")
  886. config.AccessSecret = getSecretFromFormField(r, "s3_access_secret")
  887. config.Endpoint = r.Form.Get("s3_endpoint")
  888. config.StorageClass = r.Form.Get("s3_storage_class")
  889. config.ACL = r.Form.Get("s3_acl")
  890. config.KeyPrefix = r.Form.Get("s3_key_prefix")
  891. config.UploadPartSize, err = strconv.ParseInt(r.Form.Get("s3_upload_part_size"), 10, 64)
  892. if err != nil {
  893. return config, err
  894. }
  895. config.UploadConcurrency, err = strconv.Atoi(r.Form.Get("s3_upload_concurrency"))
  896. if err != nil {
  897. return config, err
  898. }
  899. config.DownloadPartSize, err = strconv.ParseInt(r.Form.Get("s3_download_part_size"), 10, 64)
  900. if err != nil {
  901. return config, err
  902. }
  903. config.DownloadConcurrency, err = strconv.Atoi(r.Form.Get("s3_download_concurrency"))
  904. if err != nil {
  905. return config, err
  906. }
  907. config.ForcePathStyle = r.Form.Get("s3_force_path_style") != ""
  908. config.DownloadPartMaxTime, err = strconv.Atoi(r.Form.Get("s3_download_part_max_time"))
  909. if err != nil {
  910. return config, err
  911. }
  912. config.UploadPartMaxTime, err = strconv.Atoi(r.Form.Get("s3_upload_part_max_time"))
  913. return config, err
  914. }
  915. func getGCSConfig(r *http.Request) (vfs.GCSFsConfig, error) {
  916. var err error
  917. config := vfs.GCSFsConfig{}
  918. config.Bucket = r.Form.Get("gcs_bucket")
  919. config.StorageClass = r.Form.Get("gcs_storage_class")
  920. config.ACL = r.Form.Get("gcs_acl")
  921. config.KeyPrefix = r.Form.Get("gcs_key_prefix")
  922. autoCredentials := r.Form.Get("gcs_auto_credentials")
  923. if autoCredentials != "" {
  924. config.AutomaticCredentials = 1
  925. } else {
  926. config.AutomaticCredentials = 0
  927. }
  928. credentials, _, err := r.FormFile("gcs_credential_file")
  929. if err == http.ErrMissingFile {
  930. return config, nil
  931. }
  932. if err != nil {
  933. return config, err
  934. }
  935. defer credentials.Close()
  936. fileBytes, err := io.ReadAll(credentials)
  937. if err != nil || len(fileBytes) == 0 {
  938. if len(fileBytes) == 0 {
  939. err = errors.New("credentials file size must be greater than 0")
  940. }
  941. return config, err
  942. }
  943. config.Credentials = kms.NewPlainSecret(string(fileBytes))
  944. config.AutomaticCredentials = 0
  945. return config, err
  946. }
  947. func getSFTPConfig(r *http.Request) (vfs.SFTPFsConfig, error) {
  948. var err error
  949. config := vfs.SFTPFsConfig{}
  950. config.Endpoint = r.Form.Get("sftp_endpoint")
  951. config.Username = r.Form.Get("sftp_username")
  952. config.Password = getSecretFromFormField(r, "sftp_password")
  953. config.PrivateKey = getSecretFromFormField(r, "sftp_private_key")
  954. fingerprintsFormValue := r.Form.Get("sftp_fingerprints")
  955. config.Fingerprints = getSliceFromDelimitedValues(fingerprintsFormValue, "\n")
  956. config.Prefix = r.Form.Get("sftp_prefix")
  957. config.DisableCouncurrentReads = len(r.Form.Get("sftp_disable_concurrent_reads")) > 0
  958. config.BufferSize, err = strconv.ParseInt(r.Form.Get("sftp_buffer_size"), 10, 64)
  959. return config, err
  960. }
  961. func getAzureConfig(r *http.Request) (vfs.AzBlobFsConfig, error) {
  962. var err error
  963. config := vfs.AzBlobFsConfig{}
  964. config.Container = r.Form.Get("az_container")
  965. config.AccountName = r.Form.Get("az_account_name")
  966. config.AccountKey = getSecretFromFormField(r, "az_account_key")
  967. config.SASURL = getSecretFromFormField(r, "az_sas_url")
  968. config.Endpoint = r.Form.Get("az_endpoint")
  969. config.KeyPrefix = r.Form.Get("az_key_prefix")
  970. config.AccessTier = r.Form.Get("az_access_tier")
  971. config.UseEmulator = len(r.Form.Get("az_use_emulator")) > 0
  972. config.UploadPartSize, err = strconv.ParseInt(r.Form.Get("az_upload_part_size"), 10, 64)
  973. if err != nil {
  974. return config, err
  975. }
  976. config.UploadConcurrency, err = strconv.Atoi(r.Form.Get("az_upload_concurrency"))
  977. return config, err
  978. }
  979. func getFsConfigFromPostFields(r *http.Request) (vfs.Filesystem, error) {
  980. var fs vfs.Filesystem
  981. fs.Provider = sdk.GetProviderByName(r.Form.Get("fs_provider"))
  982. switch fs.Provider {
  983. case sdk.S3FilesystemProvider:
  984. config, err := getS3Config(r)
  985. if err != nil {
  986. return fs, err
  987. }
  988. fs.S3Config = config
  989. case sdk.AzureBlobFilesystemProvider:
  990. config, err := getAzureConfig(r)
  991. if err != nil {
  992. return fs, err
  993. }
  994. fs.AzBlobConfig = config
  995. case sdk.GCSFilesystemProvider:
  996. config, err := getGCSConfig(r)
  997. if err != nil {
  998. return fs, err
  999. }
  1000. fs.GCSConfig = config
  1001. case sdk.CryptedFilesystemProvider:
  1002. fs.CryptConfig.Passphrase = getSecretFromFormField(r, "crypt_passphrase")
  1003. case sdk.SFTPFilesystemProvider:
  1004. config, err := getSFTPConfig(r)
  1005. if err != nil {
  1006. return fs, err
  1007. }
  1008. fs.SFTPConfig = config
  1009. }
  1010. return fs, nil
  1011. }
  1012. func getAdminFromPostFields(r *http.Request) (dataprovider.Admin, error) {
  1013. var admin dataprovider.Admin
  1014. err := r.ParseForm()
  1015. if err != nil {
  1016. return admin, err
  1017. }
  1018. status, err := strconv.Atoi(r.Form.Get("status"))
  1019. if err != nil {
  1020. return admin, err
  1021. }
  1022. admin.Username = r.Form.Get("username")
  1023. admin.Password = r.Form.Get("password")
  1024. admin.Permissions = r.Form["permissions"]
  1025. admin.Email = r.Form.Get("email")
  1026. admin.Status = status
  1027. admin.Filters.AllowList = getSliceFromDelimitedValues(r.Form.Get("allowed_ip"), ",")
  1028. admin.Filters.AllowAPIKeyAuth = len(r.Form.Get("allow_api_key_auth")) > 0
  1029. admin.AdditionalInfo = r.Form.Get("additional_info")
  1030. admin.Description = r.Form.Get("description")
  1031. return admin, nil
  1032. }
  1033. func replacePlaceholders(field string, replacements map[string]string) string {
  1034. for k, v := range replacements {
  1035. field = strings.ReplaceAll(field, k, v)
  1036. }
  1037. return field
  1038. }
  1039. func getFolderFromTemplate(folder vfs.BaseVirtualFolder, name string) vfs.BaseVirtualFolder {
  1040. folder.Name = name
  1041. replacements := make(map[string]string)
  1042. replacements["%name%"] = folder.Name
  1043. folder.MappedPath = replacePlaceholders(folder.MappedPath, replacements)
  1044. folder.Description = replacePlaceholders(folder.Description, replacements)
  1045. switch folder.FsConfig.Provider {
  1046. case sdk.CryptedFilesystemProvider:
  1047. folder.FsConfig.CryptConfig = getCryptFsFromTemplate(folder.FsConfig.CryptConfig, replacements)
  1048. case sdk.S3FilesystemProvider:
  1049. folder.FsConfig.S3Config = getS3FsFromTemplate(folder.FsConfig.S3Config, replacements)
  1050. case sdk.GCSFilesystemProvider:
  1051. folder.FsConfig.GCSConfig = getGCSFsFromTemplate(folder.FsConfig.GCSConfig, replacements)
  1052. case sdk.AzureBlobFilesystemProvider:
  1053. folder.FsConfig.AzBlobConfig = getAzBlobFsFromTemplate(folder.FsConfig.AzBlobConfig, replacements)
  1054. case sdk.SFTPFilesystemProvider:
  1055. folder.FsConfig.SFTPConfig = getSFTPFsFromTemplate(folder.FsConfig.SFTPConfig, replacements)
  1056. }
  1057. return folder
  1058. }
  1059. func getCryptFsFromTemplate(fsConfig vfs.CryptFsConfig, replacements map[string]string) vfs.CryptFsConfig {
  1060. if fsConfig.Passphrase != nil {
  1061. if fsConfig.Passphrase.IsPlain() {
  1062. payload := replacePlaceholders(fsConfig.Passphrase.GetPayload(), replacements)
  1063. fsConfig.Passphrase = kms.NewPlainSecret(payload)
  1064. }
  1065. }
  1066. return fsConfig
  1067. }
  1068. func getS3FsFromTemplate(fsConfig vfs.S3FsConfig, replacements map[string]string) vfs.S3FsConfig {
  1069. fsConfig.KeyPrefix = replacePlaceholders(fsConfig.KeyPrefix, replacements)
  1070. fsConfig.AccessKey = replacePlaceholders(fsConfig.AccessKey, replacements)
  1071. if fsConfig.AccessSecret != nil && fsConfig.AccessSecret.IsPlain() {
  1072. payload := replacePlaceholders(fsConfig.AccessSecret.GetPayload(), replacements)
  1073. fsConfig.AccessSecret = kms.NewPlainSecret(payload)
  1074. }
  1075. return fsConfig
  1076. }
  1077. func getGCSFsFromTemplate(fsConfig vfs.GCSFsConfig, replacements map[string]string) vfs.GCSFsConfig {
  1078. fsConfig.KeyPrefix = replacePlaceholders(fsConfig.KeyPrefix, replacements)
  1079. return fsConfig
  1080. }
  1081. func getAzBlobFsFromTemplate(fsConfig vfs.AzBlobFsConfig, replacements map[string]string) vfs.AzBlobFsConfig {
  1082. fsConfig.KeyPrefix = replacePlaceholders(fsConfig.KeyPrefix, replacements)
  1083. fsConfig.AccountName = replacePlaceholders(fsConfig.AccountName, replacements)
  1084. if fsConfig.AccountKey != nil && fsConfig.AccountKey.IsPlain() {
  1085. payload := replacePlaceholders(fsConfig.AccountKey.GetPayload(), replacements)
  1086. fsConfig.AccountKey = kms.NewPlainSecret(payload)
  1087. }
  1088. return fsConfig
  1089. }
  1090. func getSFTPFsFromTemplate(fsConfig vfs.SFTPFsConfig, replacements map[string]string) vfs.SFTPFsConfig {
  1091. fsConfig.Prefix = replacePlaceholders(fsConfig.Prefix, replacements)
  1092. fsConfig.Username = replacePlaceholders(fsConfig.Username, replacements)
  1093. if fsConfig.Password != nil && fsConfig.Password.IsPlain() {
  1094. payload := replacePlaceholders(fsConfig.Password.GetPayload(), replacements)
  1095. fsConfig.Password = kms.NewPlainSecret(payload)
  1096. }
  1097. return fsConfig
  1098. }
  1099. func getUserFromTemplate(user dataprovider.User, template userTemplateFields) dataprovider.User {
  1100. user.Username = template.Username
  1101. user.Password = template.Password
  1102. user.PublicKeys = nil
  1103. if template.PublicKey != "" {
  1104. user.PublicKeys = append(user.PublicKeys, template.PublicKey)
  1105. }
  1106. replacements := make(map[string]string)
  1107. replacements["%username%"] = user.Username
  1108. user.Password = replacePlaceholders(user.Password, replacements)
  1109. replacements["%password%"] = user.Password
  1110. user.HomeDir = replacePlaceholders(user.HomeDir, replacements)
  1111. var vfolders []vfs.VirtualFolder
  1112. for _, vfolder := range user.VirtualFolders {
  1113. vfolder.Name = replacePlaceholders(vfolder.Name, replacements)
  1114. vfolder.VirtualPath = replacePlaceholders(vfolder.VirtualPath, replacements)
  1115. vfolders = append(vfolders, vfolder)
  1116. }
  1117. user.VirtualFolders = vfolders
  1118. user.Description = replacePlaceholders(user.Description, replacements)
  1119. user.AdditionalInfo = replacePlaceholders(user.AdditionalInfo, replacements)
  1120. switch user.FsConfig.Provider {
  1121. case sdk.CryptedFilesystemProvider:
  1122. user.FsConfig.CryptConfig = getCryptFsFromTemplate(user.FsConfig.CryptConfig, replacements)
  1123. case sdk.S3FilesystemProvider:
  1124. user.FsConfig.S3Config = getS3FsFromTemplate(user.FsConfig.S3Config, replacements)
  1125. case sdk.GCSFilesystemProvider:
  1126. user.FsConfig.GCSConfig = getGCSFsFromTemplate(user.FsConfig.GCSConfig, replacements)
  1127. case sdk.AzureBlobFilesystemProvider:
  1128. user.FsConfig.AzBlobConfig = getAzBlobFsFromTemplate(user.FsConfig.AzBlobConfig, replacements)
  1129. case sdk.SFTPFilesystemProvider:
  1130. user.FsConfig.SFTPConfig = getSFTPFsFromTemplate(user.FsConfig.SFTPConfig, replacements)
  1131. }
  1132. return user
  1133. }
  1134. func getTransferLimits(r *http.Request) (int64, int64, int64, error) {
  1135. dataTransferUL, err := strconv.ParseInt(r.Form.Get("upload_data_transfer"), 10, 64)
  1136. if err != nil {
  1137. return 0, 0, 0, err
  1138. }
  1139. dataTransferDL, err := strconv.ParseInt(r.Form.Get("download_data_transfer"), 10, 64)
  1140. if err != nil {
  1141. return 0, 0, 0, err
  1142. }
  1143. dataTransferTotal, err := strconv.ParseInt(r.Form.Get("total_data_transfer"), 10, 64)
  1144. if err != nil {
  1145. return 0, 0, 0, err
  1146. }
  1147. return dataTransferUL, dataTransferDL, dataTransferTotal, nil
  1148. }
  1149. func getUserFromPostFields(r *http.Request) (dataprovider.User, error) {
  1150. var user dataprovider.User
  1151. err := r.ParseMultipartForm(maxRequestSize)
  1152. if err != nil {
  1153. return user, err
  1154. }
  1155. defer r.MultipartForm.RemoveAll() //nolint:errcheck
  1156. uid, err := strconv.Atoi(r.Form.Get("uid"))
  1157. if err != nil {
  1158. return user, err
  1159. }
  1160. gid, err := strconv.Atoi(r.Form.Get("gid"))
  1161. if err != nil {
  1162. return user, err
  1163. }
  1164. maxSessions, err := strconv.Atoi(r.Form.Get("max_sessions"))
  1165. if err != nil {
  1166. return user, err
  1167. }
  1168. quotaSize, err := strconv.ParseInt(r.Form.Get("quota_size"), 10, 64)
  1169. if err != nil {
  1170. return user, err
  1171. }
  1172. quotaFiles, err := strconv.Atoi(r.Form.Get("quota_files"))
  1173. if err != nil {
  1174. return user, err
  1175. }
  1176. bandwidthUL, err := strconv.ParseInt(r.Form.Get("upload_bandwidth"), 10, 64)
  1177. if err != nil {
  1178. return user, err
  1179. }
  1180. bandwidthDL, err := strconv.ParseInt(r.Form.Get("download_bandwidth"), 10, 64)
  1181. if err != nil {
  1182. return user, err
  1183. }
  1184. dataTransferUL, dataTransferDL, dataTransferTotal, err := getTransferLimits(r)
  1185. if err != nil {
  1186. return user, err
  1187. }
  1188. status, err := strconv.Atoi(r.Form.Get("status"))
  1189. if err != nil {
  1190. return user, err
  1191. }
  1192. expirationDateMillis := int64(0)
  1193. expirationDateString := r.Form.Get("expiration_date")
  1194. if strings.TrimSpace(expirationDateString) != "" {
  1195. expirationDate, err := time.Parse(webDateTimeFormat, expirationDateString)
  1196. if err != nil {
  1197. return user, err
  1198. }
  1199. expirationDateMillis = util.GetTimeAsMsSinceEpoch(expirationDate)
  1200. }
  1201. fsConfig, err := getFsConfigFromPostFields(r)
  1202. if err != nil {
  1203. return user, err
  1204. }
  1205. filters, err := getFiltersFromUserPostFields(r)
  1206. if err != nil {
  1207. return user, err
  1208. }
  1209. user = dataprovider.User{
  1210. BaseUser: sdk.BaseUser{
  1211. Username: r.Form.Get("username"),
  1212. Email: r.Form.Get("email"),
  1213. Password: r.Form.Get("password"),
  1214. PublicKeys: r.Form["public_keys"],
  1215. HomeDir: r.Form.Get("home_dir"),
  1216. UID: uid,
  1217. GID: gid,
  1218. Permissions: getUserPermissionsFromPostFields(r),
  1219. MaxSessions: maxSessions,
  1220. QuotaSize: quotaSize,
  1221. QuotaFiles: quotaFiles,
  1222. UploadBandwidth: bandwidthUL,
  1223. DownloadBandwidth: bandwidthDL,
  1224. UploadDataTransfer: dataTransferUL,
  1225. DownloadDataTransfer: dataTransferDL,
  1226. TotalDataTransfer: dataTransferTotal,
  1227. Status: status,
  1228. ExpirationDate: expirationDateMillis,
  1229. AdditionalInfo: r.Form.Get("additional_info"),
  1230. Description: r.Form.Get("description"),
  1231. },
  1232. Filters: dataprovider.UserFilters{
  1233. BaseUserFilters: filters,
  1234. },
  1235. VirtualFolders: getVirtualFoldersFromPostFields(r),
  1236. FsConfig: fsConfig,
  1237. }
  1238. maxFileSize, err := strconv.ParseInt(r.Form.Get("max_upload_file_size"), 10, 64)
  1239. user.Filters.MaxUploadFileSize = maxFileSize
  1240. return user, err
  1241. }
  1242. func handleWebAdminForgotPwd(w http.ResponseWriter, r *http.Request) {
  1243. r.Body = http.MaxBytesReader(w, r.Body, maxRequestSize)
  1244. if !smtp.IsEnabled() {
  1245. renderNotFoundPage(w, r, errors.New("this page does not exist"))
  1246. return
  1247. }
  1248. renderForgotPwdPage(w, "")
  1249. }
  1250. func handleWebAdminForgotPwdPost(w http.ResponseWriter, r *http.Request) {
  1251. r.Body = http.MaxBytesReader(w, r.Body, maxRequestSize)
  1252. err := r.ParseForm()
  1253. if err != nil {
  1254. renderForgotPwdPage(w, err.Error())
  1255. return
  1256. }
  1257. if err := verifyCSRFToken(r.Form.Get(csrfFormToken)); err != nil {
  1258. renderForbiddenPage(w, r, err.Error())
  1259. return
  1260. }
  1261. username := r.Form.Get("username")
  1262. err = handleForgotPassword(r, username, true)
  1263. if err != nil {
  1264. if e, ok := err.(*util.ValidationError); ok {
  1265. renderForgotPwdPage(w, e.GetErrorString())
  1266. return
  1267. }
  1268. renderForgotPwdPage(w, err.Error())
  1269. return
  1270. }
  1271. http.Redirect(w, r, webAdminResetPwdPath, http.StatusFound)
  1272. }
  1273. func handleWebAdminPasswordReset(w http.ResponseWriter, r *http.Request) {
  1274. r.Body = http.MaxBytesReader(w, r.Body, maxLoginBodySize)
  1275. if !smtp.IsEnabled() {
  1276. renderNotFoundPage(w, r, errors.New("this page does not exist"))
  1277. return
  1278. }
  1279. renderResetPwdPage(w, "")
  1280. }
  1281. func handleWebAdminTwoFactor(w http.ResponseWriter, r *http.Request) {
  1282. r.Body = http.MaxBytesReader(w, r.Body, maxRequestSize)
  1283. renderTwoFactorPage(w, "")
  1284. }
  1285. func handleWebAdminTwoFactorRecovery(w http.ResponseWriter, r *http.Request) {
  1286. r.Body = http.MaxBytesReader(w, r.Body, maxRequestSize)
  1287. renderTwoFactorRecoveryPage(w, "")
  1288. }
  1289. func handleWebAdminMFA(w http.ResponseWriter, r *http.Request) {
  1290. r.Body = http.MaxBytesReader(w, r.Body, maxRequestSize)
  1291. renderMFAPage(w, r)
  1292. }
  1293. func handleWebAdminProfile(w http.ResponseWriter, r *http.Request) {
  1294. r.Body = http.MaxBytesReader(w, r.Body, maxRequestSize)
  1295. renderProfilePage(w, r, "")
  1296. }
  1297. func handleWebAdminChangePwd(w http.ResponseWriter, r *http.Request) {
  1298. r.Body = http.MaxBytesReader(w, r.Body, maxRequestSize)
  1299. renderChangePasswordPage(w, r, "")
  1300. }
  1301. func handleWebAdminProfilePost(w http.ResponseWriter, r *http.Request) {
  1302. r.Body = http.MaxBytesReader(w, r.Body, maxRequestSize)
  1303. err := r.ParseForm()
  1304. if err != nil {
  1305. renderProfilePage(w, r, err.Error())
  1306. return
  1307. }
  1308. if err := verifyCSRFToken(r.Form.Get(csrfFormToken)); err != nil {
  1309. renderForbiddenPage(w, r, err.Error())
  1310. return
  1311. }
  1312. claims, err := getTokenClaims(r)
  1313. if err != nil || claims.Username == "" {
  1314. renderProfilePage(w, r, "Invalid token claims")
  1315. return
  1316. }
  1317. admin, err := dataprovider.AdminExists(claims.Username)
  1318. if err != nil {
  1319. renderProfilePage(w, r, err.Error())
  1320. return
  1321. }
  1322. admin.Filters.AllowAPIKeyAuth = len(r.Form.Get("allow_api_key_auth")) > 0
  1323. admin.Email = r.Form.Get("email")
  1324. admin.Description = r.Form.Get("description")
  1325. err = dataprovider.UpdateAdmin(&admin, dataprovider.ActionExecutorSelf, util.GetIPFromRemoteAddress(r.RemoteAddr))
  1326. if err != nil {
  1327. renderProfilePage(w, r, err.Error())
  1328. return
  1329. }
  1330. renderMessagePage(w, r, "Profile updated", "", http.StatusOK, nil,
  1331. "Your profile has been successfully updated")
  1332. }
  1333. func handleWebMaintenance(w http.ResponseWriter, r *http.Request) {
  1334. r.Body = http.MaxBytesReader(w, r.Body, maxRequestSize)
  1335. renderMaintenancePage(w, r, "")
  1336. }
  1337. func handleWebRestore(w http.ResponseWriter, r *http.Request) {
  1338. r.Body = http.MaxBytesReader(w, r.Body, MaxRestoreSize)
  1339. claims, err := getTokenClaims(r)
  1340. if err != nil || claims.Username == "" {
  1341. renderBadRequestPage(w, r, errors.New("invalid token claims"))
  1342. return
  1343. }
  1344. err = r.ParseMultipartForm(MaxRestoreSize)
  1345. if err != nil {
  1346. renderMaintenancePage(w, r, err.Error())
  1347. return
  1348. }
  1349. defer r.MultipartForm.RemoveAll() //nolint:errcheck
  1350. if err := verifyCSRFToken(r.Form.Get(csrfFormToken)); err != nil {
  1351. renderForbiddenPage(w, r, err.Error())
  1352. return
  1353. }
  1354. restoreMode, err := strconv.Atoi(r.Form.Get("mode"))
  1355. if err != nil {
  1356. renderMaintenancePage(w, r, err.Error())
  1357. return
  1358. }
  1359. scanQuota, err := strconv.Atoi(r.Form.Get("quota"))
  1360. if err != nil {
  1361. renderMaintenancePage(w, r, err.Error())
  1362. return
  1363. }
  1364. backupFile, _, err := r.FormFile("backup_file")
  1365. if err != nil {
  1366. renderMaintenancePage(w, r, err.Error())
  1367. return
  1368. }
  1369. defer backupFile.Close()
  1370. backupContent, err := io.ReadAll(backupFile)
  1371. if err != nil || len(backupContent) == 0 {
  1372. if len(backupContent) == 0 {
  1373. err = errors.New("backup file size must be greater than 0")
  1374. }
  1375. renderMaintenancePage(w, r, err.Error())
  1376. return
  1377. }
  1378. if err := restoreBackup(backupContent, "", scanQuota, restoreMode, claims.Username, util.GetIPFromRemoteAddress(r.RemoteAddr)); err != nil {
  1379. renderMaintenancePage(w, r, err.Error())
  1380. return
  1381. }
  1382. renderMessagePage(w, r, "Data restored", "", http.StatusOK, nil, "Your backup was successfully restored")
  1383. }
  1384. func handleGetWebAdmins(w http.ResponseWriter, r *http.Request) {
  1385. r.Body = http.MaxBytesReader(w, r.Body, maxRequestSize)
  1386. limit := defaultQueryLimit
  1387. if _, ok := r.URL.Query()["qlimit"]; ok {
  1388. var err error
  1389. limit, err = strconv.Atoi(r.URL.Query().Get("qlimit"))
  1390. if err != nil {
  1391. limit = defaultQueryLimit
  1392. }
  1393. }
  1394. admins := make([]dataprovider.Admin, 0, limit)
  1395. for {
  1396. a, err := dataprovider.GetAdmins(limit, len(admins), dataprovider.OrderASC)
  1397. if err != nil {
  1398. renderInternalServerErrorPage(w, r, err)
  1399. return
  1400. }
  1401. admins = append(admins, a...)
  1402. if len(a) < limit {
  1403. break
  1404. }
  1405. }
  1406. data := adminsPage{
  1407. basePage: getBasePageData(pageAdminsTitle, webAdminsPath, r),
  1408. Admins: admins,
  1409. }
  1410. renderAdminTemplate(w, templateAdmins, data)
  1411. }
  1412. func handleWebAdminSetupGet(w http.ResponseWriter, r *http.Request) {
  1413. r.Body = http.MaxBytesReader(w, r.Body, maxLoginBodySize)
  1414. if dataprovider.HasAdmin() {
  1415. http.Redirect(w, r, webAdminLoginPath, http.StatusFound)
  1416. return
  1417. }
  1418. renderAdminSetupPage(w, r, "", "")
  1419. }
  1420. func handleWebAddAdminGet(w http.ResponseWriter, r *http.Request) {
  1421. r.Body = http.MaxBytesReader(w, r.Body, maxRequestSize)
  1422. admin := &dataprovider.Admin{Status: 1}
  1423. renderAddUpdateAdminPage(w, r, admin, "", true)
  1424. }
  1425. func handleWebUpdateAdminGet(w http.ResponseWriter, r *http.Request) {
  1426. r.Body = http.MaxBytesReader(w, r.Body, maxRequestSize)
  1427. username := getURLParam(r, "username")
  1428. admin, err := dataprovider.AdminExists(username)
  1429. if err == nil {
  1430. renderAddUpdateAdminPage(w, r, &admin, "", false)
  1431. } else if _, ok := err.(*util.RecordNotFoundError); ok {
  1432. renderNotFoundPage(w, r, err)
  1433. } else {
  1434. renderInternalServerErrorPage(w, r, err)
  1435. }
  1436. }
  1437. func handleWebAddAdminPost(w http.ResponseWriter, r *http.Request) {
  1438. r.Body = http.MaxBytesReader(w, r.Body, maxRequestSize)
  1439. claims, err := getTokenClaims(r)
  1440. if err != nil || claims.Username == "" {
  1441. renderBadRequestPage(w, r, errors.New("invalid token claims"))
  1442. return
  1443. }
  1444. admin, err := getAdminFromPostFields(r)
  1445. if err != nil {
  1446. renderAddUpdateAdminPage(w, r, &admin, err.Error(), true)
  1447. return
  1448. }
  1449. if err := verifyCSRFToken(r.Form.Get(csrfFormToken)); err != nil {
  1450. renderForbiddenPage(w, r, err.Error())
  1451. return
  1452. }
  1453. err = dataprovider.AddAdmin(&admin, claims.Username, util.GetIPFromRemoteAddress(r.Method))
  1454. if err != nil {
  1455. renderAddUpdateAdminPage(w, r, &admin, err.Error(), true)
  1456. return
  1457. }
  1458. http.Redirect(w, r, webAdminsPath, http.StatusSeeOther)
  1459. }
  1460. func handleWebUpdateAdminPost(w http.ResponseWriter, r *http.Request) {
  1461. r.Body = http.MaxBytesReader(w, r.Body, maxRequestSize)
  1462. username := getURLParam(r, "username")
  1463. admin, err := dataprovider.AdminExists(username)
  1464. if _, ok := err.(*util.RecordNotFoundError); ok {
  1465. renderNotFoundPage(w, r, err)
  1466. return
  1467. } else if err != nil {
  1468. renderInternalServerErrorPage(w, r, err)
  1469. return
  1470. }
  1471. updatedAdmin, err := getAdminFromPostFields(r)
  1472. if err != nil {
  1473. renderAddUpdateAdminPage(w, r, &updatedAdmin, err.Error(), false)
  1474. return
  1475. }
  1476. if err := verifyCSRFToken(r.Form.Get(csrfFormToken)); err != nil {
  1477. renderForbiddenPage(w, r, err.Error())
  1478. return
  1479. }
  1480. updatedAdmin.ID = admin.ID
  1481. updatedAdmin.Username = admin.Username
  1482. if updatedAdmin.Password == "" {
  1483. updatedAdmin.Password = admin.Password
  1484. }
  1485. updatedAdmin.Filters.TOTPConfig = admin.Filters.TOTPConfig
  1486. updatedAdmin.Filters.RecoveryCodes = admin.Filters.RecoveryCodes
  1487. claims, err := getTokenClaims(r)
  1488. if err != nil || claims.Username == "" {
  1489. renderAddUpdateAdminPage(w, r, &updatedAdmin, "Invalid token claims", false)
  1490. return
  1491. }
  1492. if username == claims.Username {
  1493. if claims.isCriticalPermRemoved(updatedAdmin.Permissions) {
  1494. renderAddUpdateAdminPage(w, r, &updatedAdmin, "You cannot remove these permissions to yourself", false)
  1495. return
  1496. }
  1497. if updatedAdmin.Status == 0 {
  1498. renderAddUpdateAdminPage(w, r, &updatedAdmin, "You cannot disable yourself", false)
  1499. return
  1500. }
  1501. }
  1502. err = dataprovider.UpdateAdmin(&updatedAdmin, claims.Username, util.GetIPFromRemoteAddress(r.RemoteAddr))
  1503. if err != nil {
  1504. renderAddUpdateAdminPage(w, r, &admin, err.Error(), false)
  1505. return
  1506. }
  1507. http.Redirect(w, r, webAdminsPath, http.StatusSeeOther)
  1508. }
  1509. func handleWebDefenderPage(w http.ResponseWriter, r *http.Request) {
  1510. r.Body = http.MaxBytesReader(w, r.Body, maxRequestSize)
  1511. data := defenderHostsPage{
  1512. basePage: getBasePageData(pageDefenderTitle, webDefenderPath, r),
  1513. DefenderHostsURL: webDefenderHostsPath,
  1514. }
  1515. renderAdminTemplate(w, templateDefender, data)
  1516. }
  1517. func handleGetWebUsers(w http.ResponseWriter, r *http.Request) {
  1518. r.Body = http.MaxBytesReader(w, r.Body, maxRequestSize)
  1519. limit := defaultQueryLimit
  1520. if _, ok := r.URL.Query()["qlimit"]; ok {
  1521. var err error
  1522. limit, err = strconv.Atoi(r.URL.Query().Get("qlimit"))
  1523. if err != nil {
  1524. limit = defaultQueryLimit
  1525. }
  1526. }
  1527. users := make([]dataprovider.User, 0, limit)
  1528. for {
  1529. u, err := dataprovider.GetUsers(limit, len(users), dataprovider.OrderASC)
  1530. if err != nil {
  1531. renderInternalServerErrorPage(w, r, err)
  1532. return
  1533. }
  1534. users = append(users, u...)
  1535. if len(u) < limit {
  1536. break
  1537. }
  1538. }
  1539. data := usersPage{
  1540. basePage: getBasePageData(pageUsersTitle, webUsersPath, r),
  1541. Users: users,
  1542. }
  1543. renderAdminTemplate(w, templateUsers, data)
  1544. }
  1545. func handleWebTemplateFolderGet(w http.ResponseWriter, r *http.Request) {
  1546. r.Body = http.MaxBytesReader(w, r.Body, maxRequestSize)
  1547. if r.URL.Query().Get("from") != "" {
  1548. name := r.URL.Query().Get("from")
  1549. folder, err := dataprovider.GetFolderByName(name)
  1550. if err == nil {
  1551. folder.FsConfig.SetEmptySecrets()
  1552. renderFolderPage(w, r, folder, folderPageModeTemplate, "")
  1553. } else if _, ok := err.(*util.RecordNotFoundError); ok {
  1554. renderNotFoundPage(w, r, err)
  1555. } else {
  1556. renderInternalServerErrorPage(w, r, err)
  1557. }
  1558. } else {
  1559. folder := vfs.BaseVirtualFolder{}
  1560. renderFolderPage(w, r, folder, folderPageModeTemplate, "")
  1561. }
  1562. }
  1563. func handleWebTemplateFolderPost(w http.ResponseWriter, r *http.Request) {
  1564. r.Body = http.MaxBytesReader(w, r.Body, maxRequestSize)
  1565. claims, err := getTokenClaims(r)
  1566. if err != nil || claims.Username == "" {
  1567. renderBadRequestPage(w, r, errors.New("invalid token claims"))
  1568. return
  1569. }
  1570. templateFolder := vfs.BaseVirtualFolder{}
  1571. err = r.ParseMultipartForm(maxRequestSize)
  1572. if err != nil {
  1573. renderMessagePage(w, r, "Error parsing folders fields", "", http.StatusBadRequest, err, "")
  1574. return
  1575. }
  1576. defer r.MultipartForm.RemoveAll() //nolint:errcheck
  1577. if err := verifyCSRFToken(r.Form.Get(csrfFormToken)); err != nil {
  1578. renderForbiddenPage(w, r, err.Error())
  1579. return
  1580. }
  1581. templateFolder.MappedPath = r.Form.Get("mapped_path")
  1582. templateFolder.Description = r.Form.Get("description")
  1583. fsConfig, err := getFsConfigFromPostFields(r)
  1584. if err != nil {
  1585. renderMessagePage(w, r, "Error parsing folders fields", "", http.StatusBadRequest, err, "")
  1586. return
  1587. }
  1588. templateFolder.FsConfig = fsConfig
  1589. var dump dataprovider.BackupData
  1590. dump.Version = dataprovider.DumpVersion
  1591. foldersFields := getFoldersForTemplate(r)
  1592. for _, tmpl := range foldersFields {
  1593. f := getFolderFromTemplate(templateFolder, tmpl)
  1594. if err := dataprovider.ValidateFolder(&f); err != nil {
  1595. renderMessagePage(w, r, "Folder validation error", fmt.Sprintf("Error validating folder %#v", f.Name),
  1596. http.StatusBadRequest, err, "")
  1597. return
  1598. }
  1599. dump.Folders = append(dump.Folders, f)
  1600. }
  1601. if len(dump.Folders) == 0 {
  1602. renderMessagePage(w, r, "No folders defined", "No valid folders defined, unable to complete the requested action",
  1603. http.StatusBadRequest, nil, "")
  1604. return
  1605. }
  1606. if r.Form.Get("form_action") == "export_from_template" {
  1607. w.Header().Set("Content-Disposition", fmt.Sprintf("attachment; filename=\"sftpgo-%v-folders-from-template.json\"",
  1608. len(dump.Folders)))
  1609. render.JSON(w, r, dump)
  1610. return
  1611. }
  1612. if err = RestoreFolders(dump.Folders, "", 1, 0, claims.Username, util.GetIPFromRemoteAddress(r.RemoteAddr)); err != nil {
  1613. renderMessagePage(w, r, "Unable to save folders", "Cannot save the defined folders:",
  1614. getRespStatus(err), err, "")
  1615. return
  1616. }
  1617. http.Redirect(w, r, webFoldersPath, http.StatusSeeOther)
  1618. }
  1619. func handleWebTemplateUserGet(w http.ResponseWriter, r *http.Request) {
  1620. r.Body = http.MaxBytesReader(w, r.Body, maxRequestSize)
  1621. if r.URL.Query().Get("from") != "" {
  1622. username := r.URL.Query().Get("from")
  1623. user, err := dataprovider.UserExists(username)
  1624. if err == nil {
  1625. user.SetEmptySecrets()
  1626. user.PublicKeys = nil
  1627. user.Email = ""
  1628. user.Description = ""
  1629. renderUserPage(w, r, &user, userPageModeTemplate, "")
  1630. } else if _, ok := err.(*util.RecordNotFoundError); ok {
  1631. renderNotFoundPage(w, r, err)
  1632. } else {
  1633. renderInternalServerErrorPage(w, r, err)
  1634. }
  1635. } else {
  1636. user := dataprovider.User{BaseUser: sdk.BaseUser{
  1637. Status: 1,
  1638. Permissions: map[string][]string{
  1639. "/": {dataprovider.PermAny},
  1640. },
  1641. }}
  1642. renderUserPage(w, r, &user, userPageModeTemplate, "")
  1643. }
  1644. }
  1645. func handleWebTemplateUserPost(w http.ResponseWriter, r *http.Request) {
  1646. r.Body = http.MaxBytesReader(w, r.Body, maxRequestSize)
  1647. claims, err := getTokenClaims(r)
  1648. if err != nil || claims.Username == "" {
  1649. renderBadRequestPage(w, r, errors.New("invalid token claims"))
  1650. return
  1651. }
  1652. templateUser, err := getUserFromPostFields(r)
  1653. if err != nil {
  1654. renderMessagePage(w, r, "Error parsing user fields", "", http.StatusBadRequest, err, "")
  1655. return
  1656. }
  1657. if err := verifyCSRFToken(r.Form.Get(csrfFormToken)); err != nil {
  1658. renderForbiddenPage(w, r, err.Error())
  1659. return
  1660. }
  1661. var dump dataprovider.BackupData
  1662. dump.Version = dataprovider.DumpVersion
  1663. userTmplFields := getUsersForTemplate(r)
  1664. for _, tmpl := range userTmplFields {
  1665. u := getUserFromTemplate(templateUser, tmpl)
  1666. if err := dataprovider.ValidateUser(&u); err != nil {
  1667. renderMessagePage(w, r, "User validation error", fmt.Sprintf("Error validating user %#v", u.Username),
  1668. http.StatusBadRequest, err, "")
  1669. return
  1670. }
  1671. dump.Users = append(dump.Users, u)
  1672. for _, folder := range u.VirtualFolders {
  1673. if !dump.HasFolder(folder.Name) {
  1674. dump.Folders = append(dump.Folders, folder.BaseVirtualFolder)
  1675. }
  1676. }
  1677. }
  1678. if len(dump.Users) == 0 {
  1679. renderMessagePage(w, r, "No users defined", "No valid users defined, unable to complete the requested action",
  1680. http.StatusBadRequest, nil, "")
  1681. return
  1682. }
  1683. if r.Form.Get("form_action") == "export_from_template" {
  1684. w.Header().Set("Content-Disposition", fmt.Sprintf("attachment; filename=\"sftpgo-%v-users-from-template.json\"",
  1685. len(dump.Users)))
  1686. render.JSON(w, r, dump)
  1687. return
  1688. }
  1689. if err = RestoreUsers(dump.Users, "", 1, 0, claims.Username, util.GetIPFromRemoteAddress(r.RemoteAddr)); err != nil {
  1690. renderMessagePage(w, r, "Unable to save users", "Cannot save the defined users:",
  1691. getRespStatus(err), err, "")
  1692. return
  1693. }
  1694. http.Redirect(w, r, webUsersPath, http.StatusSeeOther)
  1695. }
  1696. func handleWebAddUserGet(w http.ResponseWriter, r *http.Request) {
  1697. r.Body = http.MaxBytesReader(w, r.Body, maxRequestSize)
  1698. user := dataprovider.User{BaseUser: sdk.BaseUser{
  1699. Status: 1,
  1700. Permissions: map[string][]string{
  1701. "/": {dataprovider.PermAny},
  1702. },
  1703. }}
  1704. renderUserPage(w, r, &user, userPageModeAdd, "")
  1705. }
  1706. func handleWebUpdateUserGet(w http.ResponseWriter, r *http.Request) {
  1707. r.Body = http.MaxBytesReader(w, r.Body, maxRequestSize)
  1708. username := getURLParam(r, "username")
  1709. user, err := dataprovider.UserExists(username)
  1710. if err == nil {
  1711. renderUserPage(w, r, &user, userPageModeUpdate, "")
  1712. } else if _, ok := err.(*util.RecordNotFoundError); ok {
  1713. renderNotFoundPage(w, r, err)
  1714. } else {
  1715. renderInternalServerErrorPage(w, r, err)
  1716. }
  1717. }
  1718. func handleWebAddUserPost(w http.ResponseWriter, r *http.Request) {
  1719. r.Body = http.MaxBytesReader(w, r.Body, maxRequestSize)
  1720. claims, err := getTokenClaims(r)
  1721. if err != nil || claims.Username == "" {
  1722. renderBadRequestPage(w, r, errors.New("invalid token claims"))
  1723. return
  1724. }
  1725. user, err := getUserFromPostFields(r)
  1726. if err != nil {
  1727. renderUserPage(w, r, &user, userPageModeAdd, err.Error())
  1728. return
  1729. }
  1730. if err := verifyCSRFToken(r.Form.Get(csrfFormToken)); err != nil {
  1731. renderForbiddenPage(w, r, err.Error())
  1732. return
  1733. }
  1734. err = dataprovider.AddUser(&user, claims.Username, util.GetIPFromRemoteAddress(r.RemoteAddr))
  1735. if err == nil {
  1736. http.Redirect(w, r, webUsersPath, http.StatusSeeOther)
  1737. } else {
  1738. renderUserPage(w, r, &user, userPageModeAdd, err.Error())
  1739. }
  1740. }
  1741. func handleWebUpdateUserPost(w http.ResponseWriter, r *http.Request) {
  1742. r.Body = http.MaxBytesReader(w, r.Body, maxRequestSize)
  1743. claims, err := getTokenClaims(r)
  1744. if err != nil || claims.Username == "" {
  1745. renderBadRequestPage(w, r, errors.New("invalid token claims"))
  1746. return
  1747. }
  1748. username := getURLParam(r, "username")
  1749. user, err := dataprovider.UserExists(username)
  1750. if _, ok := err.(*util.RecordNotFoundError); ok {
  1751. renderNotFoundPage(w, r, err)
  1752. return
  1753. } else if err != nil {
  1754. renderInternalServerErrorPage(w, r, err)
  1755. return
  1756. }
  1757. updatedUser, err := getUserFromPostFields(r)
  1758. if err != nil {
  1759. renderUserPage(w, r, &user, userPageModeUpdate, err.Error())
  1760. return
  1761. }
  1762. if err := verifyCSRFToken(r.Form.Get(csrfFormToken)); err != nil {
  1763. renderForbiddenPage(w, r, err.Error())
  1764. return
  1765. }
  1766. updatedUser.ID = user.ID
  1767. updatedUser.Username = user.Username
  1768. updatedUser.Filters.RecoveryCodes = user.Filters.RecoveryCodes
  1769. updatedUser.Filters.TOTPConfig = user.Filters.TOTPConfig
  1770. updatedUser.SetEmptySecretsIfNil()
  1771. if updatedUser.Password == redactedSecret {
  1772. updatedUser.Password = user.Password
  1773. }
  1774. updateEncryptedSecrets(&updatedUser.FsConfig, user.FsConfig.S3Config.AccessSecret, user.FsConfig.AzBlobConfig.AccountKey,
  1775. user.FsConfig.AzBlobConfig.SASURL, user.FsConfig.GCSConfig.Credentials, user.FsConfig.CryptConfig.Passphrase,
  1776. user.FsConfig.SFTPConfig.Password, user.FsConfig.SFTPConfig.PrivateKey)
  1777. err = dataprovider.UpdateUser(&updatedUser, claims.Username, util.GetIPFromRemoteAddress(r.RemoteAddr))
  1778. if err == nil {
  1779. if len(r.Form.Get("disconnect")) > 0 {
  1780. disconnectUser(user.Username)
  1781. }
  1782. http.Redirect(w, r, webUsersPath, http.StatusSeeOther)
  1783. } else {
  1784. renderUserPage(w, r, &user, userPageModeUpdate, err.Error())
  1785. }
  1786. }
  1787. func handleWebGetStatus(w http.ResponseWriter, r *http.Request) {
  1788. r.Body = http.MaxBytesReader(w, r.Body, maxRequestSize)
  1789. data := statusPage{
  1790. basePage: getBasePageData(pageStatusTitle, webStatusPath, r),
  1791. Status: getServicesStatus(),
  1792. }
  1793. renderAdminTemplate(w, templateStatus, data)
  1794. }
  1795. func handleWebGetConnections(w http.ResponseWriter, r *http.Request) {
  1796. r.Body = http.MaxBytesReader(w, r.Body, maxRequestSize)
  1797. connectionStats := common.Connections.GetStats()
  1798. data := connectionsPage{
  1799. basePage: getBasePageData(pageConnectionsTitle, webConnectionsPath, r),
  1800. Connections: connectionStats,
  1801. }
  1802. renderAdminTemplate(w, templateConnections, data)
  1803. }
  1804. func handleWebAddFolderGet(w http.ResponseWriter, r *http.Request) {
  1805. r.Body = http.MaxBytesReader(w, r.Body, maxRequestSize)
  1806. renderFolderPage(w, r, vfs.BaseVirtualFolder{}, folderPageModeAdd, "")
  1807. }
  1808. func handleWebAddFolderPost(w http.ResponseWriter, r *http.Request) {
  1809. r.Body = http.MaxBytesReader(w, r.Body, maxRequestSize)
  1810. folder := vfs.BaseVirtualFolder{}
  1811. err := r.ParseMultipartForm(maxRequestSize)
  1812. if err != nil {
  1813. renderFolderPage(w, r, folder, folderPageModeAdd, err.Error())
  1814. return
  1815. }
  1816. defer r.MultipartForm.RemoveAll() //nolint:errcheck
  1817. if err := verifyCSRFToken(r.Form.Get(csrfFormToken)); err != nil {
  1818. renderForbiddenPage(w, r, err.Error())
  1819. return
  1820. }
  1821. folder.MappedPath = r.Form.Get("mapped_path")
  1822. folder.Name = r.Form.Get("name")
  1823. folder.Description = r.Form.Get("description")
  1824. fsConfig, err := getFsConfigFromPostFields(r)
  1825. if err != nil {
  1826. renderFolderPage(w, r, folder, folderPageModeAdd, err.Error())
  1827. return
  1828. }
  1829. folder.FsConfig = fsConfig
  1830. err = dataprovider.AddFolder(&folder)
  1831. if err == nil {
  1832. http.Redirect(w, r, webFoldersPath, http.StatusSeeOther)
  1833. } else {
  1834. renderFolderPage(w, r, folder, folderPageModeAdd, err.Error())
  1835. }
  1836. }
  1837. func handleWebUpdateFolderGet(w http.ResponseWriter, r *http.Request) {
  1838. r.Body = http.MaxBytesReader(w, r.Body, maxRequestSize)
  1839. name := getURLParam(r, "name")
  1840. folder, err := dataprovider.GetFolderByName(name)
  1841. if err == nil {
  1842. renderFolderPage(w, r, folder, folderPageModeUpdate, "")
  1843. } else if _, ok := err.(*util.RecordNotFoundError); ok {
  1844. renderNotFoundPage(w, r, err)
  1845. } else {
  1846. renderInternalServerErrorPage(w, r, err)
  1847. }
  1848. }
  1849. func handleWebUpdateFolderPost(w http.ResponseWriter, r *http.Request) {
  1850. r.Body = http.MaxBytesReader(w, r.Body, maxRequestSize)
  1851. claims, err := getTokenClaims(r)
  1852. if err != nil || claims.Username == "" {
  1853. renderBadRequestPage(w, r, errors.New("invalid token claims"))
  1854. return
  1855. }
  1856. name := getURLParam(r, "name")
  1857. folder, err := dataprovider.GetFolderByName(name)
  1858. if _, ok := err.(*util.RecordNotFoundError); ok {
  1859. renderNotFoundPage(w, r, err)
  1860. return
  1861. } else if err != nil {
  1862. renderInternalServerErrorPage(w, r, err)
  1863. return
  1864. }
  1865. err = r.ParseMultipartForm(maxRequestSize)
  1866. if err != nil {
  1867. renderFolderPage(w, r, folder, folderPageModeUpdate, err.Error())
  1868. return
  1869. }
  1870. defer r.MultipartForm.RemoveAll() //nolint:errcheck
  1871. if err := verifyCSRFToken(r.Form.Get(csrfFormToken)); err != nil {
  1872. renderForbiddenPage(w, r, err.Error())
  1873. return
  1874. }
  1875. fsConfig, err := getFsConfigFromPostFields(r)
  1876. if err != nil {
  1877. renderFolderPage(w, r, folder, folderPageModeUpdate, err.Error())
  1878. return
  1879. }
  1880. updatedFolder := &vfs.BaseVirtualFolder{
  1881. MappedPath: r.Form.Get("mapped_path"),
  1882. Description: r.Form.Get("description"),
  1883. }
  1884. updatedFolder.ID = folder.ID
  1885. updatedFolder.Name = folder.Name
  1886. updatedFolder.FsConfig = fsConfig
  1887. updatedFolder.FsConfig.SetEmptySecretsIfNil()
  1888. updateEncryptedSecrets(&updatedFolder.FsConfig, folder.FsConfig.S3Config.AccessSecret, folder.FsConfig.AzBlobConfig.AccountKey,
  1889. folder.FsConfig.AzBlobConfig.SASURL, folder.FsConfig.GCSConfig.Credentials, folder.FsConfig.CryptConfig.Passphrase,
  1890. folder.FsConfig.SFTPConfig.Password, folder.FsConfig.SFTPConfig.PrivateKey)
  1891. err = dataprovider.UpdateFolder(updatedFolder, folder.Users, claims.Username, util.GetIPFromRemoteAddress(r.RemoteAddr))
  1892. if err != nil {
  1893. renderFolderPage(w, r, folder, folderPageModeUpdate, err.Error())
  1894. return
  1895. }
  1896. http.Redirect(w, r, webFoldersPath, http.StatusSeeOther)
  1897. }
  1898. func getWebVirtualFolders(w http.ResponseWriter, r *http.Request, limit int) ([]vfs.BaseVirtualFolder, error) {
  1899. folders := make([]vfs.BaseVirtualFolder, 0, limit)
  1900. for {
  1901. f, err := dataprovider.GetFolders(limit, len(folders), dataprovider.OrderASC)
  1902. if err != nil {
  1903. renderInternalServerErrorPage(w, r, err)
  1904. return folders, err
  1905. }
  1906. folders = append(folders, f...)
  1907. if len(f) < limit {
  1908. break
  1909. }
  1910. }
  1911. return folders, nil
  1912. }
  1913. func handleWebGetFolders(w http.ResponseWriter, r *http.Request) {
  1914. r.Body = http.MaxBytesReader(w, r.Body, maxRequestSize)
  1915. limit := defaultQueryLimit
  1916. if _, ok := r.URL.Query()["qlimit"]; ok {
  1917. var err error
  1918. limit, err = strconv.Atoi(r.URL.Query().Get("qlimit"))
  1919. if err != nil {
  1920. limit = defaultQueryLimit
  1921. }
  1922. }
  1923. folders, err := getWebVirtualFolders(w, r, limit)
  1924. if err != nil {
  1925. return
  1926. }
  1927. data := foldersPage{
  1928. basePage: getBasePageData(pageFoldersTitle, webFoldersPath, r),
  1929. Folders: folders,
  1930. }
  1931. renderAdminTemplate(w, templateFolders, data)
  1932. }