webadmin.go 81 KB

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