webadmin.go 63 KB

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