webadmin.go 79 KB

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