webadmin.go 65 KB

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