webadmin.go 65 KB

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