webadmin.go 61 KB

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