webadmin.go 108 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869287028712872287328742875287628772878287928802881288228832884288528862887288828892890289128922893289428952896289728982899290029012902290329042905290629072908290929102911291229132914291529162917291829192920292129222923292429252926292729282929293029312932293329342935293629372938293929402941294229432944294529462947294829492950295129522953295429552956295729582959296029612962296329642965296629672968296929702971297229732974297529762977297829792980298129822983298429852986298729882989299029912992299329942995299629972998299930003001300230033004300530063007300830093010301130123013301430153016301730183019302030213022302330243025302630273028302930303031303230333034303530363037303830393040304130423043304430453046304730483049305030513052305330543055305630573058305930603061306230633064306530663067306830693070307130723073307430753076307730783079308030813082308330843085308630873088308930903091309230933094309530963097309830993100310131023103310431053106310731083109311031113112311331143115311631173118311931203121312231233124312531263127312831293130313131323133313431353136313731383139314031413142314331443145314631473148314931503151315231533154315531563157315831593160316131623163316431653166316731683169317031713172317331743175317631773178317931803181318231833184318531863187318831893190319131923193319431953196319731983199320032013202320332043205320632073208320932103211321232133214321532163217321832193220322132223223322432253226322732283229323032313232323332343235323632373238323932403241324232433244324532463247324832493250325132523253325432553256325732583259326032613262326332643265326632673268326932703271327232733274327532763277327832793280328132823283328432853286328732883289329032913292
  1. // Copyright (C) 2019-2022 Nicola Murino
  2. //
  3. // This program is free software: you can redistribute it and/or modify
  4. // it under the terms of the GNU Affero General Public License as published
  5. // by the Free Software Foundation, version 3.
  6. //
  7. // This program is distributed in the hope that it will be useful,
  8. // but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  10. // GNU Affero General Public License for more details.
  11. //
  12. // You should have received a copy of the GNU Affero General Public License
  13. // along with this program. If not, see <https://www.gnu.org/licenses/>.
  14. package httpd
  15. import (
  16. "errors"
  17. "fmt"
  18. "html/template"
  19. "io"
  20. "net/http"
  21. "net/url"
  22. "os"
  23. "path/filepath"
  24. "sort"
  25. "strconv"
  26. "strings"
  27. "time"
  28. "github.com/go-chi/render"
  29. "github.com/sftpgo/sdk"
  30. sdkkms "github.com/sftpgo/sdk/kms"
  31. "github.com/drakkan/sftpgo/v2/internal/common"
  32. "github.com/drakkan/sftpgo/v2/internal/dataprovider"
  33. "github.com/drakkan/sftpgo/v2/internal/kms"
  34. "github.com/drakkan/sftpgo/v2/internal/mfa"
  35. "github.com/drakkan/sftpgo/v2/internal/smtp"
  36. "github.com/drakkan/sftpgo/v2/internal/util"
  37. "github.com/drakkan/sftpgo/v2/internal/version"
  38. "github.com/drakkan/sftpgo/v2/internal/vfs"
  39. )
  40. type userPageMode int
  41. const (
  42. userPageModeAdd userPageMode = iota + 1
  43. userPageModeUpdate
  44. userPageModeTemplate
  45. )
  46. type folderPageMode int
  47. const (
  48. folderPageModeAdd folderPageMode = iota + 1
  49. folderPageModeUpdate
  50. folderPageModeTemplate
  51. )
  52. type genericPageMode int
  53. const (
  54. genericPageModeAdd genericPageMode = iota + 1
  55. genericPageModeUpdate
  56. )
  57. const (
  58. templateAdminDir = "webadmin"
  59. templateBase = "base.html"
  60. templateBaseLogin = "baselogin.html"
  61. templateFsConfig = "fsconfig.html"
  62. templateSharedComponents = "sharedcomponents.html"
  63. templateUsers = "users.html"
  64. templateUser = "user.html"
  65. templateAdmins = "admins.html"
  66. templateAdmin = "admin.html"
  67. templateConnections = "connections.html"
  68. templateGroups = "groups.html"
  69. templateGroup = "group.html"
  70. templateFolders = "folders.html"
  71. templateFolder = "folder.html"
  72. templateEventRules = "eventrules.html"
  73. templateEventRule = "eventrule.html"
  74. templateEventActions = "eventactions.html"
  75. templateEventAction = "eventaction.html"
  76. templateMessage = "message.html"
  77. templateStatus = "status.html"
  78. templateLogin = "login.html"
  79. templateDefender = "defender.html"
  80. templateProfile = "profile.html"
  81. templateChangePwd = "changepassword.html"
  82. templateMaintenance = "maintenance.html"
  83. templateMFA = "mfa.html"
  84. templateSetup = "adminsetup.html"
  85. pageUsersTitle = "Users"
  86. pageAdminsTitle = "Admins"
  87. pageConnectionsTitle = "Connections"
  88. pageStatusTitle = "Status"
  89. pageFoldersTitle = "Folders"
  90. pageGroupsTitle = "Groups"
  91. pageEventRulesTitle = "Event rules"
  92. pageEventActionsTitle = "Event actions"
  93. pageProfileTitle = "My profile"
  94. pageChangePwdTitle = "Change password"
  95. pageMaintenanceTitle = "Maintenance"
  96. pageDefenderTitle = "Defender"
  97. pageForgotPwdTitle = "SFTPGo Admin - Forgot password"
  98. pageResetPwdTitle = "SFTPGo Admin - Reset password"
  99. pageSetupTitle = "Create first admin user"
  100. defaultQueryLimit = 500
  101. inversePatternType = "inverse"
  102. )
  103. var (
  104. adminTemplates = make(map[string]*template.Template)
  105. )
  106. type basePage struct {
  107. Title string
  108. CurrentURL string
  109. UsersURL string
  110. UserURL string
  111. UserTemplateURL string
  112. AdminsURL string
  113. AdminURL string
  114. QuotaScanURL string
  115. ConnectionsURL string
  116. GroupsURL string
  117. GroupURL string
  118. FoldersURL string
  119. FolderURL string
  120. FolderTemplateURL string
  121. DefenderURL string
  122. LogoutURL string
  123. ProfileURL string
  124. ChangePwdURL string
  125. MFAURL string
  126. EventRulesURL string
  127. EventRuleURL string
  128. EventActionsURL string
  129. EventActionURL string
  130. FolderQuotaScanURL string
  131. StatusURL string
  132. MaintenanceURL string
  133. StaticURL string
  134. UsersTitle string
  135. AdminsTitle string
  136. ConnectionsTitle string
  137. FoldersTitle string
  138. GroupsTitle string
  139. EventRulesTitle string
  140. EventActionsTitle string
  141. StatusTitle string
  142. MaintenanceTitle string
  143. DefenderTitle string
  144. Version string
  145. CSRFToken string
  146. IsEventManagerPage bool
  147. HasDefender bool
  148. HasExternalLogin bool
  149. LoggedAdmin *dataprovider.Admin
  150. Branding UIBranding
  151. }
  152. type usersPage struct {
  153. basePage
  154. Users []dataprovider.User
  155. }
  156. type adminsPage struct {
  157. basePage
  158. Admins []dataprovider.Admin
  159. }
  160. type foldersPage struct {
  161. basePage
  162. Folders []vfs.BaseVirtualFolder
  163. }
  164. type groupsPage struct {
  165. basePage
  166. Groups []dataprovider.Group
  167. }
  168. type eventRulesPage struct {
  169. basePage
  170. Rules []dataprovider.EventRule
  171. }
  172. type eventActionsPage struct {
  173. basePage
  174. Actions []dataprovider.BaseEventAction
  175. }
  176. type connectionsPage struct {
  177. basePage
  178. Connections []common.ConnectionStatus
  179. }
  180. type statusPage struct {
  181. basePage
  182. Status *ServicesStatus
  183. }
  184. type fsWrapper struct {
  185. vfs.Filesystem
  186. IsUserPage bool
  187. IsGroupPage bool
  188. HasUsersBaseDir bool
  189. DirPath string
  190. }
  191. type userPage struct {
  192. basePage
  193. User *dataprovider.User
  194. RootPerms []string
  195. Error string
  196. ValidPerms []string
  197. ValidLoginMethods []string
  198. ValidProtocols []string
  199. TwoFactorProtocols []string
  200. WebClientOptions []string
  201. RootDirPerms []string
  202. Mode userPageMode
  203. VirtualFolders []vfs.BaseVirtualFolder
  204. Groups []dataprovider.Group
  205. CanImpersonate bool
  206. FsWrapper fsWrapper
  207. }
  208. type adminPage struct {
  209. basePage
  210. Admin *dataprovider.Admin
  211. Error string
  212. IsAdd bool
  213. }
  214. type profilePage struct {
  215. basePage
  216. Error string
  217. AllowAPIKeyAuth bool
  218. Email string
  219. Description string
  220. }
  221. type changePasswordPage struct {
  222. basePage
  223. Error string
  224. }
  225. type mfaPage struct {
  226. basePage
  227. TOTPConfigs []string
  228. TOTPConfig dataprovider.AdminTOTPConfig
  229. GenerateTOTPURL string
  230. ValidateTOTPURL string
  231. SaveTOTPURL string
  232. RecCodesURL string
  233. }
  234. type maintenancePage struct {
  235. basePage
  236. BackupPath string
  237. RestorePath string
  238. Error string
  239. }
  240. type defenderHostsPage struct {
  241. basePage
  242. DefenderHostsURL string
  243. }
  244. type setupPage struct {
  245. basePage
  246. Username string
  247. HasInstallationCode bool
  248. InstallationCodeHint string
  249. HideSupportLink bool
  250. Error string
  251. }
  252. type folderPage struct {
  253. basePage
  254. Folder vfs.BaseVirtualFolder
  255. Error string
  256. Mode folderPageMode
  257. FsWrapper fsWrapper
  258. }
  259. type groupPage struct {
  260. basePage
  261. Group *dataprovider.Group
  262. Error string
  263. Mode genericPageMode
  264. ValidPerms []string
  265. ValidLoginMethods []string
  266. ValidProtocols []string
  267. TwoFactorProtocols []string
  268. WebClientOptions []string
  269. VirtualFolders []vfs.BaseVirtualFolder
  270. FsWrapper fsWrapper
  271. }
  272. type eventActionPage struct {
  273. basePage
  274. Action dataprovider.BaseEventAction
  275. ActionTypes []dataprovider.EnumMapping
  276. FsActions []dataprovider.EnumMapping
  277. HTTPMethods []string
  278. RedactedSecret string
  279. Error string
  280. Mode genericPageMode
  281. }
  282. type eventRulePage struct {
  283. basePage
  284. Rule dataprovider.EventRule
  285. TriggerTypes []dataprovider.EnumMapping
  286. Actions []dataprovider.BaseEventAction
  287. FsEvents []string
  288. Protocols []string
  289. ProviderEvents []string
  290. ProviderObjects []string
  291. Error string
  292. Mode genericPageMode
  293. IsShared bool
  294. }
  295. type messagePage struct {
  296. basePage
  297. Error string
  298. Success string
  299. }
  300. type userTemplateFields struct {
  301. Username string
  302. Password string
  303. PublicKeys []string
  304. }
  305. func loadAdminTemplates(templatesPath string) {
  306. usersPaths := []string{
  307. filepath.Join(templatesPath, templateCommonDir, templateCommonCSS),
  308. filepath.Join(templatesPath, templateAdminDir, templateBase),
  309. filepath.Join(templatesPath, templateAdminDir, templateUsers),
  310. }
  311. userPaths := []string{
  312. filepath.Join(templatesPath, templateCommonDir, templateCommonCSS),
  313. filepath.Join(templatesPath, templateAdminDir, templateBase),
  314. filepath.Join(templatesPath, templateAdminDir, templateSharedComponents),
  315. filepath.Join(templatesPath, templateAdminDir, templateFsConfig),
  316. filepath.Join(templatesPath, templateAdminDir, templateUser),
  317. }
  318. adminsPaths := []string{
  319. filepath.Join(templatesPath, templateCommonDir, templateCommonCSS),
  320. filepath.Join(templatesPath, templateAdminDir, templateBase),
  321. filepath.Join(templatesPath, templateAdminDir, templateAdmins),
  322. }
  323. adminPaths := []string{
  324. filepath.Join(templatesPath, templateCommonDir, templateCommonCSS),
  325. filepath.Join(templatesPath, templateAdminDir, templateBase),
  326. filepath.Join(templatesPath, templateAdminDir, templateAdmin),
  327. }
  328. profilePaths := []string{
  329. filepath.Join(templatesPath, templateCommonDir, templateCommonCSS),
  330. filepath.Join(templatesPath, templateAdminDir, templateBase),
  331. filepath.Join(templatesPath, templateAdminDir, templateProfile),
  332. }
  333. changePwdPaths := []string{
  334. filepath.Join(templatesPath, templateCommonDir, templateCommonCSS),
  335. filepath.Join(templatesPath, templateAdminDir, templateBase),
  336. filepath.Join(templatesPath, templateAdminDir, templateChangePwd),
  337. }
  338. connectionsPaths := []string{
  339. filepath.Join(templatesPath, templateCommonDir, templateCommonCSS),
  340. filepath.Join(templatesPath, templateAdminDir, templateBase),
  341. filepath.Join(templatesPath, templateAdminDir, templateConnections),
  342. }
  343. messagePaths := []string{
  344. filepath.Join(templatesPath, templateCommonDir, templateCommonCSS),
  345. filepath.Join(templatesPath, templateAdminDir, templateBase),
  346. filepath.Join(templatesPath, templateAdminDir, templateMessage),
  347. }
  348. foldersPaths := []string{
  349. filepath.Join(templatesPath, templateCommonDir, templateCommonCSS),
  350. filepath.Join(templatesPath, templateAdminDir, templateBase),
  351. filepath.Join(templatesPath, templateAdminDir, templateFolders),
  352. }
  353. folderPaths := []string{
  354. filepath.Join(templatesPath, templateCommonDir, templateCommonCSS),
  355. filepath.Join(templatesPath, templateAdminDir, templateBase),
  356. filepath.Join(templatesPath, templateAdminDir, templateFsConfig),
  357. filepath.Join(templatesPath, templateAdminDir, templateFolder),
  358. }
  359. groupsPaths := []string{
  360. filepath.Join(templatesPath, templateCommonDir, templateCommonCSS),
  361. filepath.Join(templatesPath, templateAdminDir, templateBase),
  362. filepath.Join(templatesPath, templateAdminDir, templateGroups),
  363. }
  364. groupPaths := []string{
  365. filepath.Join(templatesPath, templateCommonDir, templateCommonCSS),
  366. filepath.Join(templatesPath, templateAdminDir, templateBase),
  367. filepath.Join(templatesPath, templateAdminDir, templateFsConfig),
  368. filepath.Join(templatesPath, templateAdminDir, templateSharedComponents),
  369. filepath.Join(templatesPath, templateAdminDir, templateGroup),
  370. }
  371. eventRulesPaths := []string{
  372. filepath.Join(templatesPath, templateCommonDir, templateCommonCSS),
  373. filepath.Join(templatesPath, templateAdminDir, templateBase),
  374. filepath.Join(templatesPath, templateAdminDir, templateEventRules),
  375. }
  376. eventRulePaths := []string{
  377. filepath.Join(templatesPath, templateCommonDir, templateCommonCSS),
  378. filepath.Join(templatesPath, templateAdminDir, templateBase),
  379. filepath.Join(templatesPath, templateAdminDir, templateEventRule),
  380. }
  381. eventActionsPaths := []string{
  382. filepath.Join(templatesPath, templateCommonDir, templateCommonCSS),
  383. filepath.Join(templatesPath, templateAdminDir, templateBase),
  384. filepath.Join(templatesPath, templateAdminDir, templateEventActions),
  385. }
  386. eventActionPaths := []string{
  387. filepath.Join(templatesPath, templateCommonDir, templateCommonCSS),
  388. filepath.Join(templatesPath, templateAdminDir, templateBase),
  389. filepath.Join(templatesPath, templateAdminDir, templateEventAction),
  390. }
  391. statusPaths := []string{
  392. filepath.Join(templatesPath, templateCommonDir, templateCommonCSS),
  393. filepath.Join(templatesPath, templateAdminDir, templateBase),
  394. filepath.Join(templatesPath, templateAdminDir, templateStatus),
  395. }
  396. loginPaths := []string{
  397. filepath.Join(templatesPath, templateCommonDir, templateCommonCSS),
  398. filepath.Join(templatesPath, templateAdminDir, templateBaseLogin),
  399. filepath.Join(templatesPath, templateAdminDir, templateLogin),
  400. }
  401. maintenancePaths := []string{
  402. filepath.Join(templatesPath, templateCommonDir, templateCommonCSS),
  403. filepath.Join(templatesPath, templateAdminDir, templateBase),
  404. filepath.Join(templatesPath, templateAdminDir, templateMaintenance),
  405. }
  406. defenderPaths := []string{
  407. filepath.Join(templatesPath, templateCommonDir, templateCommonCSS),
  408. filepath.Join(templatesPath, templateAdminDir, templateBase),
  409. filepath.Join(templatesPath, templateAdminDir, templateDefender),
  410. }
  411. mfaPaths := []string{
  412. filepath.Join(templatesPath, templateCommonDir, templateCommonCSS),
  413. filepath.Join(templatesPath, templateAdminDir, templateBase),
  414. filepath.Join(templatesPath, templateAdminDir, templateMFA),
  415. }
  416. twoFactorPaths := []string{
  417. filepath.Join(templatesPath, templateCommonDir, templateCommonCSS),
  418. filepath.Join(templatesPath, templateAdminDir, templateBaseLogin),
  419. filepath.Join(templatesPath, templateAdminDir, templateTwoFactor),
  420. }
  421. twoFactorRecoveryPaths := []string{
  422. filepath.Join(templatesPath, templateCommonDir, templateCommonCSS),
  423. filepath.Join(templatesPath, templateAdminDir, templateBaseLogin),
  424. filepath.Join(templatesPath, templateAdminDir, templateTwoFactorRecovery),
  425. }
  426. setupPaths := []string{
  427. filepath.Join(templatesPath, templateCommonDir, templateCommonCSS),
  428. filepath.Join(templatesPath, templateAdminDir, templateBaseLogin),
  429. filepath.Join(templatesPath, templateAdminDir, templateSetup),
  430. }
  431. forgotPwdPaths := []string{
  432. filepath.Join(templatesPath, templateCommonDir, templateCommonCSS),
  433. filepath.Join(templatesPath, templateCommonDir, templateForgotPassword),
  434. }
  435. resetPwdPaths := []string{
  436. filepath.Join(templatesPath, templateCommonDir, templateCommonCSS),
  437. filepath.Join(templatesPath, templateCommonDir, templateResetPassword),
  438. }
  439. fsBaseTpl := template.New("fsBaseTemplate").Funcs(template.FuncMap{
  440. "ListFSProviders": func() []sdk.FilesystemProvider {
  441. return []sdk.FilesystemProvider{sdk.LocalFilesystemProvider, sdk.CryptedFilesystemProvider,
  442. sdk.S3FilesystemProvider, sdk.GCSFilesystemProvider, sdk.AzureBlobFilesystemProvider,
  443. sdk.SFTPFilesystemProvider, sdk.HTTPFilesystemProvider,
  444. }
  445. },
  446. })
  447. usersTmpl := util.LoadTemplate(nil, usersPaths...)
  448. userTmpl := util.LoadTemplate(fsBaseTpl, userPaths...)
  449. adminsTmpl := util.LoadTemplate(nil, adminsPaths...)
  450. adminTmpl := util.LoadTemplate(nil, adminPaths...)
  451. connectionsTmpl := util.LoadTemplate(nil, connectionsPaths...)
  452. messageTmpl := util.LoadTemplate(nil, messagePaths...)
  453. groupsTmpl := util.LoadTemplate(nil, groupsPaths...)
  454. groupTmpl := util.LoadTemplate(fsBaseTpl, groupPaths...)
  455. foldersTmpl := util.LoadTemplate(nil, foldersPaths...)
  456. folderTmpl := util.LoadTemplate(fsBaseTpl, folderPaths...)
  457. eventRulesTmpl := util.LoadTemplate(nil, eventRulesPaths...)
  458. eventRuleTmpl := util.LoadTemplate(nil, eventRulePaths...)
  459. eventActionsTmpl := util.LoadTemplate(nil, eventActionsPaths...)
  460. eventActionTmpl := util.LoadTemplate(nil, eventActionPaths...)
  461. statusTmpl := util.LoadTemplate(nil, statusPaths...)
  462. loginTmpl := util.LoadTemplate(nil, loginPaths...)
  463. profileTmpl := util.LoadTemplate(nil, profilePaths...)
  464. changePwdTmpl := util.LoadTemplate(nil, changePwdPaths...)
  465. maintenanceTmpl := util.LoadTemplate(nil, maintenancePaths...)
  466. defenderTmpl := util.LoadTemplate(nil, defenderPaths...)
  467. mfaTmpl := util.LoadTemplate(nil, mfaPaths...)
  468. twoFactorTmpl := util.LoadTemplate(nil, twoFactorPaths...)
  469. twoFactorRecoveryTmpl := util.LoadTemplate(nil, twoFactorRecoveryPaths...)
  470. setupTmpl := util.LoadTemplate(nil, setupPaths...)
  471. forgotPwdTmpl := util.LoadTemplate(nil, forgotPwdPaths...)
  472. resetPwdTmpl := util.LoadTemplate(nil, resetPwdPaths...)
  473. adminTemplates[templateUsers] = usersTmpl
  474. adminTemplates[templateUser] = userTmpl
  475. adminTemplates[templateAdmins] = adminsTmpl
  476. adminTemplates[templateAdmin] = adminTmpl
  477. adminTemplates[templateConnections] = connectionsTmpl
  478. adminTemplates[templateMessage] = messageTmpl
  479. adminTemplates[templateGroups] = groupsTmpl
  480. adminTemplates[templateGroup] = groupTmpl
  481. adminTemplates[templateFolders] = foldersTmpl
  482. adminTemplates[templateFolder] = folderTmpl
  483. adminTemplates[templateEventRules] = eventRulesTmpl
  484. adminTemplates[templateEventRule] = eventRuleTmpl
  485. adminTemplates[templateEventActions] = eventActionsTmpl
  486. adminTemplates[templateEventAction] = eventActionTmpl
  487. adminTemplates[templateStatus] = statusTmpl
  488. adminTemplates[templateLogin] = loginTmpl
  489. adminTemplates[templateProfile] = profileTmpl
  490. adminTemplates[templateChangePwd] = changePwdTmpl
  491. adminTemplates[templateMaintenance] = maintenanceTmpl
  492. adminTemplates[templateDefender] = defenderTmpl
  493. adminTemplates[templateMFA] = mfaTmpl
  494. adminTemplates[templateTwoFactor] = twoFactorTmpl
  495. adminTemplates[templateTwoFactorRecovery] = twoFactorRecoveryTmpl
  496. adminTemplates[templateSetup] = setupTmpl
  497. adminTemplates[templateForgotPassword] = forgotPwdTmpl
  498. adminTemplates[templateResetPassword] = resetPwdTmpl
  499. }
  500. func isEventManagerResource(currentURL string) bool {
  501. if currentURL == webAdminEventRulesPath {
  502. return true
  503. }
  504. if currentURL == webAdminEventActionsPath {
  505. return true
  506. }
  507. if currentURL == webAdminEventRulePath || strings.HasPrefix(currentURL, webAdminEventRulePath+"/") {
  508. return true
  509. }
  510. if currentURL == webAdminEventActionPath || strings.HasPrefix(currentURL, webAdminEventActionPath+"/") {
  511. return true
  512. }
  513. return false
  514. }
  515. func (s *httpdServer) getBasePageData(title, currentURL string, r *http.Request) basePage {
  516. var csrfToken string
  517. if currentURL != "" {
  518. csrfToken = createCSRFToken(util.GetIPFromRemoteAddress(r.RemoteAddr))
  519. }
  520. return basePage{
  521. Title: title,
  522. CurrentURL: currentURL,
  523. UsersURL: webUsersPath,
  524. UserURL: webUserPath,
  525. UserTemplateURL: webTemplateUser,
  526. AdminsURL: webAdminsPath,
  527. AdminURL: webAdminPath,
  528. GroupsURL: webGroupsPath,
  529. GroupURL: webGroupPath,
  530. FoldersURL: webFoldersPath,
  531. FolderURL: webFolderPath,
  532. FolderTemplateURL: webTemplateFolder,
  533. DefenderURL: webDefenderPath,
  534. LogoutURL: webLogoutPath,
  535. ProfileURL: webAdminProfilePath,
  536. ChangePwdURL: webChangeAdminPwdPath,
  537. MFAURL: webAdminMFAPath,
  538. EventRulesURL: webAdminEventRulesPath,
  539. EventRuleURL: webAdminEventRulePath,
  540. EventActionsURL: webAdminEventActionsPath,
  541. EventActionURL: webAdminEventActionPath,
  542. QuotaScanURL: webQuotaScanPath,
  543. ConnectionsURL: webConnectionsPath,
  544. StatusURL: webStatusPath,
  545. FolderQuotaScanURL: webScanVFolderPath,
  546. MaintenanceURL: webMaintenancePath,
  547. StaticURL: webStaticFilesPath,
  548. UsersTitle: pageUsersTitle,
  549. AdminsTitle: pageAdminsTitle,
  550. ConnectionsTitle: pageConnectionsTitle,
  551. FoldersTitle: pageFoldersTitle,
  552. GroupsTitle: pageGroupsTitle,
  553. EventRulesTitle: pageEventRulesTitle,
  554. EventActionsTitle: pageEventActionsTitle,
  555. StatusTitle: pageStatusTitle,
  556. MaintenanceTitle: pageMaintenanceTitle,
  557. DefenderTitle: pageDefenderTitle,
  558. Version: version.GetAsString(),
  559. LoggedAdmin: getAdminFromToken(r),
  560. IsEventManagerPage: isEventManagerResource(currentURL),
  561. HasDefender: common.Config.DefenderConfig.Enabled,
  562. HasExternalLogin: isLoggedInWithOIDC(r),
  563. CSRFToken: csrfToken,
  564. Branding: s.binding.Branding.WebAdmin,
  565. }
  566. }
  567. func renderAdminTemplate(w http.ResponseWriter, tmplName string, data any) {
  568. err := adminTemplates[tmplName].ExecuteTemplate(w, tmplName, data)
  569. if err != nil {
  570. http.Error(w, err.Error(), http.StatusInternalServerError)
  571. }
  572. }
  573. func (s *httpdServer) renderMessagePage(w http.ResponseWriter, r *http.Request, title, body string, statusCode int,
  574. err error, message string,
  575. ) {
  576. var errorString string
  577. if body != "" {
  578. errorString = body + " "
  579. }
  580. if err != nil {
  581. errorString += err.Error()
  582. }
  583. data := messagePage{
  584. basePage: s.getBasePageData(title, "", r),
  585. Error: errorString,
  586. Success: message,
  587. }
  588. w.WriteHeader(statusCode)
  589. renderAdminTemplate(w, templateMessage, data)
  590. }
  591. func (s *httpdServer) renderInternalServerErrorPage(w http.ResponseWriter, r *http.Request, err error) {
  592. s.renderMessagePage(w, r, page500Title, page500Body, http.StatusInternalServerError, err, "")
  593. }
  594. func (s *httpdServer) renderBadRequestPage(w http.ResponseWriter, r *http.Request, err error) {
  595. s.renderMessagePage(w, r, page400Title, "", http.StatusBadRequest, err, "")
  596. }
  597. func (s *httpdServer) renderForbiddenPage(w http.ResponseWriter, r *http.Request, body string) {
  598. s.renderMessagePage(w, r, page403Title, "", http.StatusForbidden, nil, body)
  599. }
  600. func (s *httpdServer) renderNotFoundPage(w http.ResponseWriter, r *http.Request, err error) {
  601. s.renderMessagePage(w, r, page404Title, page404Body, http.StatusNotFound, err, "")
  602. }
  603. func (s *httpdServer) renderForgotPwdPage(w http.ResponseWriter, error, ip string) {
  604. data := forgotPwdPage{
  605. CurrentURL: webAdminForgotPwdPath,
  606. Error: error,
  607. CSRFToken: createCSRFToken(ip),
  608. StaticURL: webStaticFilesPath,
  609. Title: pageForgotPwdTitle,
  610. Branding: s.binding.Branding.WebAdmin,
  611. }
  612. renderAdminTemplate(w, templateForgotPassword, data)
  613. }
  614. func (s *httpdServer) renderResetPwdPage(w http.ResponseWriter, error, ip string) {
  615. data := resetPwdPage{
  616. CurrentURL: webAdminResetPwdPath,
  617. Error: error,
  618. CSRFToken: createCSRFToken(ip),
  619. StaticURL: webStaticFilesPath,
  620. Title: pageResetPwdTitle,
  621. Branding: s.binding.Branding.WebAdmin,
  622. }
  623. renderAdminTemplate(w, templateResetPassword, data)
  624. }
  625. func (s *httpdServer) renderTwoFactorPage(w http.ResponseWriter, error, ip string) {
  626. data := twoFactorPage{
  627. CurrentURL: webAdminTwoFactorPath,
  628. Version: version.Get().Version,
  629. Error: error,
  630. CSRFToken: createCSRFToken(ip),
  631. StaticURL: webStaticFilesPath,
  632. RecoveryURL: webAdminTwoFactorRecoveryPath,
  633. Branding: s.binding.Branding.WebAdmin,
  634. }
  635. renderAdminTemplate(w, templateTwoFactor, data)
  636. }
  637. func (s *httpdServer) renderTwoFactorRecoveryPage(w http.ResponseWriter, error, ip string) {
  638. data := twoFactorPage{
  639. CurrentURL: webAdminTwoFactorRecoveryPath,
  640. Version: version.Get().Version,
  641. Error: error,
  642. CSRFToken: createCSRFToken(ip),
  643. StaticURL: webStaticFilesPath,
  644. Branding: s.binding.Branding.WebAdmin,
  645. }
  646. renderAdminTemplate(w, templateTwoFactorRecovery, data)
  647. }
  648. func (s *httpdServer) renderMFAPage(w http.ResponseWriter, r *http.Request) {
  649. data := mfaPage{
  650. basePage: s.getBasePageData(pageMFATitle, webAdminMFAPath, r),
  651. TOTPConfigs: mfa.GetAvailableTOTPConfigNames(),
  652. GenerateTOTPURL: webAdminTOTPGeneratePath,
  653. ValidateTOTPURL: webAdminTOTPValidatePath,
  654. SaveTOTPURL: webAdminTOTPSavePath,
  655. RecCodesURL: webAdminRecoveryCodesPath,
  656. }
  657. admin, err := dataprovider.AdminExists(data.LoggedAdmin.Username)
  658. if err != nil {
  659. s.renderInternalServerErrorPage(w, r, err)
  660. return
  661. }
  662. data.TOTPConfig = admin.Filters.TOTPConfig
  663. renderAdminTemplate(w, templateMFA, data)
  664. }
  665. func (s *httpdServer) renderProfilePage(w http.ResponseWriter, r *http.Request, error string) {
  666. data := profilePage{
  667. basePage: s.getBasePageData(pageProfileTitle, webAdminProfilePath, r),
  668. Error: error,
  669. }
  670. admin, err := dataprovider.AdminExists(data.LoggedAdmin.Username)
  671. if err != nil {
  672. s.renderInternalServerErrorPage(w, r, err)
  673. return
  674. }
  675. data.AllowAPIKeyAuth = admin.Filters.AllowAPIKeyAuth
  676. data.Email = admin.Email
  677. data.Description = admin.Description
  678. renderAdminTemplate(w, templateProfile, data)
  679. }
  680. func (s *httpdServer) renderChangePasswordPage(w http.ResponseWriter, r *http.Request, error string) {
  681. data := changePasswordPage{
  682. basePage: s.getBasePageData(pageChangePwdTitle, webChangeAdminPwdPath, r),
  683. Error: error,
  684. }
  685. renderAdminTemplate(w, templateChangePwd, data)
  686. }
  687. func (s *httpdServer) renderMaintenancePage(w http.ResponseWriter, r *http.Request, error string) {
  688. data := maintenancePage{
  689. basePage: s.getBasePageData(pageMaintenanceTitle, webMaintenancePath, r),
  690. BackupPath: webBackupPath,
  691. RestorePath: webRestorePath,
  692. Error: error,
  693. }
  694. renderAdminTemplate(w, templateMaintenance, data)
  695. }
  696. func (s *httpdServer) renderAdminSetupPage(w http.ResponseWriter, r *http.Request, username, error string) {
  697. data := setupPage{
  698. basePage: s.getBasePageData(pageSetupTitle, webAdminSetupPath, r),
  699. Username: username,
  700. HasInstallationCode: installationCode != "",
  701. InstallationCodeHint: installationCodeHint,
  702. HideSupportLink: hideSupportLink,
  703. Error: error,
  704. }
  705. renderAdminTemplate(w, templateSetup, data)
  706. }
  707. func (s *httpdServer) renderAddUpdateAdminPage(w http.ResponseWriter, r *http.Request, admin *dataprovider.Admin,
  708. error string, isAdd bool) {
  709. currentURL := webAdminPath
  710. title := "Add a new admin"
  711. if !isAdd {
  712. currentURL = fmt.Sprintf("%v/%v", webAdminPath, url.PathEscape(admin.Username))
  713. title = "Update admin"
  714. }
  715. data := adminPage{
  716. basePage: s.getBasePageData(title, currentURL, r),
  717. Admin: admin,
  718. Error: error,
  719. IsAdd: isAdd,
  720. }
  721. renderAdminTemplate(w, templateAdmin, data)
  722. }
  723. func (s *httpdServer) renderUserPage(w http.ResponseWriter, r *http.Request, user *dataprovider.User,
  724. mode userPageMode, error string,
  725. ) {
  726. folders, err := s.getWebVirtualFolders(w, r, defaultQueryLimit, true)
  727. if err != nil {
  728. return
  729. }
  730. groups, err := s.getWebGroups(w, r, defaultQueryLimit, true)
  731. if err != nil {
  732. return
  733. }
  734. user.SetEmptySecretsIfNil()
  735. var title, currentURL string
  736. switch mode {
  737. case userPageModeAdd:
  738. title = "Add a new user"
  739. currentURL = webUserPath
  740. case userPageModeUpdate:
  741. title = "Update user"
  742. currentURL = fmt.Sprintf("%v/%v", webUserPath, url.PathEscape(user.Username))
  743. case userPageModeTemplate:
  744. title = "User template"
  745. currentURL = webTemplateUser
  746. }
  747. if user.Password != "" && user.IsPasswordHashed() {
  748. switch mode {
  749. case userPageModeUpdate:
  750. user.Password = redactedSecret
  751. default:
  752. user.Password = ""
  753. }
  754. }
  755. user.FsConfig.RedactedSecret = redactedSecret
  756. data := userPage{
  757. basePage: s.getBasePageData(title, currentURL, r),
  758. Mode: mode,
  759. Error: error,
  760. User: user,
  761. ValidPerms: dataprovider.ValidPerms,
  762. ValidLoginMethods: dataprovider.ValidLoginMethods,
  763. ValidProtocols: dataprovider.ValidProtocols,
  764. TwoFactorProtocols: dataprovider.MFAProtocols,
  765. WebClientOptions: sdk.WebClientOptions,
  766. RootDirPerms: user.GetPermissionsForPath("/"),
  767. VirtualFolders: folders,
  768. Groups: groups,
  769. CanImpersonate: os.Getuid() == 0,
  770. FsWrapper: fsWrapper{
  771. Filesystem: user.FsConfig,
  772. IsUserPage: true,
  773. IsGroupPage: false,
  774. HasUsersBaseDir: dataprovider.HasUsersBaseDir(),
  775. DirPath: user.HomeDir,
  776. },
  777. }
  778. renderAdminTemplate(w, templateUser, data)
  779. }
  780. func (s *httpdServer) renderGroupPage(w http.ResponseWriter, r *http.Request, group dataprovider.Group,
  781. mode genericPageMode, error string,
  782. ) {
  783. folders, err := s.getWebVirtualFolders(w, r, defaultQueryLimit, true)
  784. if err != nil {
  785. return
  786. }
  787. group.SetEmptySecretsIfNil()
  788. group.UserSettings.FsConfig.RedactedSecret = redactedSecret
  789. var title, currentURL string
  790. switch mode {
  791. case genericPageModeAdd:
  792. title = "Add a new group"
  793. currentURL = webGroupPath
  794. case genericPageModeUpdate:
  795. title = "Update group"
  796. currentURL = fmt.Sprintf("%v/%v", webGroupPath, url.PathEscape(group.Name))
  797. }
  798. group.UserSettings.FsConfig.RedactedSecret = redactedSecret
  799. group.UserSettings.FsConfig.SetEmptySecretsIfNil()
  800. data := groupPage{
  801. basePage: s.getBasePageData(title, currentURL, r),
  802. Error: error,
  803. Group: &group,
  804. Mode: mode,
  805. ValidPerms: dataprovider.ValidPerms,
  806. ValidLoginMethods: dataprovider.ValidLoginMethods,
  807. ValidProtocols: dataprovider.ValidProtocols,
  808. TwoFactorProtocols: dataprovider.MFAProtocols,
  809. WebClientOptions: sdk.WebClientOptions,
  810. VirtualFolders: folders,
  811. FsWrapper: fsWrapper{
  812. Filesystem: group.UserSettings.FsConfig,
  813. IsUserPage: false,
  814. IsGroupPage: true,
  815. HasUsersBaseDir: false,
  816. DirPath: group.UserSettings.HomeDir,
  817. },
  818. }
  819. renderAdminTemplate(w, templateGroup, data)
  820. }
  821. func (s *httpdServer) renderEventActionPage(w http.ResponseWriter, r *http.Request, action dataprovider.BaseEventAction,
  822. mode genericPageMode, error string,
  823. ) {
  824. action.Options.SetEmptySecretsIfNil()
  825. var title, currentURL string
  826. switch mode {
  827. case genericPageModeAdd:
  828. title = "Add a new event action"
  829. currentURL = webAdminEventActionPath
  830. case genericPageModeUpdate:
  831. title = "Update event action"
  832. currentURL = fmt.Sprintf("%v/%v", webAdminEventActionPath, url.PathEscape(action.Name))
  833. }
  834. if action.Options.HTTPConfig.Timeout == 0 {
  835. action.Options.HTTPConfig.Timeout = 20
  836. }
  837. if action.Options.CmdConfig.Timeout == 0 {
  838. action.Options.CmdConfig.Timeout = 20
  839. }
  840. data := eventActionPage{
  841. basePage: s.getBasePageData(title, currentURL, r),
  842. Action: action,
  843. ActionTypes: dataprovider.EventActionTypes,
  844. FsActions: dataprovider.FsActionTypes,
  845. HTTPMethods: dataprovider.SupportedHTTPActionMethods,
  846. RedactedSecret: redactedSecret,
  847. Error: error,
  848. Mode: mode,
  849. }
  850. renderAdminTemplate(w, templateEventAction, data)
  851. }
  852. func (s *httpdServer) renderEventRulePage(w http.ResponseWriter, r *http.Request, rule dataprovider.EventRule,
  853. mode genericPageMode, error string,
  854. ) {
  855. actions, err := s.getWebEventActions(w, r, defaultQueryLimit, true)
  856. if err != nil {
  857. return
  858. }
  859. var title, currentURL string
  860. switch mode {
  861. case genericPageModeAdd:
  862. title = "Add new event rules"
  863. currentURL = webAdminEventRulePath
  864. case genericPageModeUpdate:
  865. title = "Update event rules"
  866. currentURL = fmt.Sprintf("%v/%v", webAdminEventRulePath, url.PathEscape(rule.Name))
  867. }
  868. data := eventRulePage{
  869. basePage: s.getBasePageData(title, currentURL, r),
  870. Rule: rule,
  871. TriggerTypes: dataprovider.EventTriggerTypes,
  872. Actions: actions,
  873. FsEvents: dataprovider.SupportedFsEvents,
  874. Protocols: dataprovider.SupportedRuleConditionProtocols,
  875. ProviderEvents: dataprovider.SupportedProviderEvents,
  876. ProviderObjects: dataprovider.SupporteRuleConditionProviderObjects,
  877. Error: error,
  878. Mode: mode,
  879. IsShared: s.isShared > 0,
  880. }
  881. renderAdminTemplate(w, templateEventRule, data)
  882. }
  883. func (s *httpdServer) renderFolderPage(w http.ResponseWriter, r *http.Request, folder vfs.BaseVirtualFolder,
  884. mode folderPageMode, error string,
  885. ) {
  886. var title, currentURL string
  887. switch mode {
  888. case folderPageModeAdd:
  889. title = "Add a new folder"
  890. currentURL = webFolderPath
  891. case folderPageModeUpdate:
  892. title = "Update folder"
  893. currentURL = fmt.Sprintf("%v/%v", webFolderPath, url.PathEscape(folder.Name))
  894. case folderPageModeTemplate:
  895. title = "Folder template"
  896. currentURL = webTemplateFolder
  897. }
  898. folder.FsConfig.RedactedSecret = redactedSecret
  899. folder.FsConfig.SetEmptySecretsIfNil()
  900. data := folderPage{
  901. basePage: s.getBasePageData(title, currentURL, r),
  902. Error: error,
  903. Folder: folder,
  904. Mode: mode,
  905. FsWrapper: fsWrapper{
  906. Filesystem: folder.FsConfig,
  907. IsUserPage: false,
  908. IsGroupPage: false,
  909. HasUsersBaseDir: false,
  910. DirPath: folder.MappedPath,
  911. },
  912. }
  913. renderAdminTemplate(w, templateFolder, data)
  914. }
  915. func getFoldersForTemplate(r *http.Request) []string {
  916. var res []string
  917. folderNames := r.Form["tpl_foldername"]
  918. folders := make(map[string]bool)
  919. for _, name := range folderNames {
  920. name = strings.TrimSpace(name)
  921. if name == "" {
  922. continue
  923. }
  924. if _, ok := folders[name]; ok {
  925. continue
  926. }
  927. folders[name] = true
  928. res = append(res, name)
  929. }
  930. return res
  931. }
  932. func getUsersForTemplate(r *http.Request) []userTemplateFields {
  933. var res []userTemplateFields
  934. tplUsernames := r.Form["tpl_username"]
  935. tplPasswords := r.Form["tpl_password"]
  936. tplPublicKeys := r.Form["tpl_public_keys"]
  937. users := make(map[string]bool)
  938. for idx, username := range tplUsernames {
  939. username = strings.TrimSpace(username)
  940. password := ""
  941. publicKey := ""
  942. if len(tplPasswords) > idx {
  943. password = strings.TrimSpace(tplPasswords[idx])
  944. }
  945. if len(tplPublicKeys) > idx {
  946. publicKey = strings.TrimSpace(tplPublicKeys[idx])
  947. }
  948. if username == "" {
  949. continue
  950. }
  951. if _, ok := users[username]; ok {
  952. continue
  953. }
  954. users[username] = true
  955. res = append(res, userTemplateFields{
  956. Username: username,
  957. Password: password,
  958. PublicKeys: []string{publicKey},
  959. })
  960. }
  961. return res
  962. }
  963. func getVirtualFoldersFromPostFields(r *http.Request) []vfs.VirtualFolder {
  964. var virtualFolders []vfs.VirtualFolder
  965. folderPaths := r.Form["vfolder_path"]
  966. folderNames := r.Form["vfolder_name"]
  967. folderQuotaSizes := r.Form["vfolder_quota_size"]
  968. folderQuotaFiles := r.Form["vfolder_quota_files"]
  969. for idx, p := range folderPaths {
  970. p = strings.TrimSpace(p)
  971. name := ""
  972. if len(folderNames) > idx {
  973. name = folderNames[idx]
  974. }
  975. if p != "" && name != "" {
  976. vfolder := vfs.VirtualFolder{
  977. BaseVirtualFolder: vfs.BaseVirtualFolder{
  978. Name: name,
  979. },
  980. VirtualPath: p,
  981. QuotaFiles: -1,
  982. QuotaSize: -1,
  983. }
  984. if len(folderQuotaSizes) > idx {
  985. quotaSize, err := strconv.ParseInt(strings.TrimSpace(folderQuotaSizes[idx]), 10, 64)
  986. if err == nil {
  987. vfolder.QuotaSize = quotaSize
  988. }
  989. }
  990. if len(folderQuotaFiles) > idx {
  991. quotaFiles, err := strconv.Atoi(strings.TrimSpace(folderQuotaFiles[idx]))
  992. if err == nil {
  993. vfolder.QuotaFiles = quotaFiles
  994. }
  995. }
  996. virtualFolders = append(virtualFolders, vfolder)
  997. }
  998. }
  999. return virtualFolders
  1000. }
  1001. func getSubDirPermissionsFromPostFields(r *http.Request) map[string][]string {
  1002. permissions := make(map[string][]string)
  1003. for k := range r.Form {
  1004. if strings.HasPrefix(k, "sub_perm_path") {
  1005. p := strings.TrimSpace(r.Form.Get(k))
  1006. if p != "" {
  1007. idx := strings.TrimPrefix(k, "sub_perm_path")
  1008. permissions[p] = r.Form[fmt.Sprintf("sub_perm_permissions%v", idx)]
  1009. }
  1010. }
  1011. }
  1012. return permissions
  1013. }
  1014. func getUserPermissionsFromPostFields(r *http.Request) map[string][]string {
  1015. permissions := getSubDirPermissionsFromPostFields(r)
  1016. permissions["/"] = r.Form["permissions"]
  1017. return permissions
  1018. }
  1019. func getDataTransferLimitsFromPostFields(r *http.Request) ([]sdk.DataTransferLimit, error) {
  1020. var result []sdk.DataTransferLimit
  1021. for k := range r.Form {
  1022. if strings.HasPrefix(k, "data_transfer_limit_sources") {
  1023. sources := getSliceFromDelimitedValues(r.Form.Get(k), ",")
  1024. if len(sources) > 0 {
  1025. dtLimit := sdk.DataTransferLimit{
  1026. Sources: sources,
  1027. }
  1028. idx := strings.TrimPrefix(k, "data_transfer_limit_sources")
  1029. ul := r.Form.Get(fmt.Sprintf("upload_data_transfer_source%v", idx))
  1030. dl := r.Form.Get(fmt.Sprintf("download_data_transfer_source%v", idx))
  1031. total := r.Form.Get(fmt.Sprintf("total_data_transfer_source%v", idx))
  1032. if ul != "" {
  1033. dataUL, err := strconv.ParseInt(ul, 10, 64)
  1034. if err != nil {
  1035. return result, fmt.Errorf("invalid upload_data_transfer_source%v %#v: %w", idx, ul, err)
  1036. }
  1037. dtLimit.UploadDataTransfer = dataUL
  1038. }
  1039. if dl != "" {
  1040. dataDL, err := strconv.ParseInt(dl, 10, 64)
  1041. if err != nil {
  1042. return result, fmt.Errorf("invalid download_data_transfer_source%v %#v: %w", idx, dl, err)
  1043. }
  1044. dtLimit.DownloadDataTransfer = dataDL
  1045. }
  1046. if total != "" {
  1047. dataTotal, err := strconv.ParseInt(total, 10, 64)
  1048. if err != nil {
  1049. return result, fmt.Errorf("invalid total_data_transfer_source%v %#v: %w", idx, total, err)
  1050. }
  1051. dtLimit.TotalDataTransfer = dataTotal
  1052. }
  1053. result = append(result, dtLimit)
  1054. }
  1055. }
  1056. }
  1057. return result, nil
  1058. }
  1059. func getBandwidthLimitsFromPostFields(r *http.Request) ([]sdk.BandwidthLimit, error) {
  1060. var result []sdk.BandwidthLimit
  1061. for k := range r.Form {
  1062. if strings.HasPrefix(k, "bandwidth_limit_sources") {
  1063. sources := getSliceFromDelimitedValues(r.Form.Get(k), ",")
  1064. if len(sources) > 0 {
  1065. bwLimit := sdk.BandwidthLimit{
  1066. Sources: sources,
  1067. }
  1068. idx := strings.TrimPrefix(k, "bandwidth_limit_sources")
  1069. ul := r.Form.Get(fmt.Sprintf("upload_bandwidth_source%v", idx))
  1070. dl := r.Form.Get(fmt.Sprintf("download_bandwidth_source%v", idx))
  1071. if ul != "" {
  1072. bandwidthUL, err := strconv.ParseInt(ul, 10, 64)
  1073. if err != nil {
  1074. return result, fmt.Errorf("invalid upload_bandwidth_source%v %#v: %w", idx, ul, err)
  1075. }
  1076. bwLimit.UploadBandwidth = bandwidthUL
  1077. }
  1078. if dl != "" {
  1079. bandwidthDL, err := strconv.ParseInt(dl, 10, 64)
  1080. if err != nil {
  1081. return result, fmt.Errorf("invalid download_bandwidth_source%v %#v: %w", idx, ul, err)
  1082. }
  1083. bwLimit.DownloadBandwidth = bandwidthDL
  1084. }
  1085. result = append(result, bwLimit)
  1086. }
  1087. }
  1088. }
  1089. return result, nil
  1090. }
  1091. func getPatterDenyPolicyFromString(policy string) int {
  1092. denyPolicy := sdk.DenyPolicyDefault
  1093. if policy == "1" {
  1094. denyPolicy = sdk.DenyPolicyHide
  1095. }
  1096. return denyPolicy
  1097. }
  1098. func getFilePatternsFromPostField(r *http.Request) []sdk.PatternsFilter {
  1099. var result []sdk.PatternsFilter
  1100. allowedPatterns := make(map[string][]string)
  1101. deniedPatterns := make(map[string][]string)
  1102. patternPolicies := make(map[string]string)
  1103. for k := range r.Form {
  1104. if strings.HasPrefix(k, "pattern_path") {
  1105. p := strings.TrimSpace(r.Form.Get(k))
  1106. idx := strings.TrimPrefix(k, "pattern_path")
  1107. filters := strings.TrimSpace(r.Form.Get(fmt.Sprintf("patterns%v", idx)))
  1108. filters = strings.ReplaceAll(filters, " ", "")
  1109. patternType := r.Form.Get(fmt.Sprintf("pattern_type%v", idx))
  1110. patternPolicy := r.Form.Get(fmt.Sprintf("pattern_policy%v", idx))
  1111. if p != "" && filters != "" {
  1112. if patternType == "allowed" {
  1113. allowedPatterns[p] = append(allowedPatterns[p], strings.Split(filters, ",")...)
  1114. } else {
  1115. deniedPatterns[p] = append(deniedPatterns[p], strings.Split(filters, ",")...)
  1116. }
  1117. if patternPolicy != "" && patternPolicy != "0" {
  1118. patternPolicies[p] = patternPolicy
  1119. }
  1120. }
  1121. }
  1122. }
  1123. for dirAllowed, allowPatterns := range allowedPatterns {
  1124. filter := sdk.PatternsFilter{
  1125. Path: dirAllowed,
  1126. AllowedPatterns: allowPatterns,
  1127. DenyPolicy: getPatterDenyPolicyFromString(patternPolicies[dirAllowed]),
  1128. }
  1129. for dirDenied, denPatterns := range deniedPatterns {
  1130. if dirAllowed == dirDenied {
  1131. filter.DeniedPatterns = denPatterns
  1132. break
  1133. }
  1134. }
  1135. result = append(result, filter)
  1136. }
  1137. for dirDenied, denPatterns := range deniedPatterns {
  1138. found := false
  1139. for _, res := range result {
  1140. if res.Path == dirDenied {
  1141. found = true
  1142. break
  1143. }
  1144. }
  1145. if !found {
  1146. result = append(result, sdk.PatternsFilter{
  1147. Path: dirDenied,
  1148. DeniedPatterns: denPatterns,
  1149. DenyPolicy: getPatterDenyPolicyFromString(patternPolicies[dirDenied]),
  1150. })
  1151. }
  1152. }
  1153. return result
  1154. }
  1155. func getGroupsFromUserPostFields(r *http.Request) []sdk.GroupMapping {
  1156. var groups []sdk.GroupMapping
  1157. primaryGroup := r.Form.Get("primary_group")
  1158. if primaryGroup != "" {
  1159. groups = append(groups, sdk.GroupMapping{
  1160. Name: primaryGroup,
  1161. Type: sdk.GroupTypePrimary,
  1162. })
  1163. }
  1164. secondaryGroups := r.Form["secondary_groups"]
  1165. for _, name := range secondaryGroups {
  1166. groups = append(groups, sdk.GroupMapping{
  1167. Name: name,
  1168. Type: sdk.GroupTypeSecondary,
  1169. })
  1170. }
  1171. return groups
  1172. }
  1173. func getFiltersFromUserPostFields(r *http.Request) (sdk.BaseUserFilters, error) {
  1174. var filters sdk.BaseUserFilters
  1175. bwLimits, err := getBandwidthLimitsFromPostFields(r)
  1176. if err != nil {
  1177. return filters, err
  1178. }
  1179. dtLimits, err := getDataTransferLimitsFromPostFields(r)
  1180. if err != nil {
  1181. return filters, err
  1182. }
  1183. maxFileSize, err := strconv.ParseInt(r.Form.Get("max_upload_file_size"), 10, 64)
  1184. if err != nil {
  1185. return filters, fmt.Errorf("invalid max upload file size: %w", err)
  1186. }
  1187. defaultSharesExpiration, err := strconv.ParseInt(r.Form.Get("default_shares_expiration"), 10, 64)
  1188. if err != nil {
  1189. return filters, fmt.Errorf("invalid default shares expiration: %w", err)
  1190. }
  1191. if r.Form.Get("ftp_security") == "1" {
  1192. filters.FTPSecurity = 1
  1193. }
  1194. filters.BandwidthLimits = bwLimits
  1195. filters.DataTransferLimits = dtLimits
  1196. filters.AllowedIP = getSliceFromDelimitedValues(r.Form.Get("allowed_ip"), ",")
  1197. filters.DeniedIP = getSliceFromDelimitedValues(r.Form.Get("denied_ip"), ",")
  1198. filters.DeniedLoginMethods = r.Form["denied_login_methods"]
  1199. filters.DeniedProtocols = r.Form["denied_protocols"]
  1200. filters.TwoFactorAuthProtocols = r.Form["required_two_factor_protocols"]
  1201. filters.FilePatterns = getFilePatternsFromPostField(r)
  1202. filters.TLSUsername = sdk.TLSUsername(r.Form.Get("tls_username"))
  1203. filters.WebClient = r.Form["web_client_options"]
  1204. filters.DefaultSharesExpiration = int(defaultSharesExpiration)
  1205. hooks := r.Form["hooks"]
  1206. if util.Contains(hooks, "external_auth_disabled") {
  1207. filters.Hooks.ExternalAuthDisabled = true
  1208. }
  1209. if util.Contains(hooks, "pre_login_disabled") {
  1210. filters.Hooks.PreLoginDisabled = true
  1211. }
  1212. if util.Contains(hooks, "check_password_disabled") {
  1213. filters.Hooks.CheckPasswordDisabled = true
  1214. }
  1215. filters.IsAnonymous = r.Form.Get("is_anonymous") != ""
  1216. filters.DisableFsChecks = r.Form.Get("disable_fs_checks") != ""
  1217. filters.AllowAPIKeyAuth = r.Form.Get("allow_api_key_auth") != ""
  1218. filters.StartDirectory = r.Form.Get("start_directory")
  1219. filters.MaxUploadFileSize = maxFileSize
  1220. filters.ExternalAuthCacheTime, err = strconv.ParseInt(r.Form.Get("external_auth_cache_time"), 10, 64)
  1221. if err != nil {
  1222. return filters, fmt.Errorf("invalid external auth cache time: %w", err)
  1223. }
  1224. return filters, nil
  1225. }
  1226. func getSecretFromFormField(r *http.Request, field string) *kms.Secret {
  1227. secret := kms.NewPlainSecret(r.Form.Get(field))
  1228. if strings.TrimSpace(secret.GetPayload()) == redactedSecret {
  1229. secret.SetStatus(sdkkms.SecretStatusRedacted)
  1230. }
  1231. if strings.TrimSpace(secret.GetPayload()) == "" {
  1232. secret.SetStatus("")
  1233. }
  1234. return secret
  1235. }
  1236. func getS3Config(r *http.Request) (vfs.S3FsConfig, error) {
  1237. var err error
  1238. config := vfs.S3FsConfig{}
  1239. config.Bucket = r.Form.Get("s3_bucket")
  1240. config.Region = r.Form.Get("s3_region")
  1241. config.AccessKey = r.Form.Get("s3_access_key")
  1242. config.RoleARN = r.Form.Get("s3_role_arn")
  1243. config.AccessSecret = getSecretFromFormField(r, "s3_access_secret")
  1244. config.Endpoint = r.Form.Get("s3_endpoint")
  1245. config.StorageClass = r.Form.Get("s3_storage_class")
  1246. config.ACL = r.Form.Get("s3_acl")
  1247. config.KeyPrefix = r.Form.Get("s3_key_prefix")
  1248. config.UploadPartSize, err = strconv.ParseInt(r.Form.Get("s3_upload_part_size"), 10, 64)
  1249. if err != nil {
  1250. return config, fmt.Errorf("invalid s3 upload part size: %w", err)
  1251. }
  1252. config.UploadConcurrency, err = strconv.Atoi(r.Form.Get("s3_upload_concurrency"))
  1253. if err != nil {
  1254. return config, fmt.Errorf("invalid s3 upload concurrency: %w", err)
  1255. }
  1256. config.DownloadPartSize, err = strconv.ParseInt(r.Form.Get("s3_download_part_size"), 10, 64)
  1257. if err != nil {
  1258. return config, fmt.Errorf("invalid s3 download part size: %w", err)
  1259. }
  1260. config.DownloadConcurrency, err = strconv.Atoi(r.Form.Get("s3_download_concurrency"))
  1261. if err != nil {
  1262. return config, fmt.Errorf("invalid s3 download concurrency: %w", err)
  1263. }
  1264. config.ForcePathStyle = r.Form.Get("s3_force_path_style") != ""
  1265. config.DownloadPartMaxTime, err = strconv.Atoi(r.Form.Get("s3_download_part_max_time"))
  1266. if err != nil {
  1267. return config, fmt.Errorf("invalid s3 download part max time: %w", err)
  1268. }
  1269. config.UploadPartMaxTime, err = strconv.Atoi(r.Form.Get("s3_upload_part_max_time"))
  1270. if err != nil {
  1271. return config, fmt.Errorf("invalid s3 upload part max time: %w", err)
  1272. }
  1273. return config, nil
  1274. }
  1275. func getGCSConfig(r *http.Request) (vfs.GCSFsConfig, error) {
  1276. var err error
  1277. config := vfs.GCSFsConfig{}
  1278. config.Bucket = r.Form.Get("gcs_bucket")
  1279. config.StorageClass = r.Form.Get("gcs_storage_class")
  1280. config.ACL = r.Form.Get("gcs_acl")
  1281. config.KeyPrefix = r.Form.Get("gcs_key_prefix")
  1282. autoCredentials := r.Form.Get("gcs_auto_credentials")
  1283. if autoCredentials != "" {
  1284. config.AutomaticCredentials = 1
  1285. } else {
  1286. config.AutomaticCredentials = 0
  1287. }
  1288. credentials, _, err := r.FormFile("gcs_credential_file")
  1289. if err == http.ErrMissingFile {
  1290. return config, nil
  1291. }
  1292. if err != nil {
  1293. return config, err
  1294. }
  1295. defer credentials.Close()
  1296. fileBytes, err := io.ReadAll(credentials)
  1297. if err != nil || len(fileBytes) == 0 {
  1298. if len(fileBytes) == 0 {
  1299. err = errors.New("credentials file size must be greater than 0")
  1300. }
  1301. return config, err
  1302. }
  1303. config.Credentials = kms.NewPlainSecret(string(fileBytes))
  1304. config.AutomaticCredentials = 0
  1305. return config, err
  1306. }
  1307. func getSFTPConfig(r *http.Request) (vfs.SFTPFsConfig, error) {
  1308. var err error
  1309. config := vfs.SFTPFsConfig{}
  1310. config.Endpoint = r.Form.Get("sftp_endpoint")
  1311. config.Username = r.Form.Get("sftp_username")
  1312. config.Password = getSecretFromFormField(r, "sftp_password")
  1313. config.PrivateKey = getSecretFromFormField(r, "sftp_private_key")
  1314. config.KeyPassphrase = getSecretFromFormField(r, "sftp_key_passphrase")
  1315. fingerprintsFormValue := r.Form.Get("sftp_fingerprints")
  1316. config.Fingerprints = getSliceFromDelimitedValues(fingerprintsFormValue, "\n")
  1317. config.Prefix = r.Form.Get("sftp_prefix")
  1318. config.DisableCouncurrentReads = r.Form.Get("sftp_disable_concurrent_reads") != ""
  1319. config.BufferSize, err = strconv.ParseInt(r.Form.Get("sftp_buffer_size"), 10, 64)
  1320. if r.Form.Get("sftp_equality_check_mode") != "" {
  1321. config.EqualityCheckMode = 1
  1322. } else {
  1323. config.EqualityCheckMode = 0
  1324. }
  1325. if err != nil {
  1326. return config, fmt.Errorf("invalid SFTP buffer size: %w", err)
  1327. }
  1328. return config, nil
  1329. }
  1330. func getHTTPFsConfig(r *http.Request) vfs.HTTPFsConfig {
  1331. config := vfs.HTTPFsConfig{}
  1332. config.Endpoint = r.Form.Get("http_endpoint")
  1333. config.Username = r.Form.Get("http_username")
  1334. config.SkipTLSVerify = r.Form.Get("http_skip_tls_verify") != ""
  1335. config.Password = getSecretFromFormField(r, "http_password")
  1336. config.APIKey = getSecretFromFormField(r, "http_api_key")
  1337. if r.Form.Get("http_equality_check_mode") != "" {
  1338. config.EqualityCheckMode = 1
  1339. } else {
  1340. config.EqualityCheckMode = 0
  1341. }
  1342. return config
  1343. }
  1344. func getAzureConfig(r *http.Request) (vfs.AzBlobFsConfig, error) {
  1345. var err error
  1346. config := vfs.AzBlobFsConfig{}
  1347. config.Container = r.Form.Get("az_container")
  1348. config.AccountName = r.Form.Get("az_account_name")
  1349. config.AccountKey = getSecretFromFormField(r, "az_account_key")
  1350. config.SASURL = getSecretFromFormField(r, "az_sas_url")
  1351. config.Endpoint = r.Form.Get("az_endpoint")
  1352. config.KeyPrefix = r.Form.Get("az_key_prefix")
  1353. config.AccessTier = r.Form.Get("az_access_tier")
  1354. config.UseEmulator = r.Form.Get("az_use_emulator") != ""
  1355. config.UploadPartSize, err = strconv.ParseInt(r.Form.Get("az_upload_part_size"), 10, 64)
  1356. if err != nil {
  1357. return config, fmt.Errorf("invalid azure upload part size: %w", err)
  1358. }
  1359. config.UploadConcurrency, err = strconv.Atoi(r.Form.Get("az_upload_concurrency"))
  1360. if err != nil {
  1361. return config, fmt.Errorf("invalid azure upload concurrency: %w", err)
  1362. }
  1363. config.DownloadPartSize, err = strconv.ParseInt(r.Form.Get("az_download_part_size"), 10, 64)
  1364. if err != nil {
  1365. return config, fmt.Errorf("invalid azure download part size: %w", err)
  1366. }
  1367. config.DownloadConcurrency, err = strconv.Atoi(r.Form.Get("az_download_concurrency"))
  1368. if err != nil {
  1369. return config, fmt.Errorf("invalid azure download concurrency: %w", err)
  1370. }
  1371. return config, nil
  1372. }
  1373. func getFsConfigFromPostFields(r *http.Request) (vfs.Filesystem, error) {
  1374. var fs vfs.Filesystem
  1375. fs.Provider = sdk.GetProviderByName(r.Form.Get("fs_provider"))
  1376. switch fs.Provider {
  1377. case sdk.S3FilesystemProvider:
  1378. config, err := getS3Config(r)
  1379. if err != nil {
  1380. return fs, err
  1381. }
  1382. fs.S3Config = config
  1383. case sdk.AzureBlobFilesystemProvider:
  1384. config, err := getAzureConfig(r)
  1385. if err != nil {
  1386. return fs, err
  1387. }
  1388. fs.AzBlobConfig = config
  1389. case sdk.GCSFilesystemProvider:
  1390. config, err := getGCSConfig(r)
  1391. if err != nil {
  1392. return fs, err
  1393. }
  1394. fs.GCSConfig = config
  1395. case sdk.CryptedFilesystemProvider:
  1396. fs.CryptConfig.Passphrase = getSecretFromFormField(r, "crypt_passphrase")
  1397. case sdk.SFTPFilesystemProvider:
  1398. config, err := getSFTPConfig(r)
  1399. if err != nil {
  1400. return fs, err
  1401. }
  1402. fs.SFTPConfig = config
  1403. case sdk.HTTPFilesystemProvider:
  1404. fs.HTTPConfig = getHTTPFsConfig(r)
  1405. }
  1406. return fs, nil
  1407. }
  1408. func getAdminFromPostFields(r *http.Request) (dataprovider.Admin, error) {
  1409. var admin dataprovider.Admin
  1410. err := r.ParseForm()
  1411. if err != nil {
  1412. return admin, err
  1413. }
  1414. status, err := strconv.Atoi(r.Form.Get("status"))
  1415. if err != nil {
  1416. return admin, fmt.Errorf("invalid status: %w", err)
  1417. }
  1418. admin.Username = r.Form.Get("username")
  1419. admin.Password = r.Form.Get("password")
  1420. admin.Permissions = r.Form["permissions"]
  1421. admin.Email = r.Form.Get("email")
  1422. admin.Status = status
  1423. admin.Filters.AllowList = getSliceFromDelimitedValues(r.Form.Get("allowed_ip"), ",")
  1424. admin.Filters.AllowAPIKeyAuth = r.Form.Get("allow_api_key_auth") != ""
  1425. admin.AdditionalInfo = r.Form.Get("additional_info")
  1426. admin.Description = r.Form.Get("description")
  1427. return admin, nil
  1428. }
  1429. func replacePlaceholders(field string, replacements map[string]string) string {
  1430. for k, v := range replacements {
  1431. field = strings.ReplaceAll(field, k, v)
  1432. }
  1433. return field
  1434. }
  1435. func getFolderFromTemplate(folder vfs.BaseVirtualFolder, name string) vfs.BaseVirtualFolder {
  1436. folder.Name = name
  1437. replacements := make(map[string]string)
  1438. replacements["%name%"] = folder.Name
  1439. folder.MappedPath = replacePlaceholders(folder.MappedPath, replacements)
  1440. folder.Description = replacePlaceholders(folder.Description, replacements)
  1441. switch folder.FsConfig.Provider {
  1442. case sdk.CryptedFilesystemProvider:
  1443. folder.FsConfig.CryptConfig = getCryptFsFromTemplate(folder.FsConfig.CryptConfig, replacements)
  1444. case sdk.S3FilesystemProvider:
  1445. folder.FsConfig.S3Config = getS3FsFromTemplate(folder.FsConfig.S3Config, replacements)
  1446. case sdk.GCSFilesystemProvider:
  1447. folder.FsConfig.GCSConfig = getGCSFsFromTemplate(folder.FsConfig.GCSConfig, replacements)
  1448. case sdk.AzureBlobFilesystemProvider:
  1449. folder.FsConfig.AzBlobConfig = getAzBlobFsFromTemplate(folder.FsConfig.AzBlobConfig, replacements)
  1450. case sdk.SFTPFilesystemProvider:
  1451. folder.FsConfig.SFTPConfig = getSFTPFsFromTemplate(folder.FsConfig.SFTPConfig, replacements)
  1452. case sdk.HTTPFilesystemProvider:
  1453. folder.FsConfig.HTTPConfig = getHTTPFsFromTemplate(folder.FsConfig.HTTPConfig, replacements)
  1454. }
  1455. return folder
  1456. }
  1457. func getCryptFsFromTemplate(fsConfig vfs.CryptFsConfig, replacements map[string]string) vfs.CryptFsConfig {
  1458. if fsConfig.Passphrase != nil {
  1459. if fsConfig.Passphrase.IsPlain() {
  1460. payload := replacePlaceholders(fsConfig.Passphrase.GetPayload(), replacements)
  1461. fsConfig.Passphrase = kms.NewPlainSecret(payload)
  1462. }
  1463. }
  1464. return fsConfig
  1465. }
  1466. func getS3FsFromTemplate(fsConfig vfs.S3FsConfig, replacements map[string]string) vfs.S3FsConfig {
  1467. fsConfig.KeyPrefix = replacePlaceholders(fsConfig.KeyPrefix, replacements)
  1468. fsConfig.AccessKey = replacePlaceholders(fsConfig.AccessKey, replacements)
  1469. if fsConfig.AccessSecret != nil && fsConfig.AccessSecret.IsPlain() {
  1470. payload := replacePlaceholders(fsConfig.AccessSecret.GetPayload(), replacements)
  1471. fsConfig.AccessSecret = kms.NewPlainSecret(payload)
  1472. }
  1473. return fsConfig
  1474. }
  1475. func getGCSFsFromTemplate(fsConfig vfs.GCSFsConfig, replacements map[string]string) vfs.GCSFsConfig {
  1476. fsConfig.KeyPrefix = replacePlaceholders(fsConfig.KeyPrefix, replacements)
  1477. return fsConfig
  1478. }
  1479. func getAzBlobFsFromTemplate(fsConfig vfs.AzBlobFsConfig, replacements map[string]string) vfs.AzBlobFsConfig {
  1480. fsConfig.KeyPrefix = replacePlaceholders(fsConfig.KeyPrefix, replacements)
  1481. fsConfig.AccountName = replacePlaceholders(fsConfig.AccountName, replacements)
  1482. if fsConfig.AccountKey != nil && fsConfig.AccountKey.IsPlain() {
  1483. payload := replacePlaceholders(fsConfig.AccountKey.GetPayload(), replacements)
  1484. fsConfig.AccountKey = kms.NewPlainSecret(payload)
  1485. }
  1486. return fsConfig
  1487. }
  1488. func getSFTPFsFromTemplate(fsConfig vfs.SFTPFsConfig, replacements map[string]string) vfs.SFTPFsConfig {
  1489. fsConfig.Prefix = replacePlaceholders(fsConfig.Prefix, replacements)
  1490. fsConfig.Username = replacePlaceholders(fsConfig.Username, replacements)
  1491. if fsConfig.Password != nil && fsConfig.Password.IsPlain() {
  1492. payload := replacePlaceholders(fsConfig.Password.GetPayload(), replacements)
  1493. fsConfig.Password = kms.NewPlainSecret(payload)
  1494. }
  1495. return fsConfig
  1496. }
  1497. func getHTTPFsFromTemplate(fsConfig vfs.HTTPFsConfig, replacements map[string]string) vfs.HTTPFsConfig {
  1498. fsConfig.Username = replacePlaceholders(fsConfig.Username, replacements)
  1499. return fsConfig
  1500. }
  1501. func getUserFromTemplate(user dataprovider.User, template userTemplateFields) dataprovider.User {
  1502. user.Username = template.Username
  1503. user.Password = template.Password
  1504. user.PublicKeys = template.PublicKeys
  1505. replacements := make(map[string]string)
  1506. replacements["%username%"] = user.Username
  1507. if user.Password != "" && !user.IsPasswordHashed() {
  1508. user.Password = replacePlaceholders(user.Password, replacements)
  1509. replacements["%password%"] = user.Password
  1510. }
  1511. user.HomeDir = replacePlaceholders(user.HomeDir, replacements)
  1512. var vfolders []vfs.VirtualFolder
  1513. for _, vfolder := range user.VirtualFolders {
  1514. vfolder.Name = replacePlaceholders(vfolder.Name, replacements)
  1515. vfolder.VirtualPath = replacePlaceholders(vfolder.VirtualPath, replacements)
  1516. vfolders = append(vfolders, vfolder)
  1517. }
  1518. user.VirtualFolders = vfolders
  1519. user.Description = replacePlaceholders(user.Description, replacements)
  1520. user.AdditionalInfo = replacePlaceholders(user.AdditionalInfo, replacements)
  1521. user.Filters.StartDirectory = replacePlaceholders(user.Filters.StartDirectory, replacements)
  1522. switch user.FsConfig.Provider {
  1523. case sdk.CryptedFilesystemProvider:
  1524. user.FsConfig.CryptConfig = getCryptFsFromTemplate(user.FsConfig.CryptConfig, replacements)
  1525. case sdk.S3FilesystemProvider:
  1526. user.FsConfig.S3Config = getS3FsFromTemplate(user.FsConfig.S3Config, replacements)
  1527. case sdk.GCSFilesystemProvider:
  1528. user.FsConfig.GCSConfig = getGCSFsFromTemplate(user.FsConfig.GCSConfig, replacements)
  1529. case sdk.AzureBlobFilesystemProvider:
  1530. user.FsConfig.AzBlobConfig = getAzBlobFsFromTemplate(user.FsConfig.AzBlobConfig, replacements)
  1531. case sdk.SFTPFilesystemProvider:
  1532. user.FsConfig.SFTPConfig = getSFTPFsFromTemplate(user.FsConfig.SFTPConfig, replacements)
  1533. case sdk.HTTPFilesystemProvider:
  1534. user.FsConfig.HTTPConfig = getHTTPFsFromTemplate(user.FsConfig.HTTPConfig, replacements)
  1535. }
  1536. return user
  1537. }
  1538. func getTransferLimits(r *http.Request) (int64, int64, int64, error) {
  1539. dataTransferUL, err := strconv.ParseInt(r.Form.Get("upload_data_transfer"), 10, 64)
  1540. if err != nil {
  1541. return 0, 0, 0, fmt.Errorf("invalid upload data transfer: %w", err)
  1542. }
  1543. dataTransferDL, err := strconv.ParseInt(r.Form.Get("download_data_transfer"), 10, 64)
  1544. if err != nil {
  1545. return 0, 0, 0, fmt.Errorf("invalid download data transfer: %w", err)
  1546. }
  1547. dataTransferTotal, err := strconv.ParseInt(r.Form.Get("total_data_transfer"), 10, 64)
  1548. if err != nil {
  1549. return 0, 0, 0, fmt.Errorf("invalid total data transfer: %w", err)
  1550. }
  1551. return dataTransferUL, dataTransferDL, dataTransferTotal, nil
  1552. }
  1553. func getQuotaLimits(r *http.Request) (int64, int, error) {
  1554. quotaSize, err := strconv.ParseInt(r.Form.Get("quota_size"), 10, 64)
  1555. if err != nil {
  1556. return 0, 0, fmt.Errorf("invalid quota size: %w", err)
  1557. }
  1558. quotaFiles, err := strconv.Atoi(r.Form.Get("quota_files"))
  1559. if err != nil {
  1560. return 0, 0, fmt.Errorf("invalid quota files: %w", err)
  1561. }
  1562. return quotaSize, quotaFiles, nil
  1563. }
  1564. func getUserFromPostFields(r *http.Request) (dataprovider.User, error) {
  1565. user := dataprovider.User{}
  1566. err := r.ParseMultipartForm(maxRequestSize)
  1567. if err != nil {
  1568. return user, err
  1569. }
  1570. defer r.MultipartForm.RemoveAll() //nolint:errcheck
  1571. uid, err := strconv.Atoi(r.Form.Get("uid"))
  1572. if err != nil {
  1573. return user, fmt.Errorf("invalid uid: %w", err)
  1574. }
  1575. gid, err := strconv.Atoi(r.Form.Get("gid"))
  1576. if err != nil {
  1577. return user, fmt.Errorf("invalid uid: %w", err)
  1578. }
  1579. maxSessions, err := strconv.Atoi(r.Form.Get("max_sessions"))
  1580. if err != nil {
  1581. return user, fmt.Errorf("invalid max sessions: %w", err)
  1582. }
  1583. quotaSize, quotaFiles, err := getQuotaLimits(r)
  1584. if err != nil {
  1585. return user, err
  1586. }
  1587. bandwidthUL, err := strconv.ParseInt(r.Form.Get("upload_bandwidth"), 10, 64)
  1588. if err != nil {
  1589. return user, fmt.Errorf("invalid upload bandwidth: %w", err)
  1590. }
  1591. bandwidthDL, err := strconv.ParseInt(r.Form.Get("download_bandwidth"), 10, 64)
  1592. if err != nil {
  1593. return user, fmt.Errorf("invalid download bandwidth: %w", err)
  1594. }
  1595. dataTransferUL, dataTransferDL, dataTransferTotal, err := getTransferLimits(r)
  1596. if err != nil {
  1597. return user, err
  1598. }
  1599. status, err := strconv.Atoi(r.Form.Get("status"))
  1600. if err != nil {
  1601. return user, fmt.Errorf("invalid status: %w", err)
  1602. }
  1603. expirationDateMillis := int64(0)
  1604. expirationDateString := r.Form.Get("expiration_date")
  1605. if strings.TrimSpace(expirationDateString) != "" {
  1606. expirationDate, err := time.Parse(webDateTimeFormat, expirationDateString)
  1607. if err != nil {
  1608. return user, err
  1609. }
  1610. expirationDateMillis = util.GetTimeAsMsSinceEpoch(expirationDate)
  1611. }
  1612. fsConfig, err := getFsConfigFromPostFields(r)
  1613. if err != nil {
  1614. return user, err
  1615. }
  1616. filters, err := getFiltersFromUserPostFields(r)
  1617. if err != nil {
  1618. return user, err
  1619. }
  1620. user = dataprovider.User{
  1621. BaseUser: sdk.BaseUser{
  1622. Username: r.Form.Get("username"),
  1623. Email: r.Form.Get("email"),
  1624. Password: r.Form.Get("password"),
  1625. PublicKeys: r.Form["public_keys"],
  1626. HomeDir: r.Form.Get("home_dir"),
  1627. UID: uid,
  1628. GID: gid,
  1629. Permissions: getUserPermissionsFromPostFields(r),
  1630. MaxSessions: maxSessions,
  1631. QuotaSize: quotaSize,
  1632. QuotaFiles: quotaFiles,
  1633. UploadBandwidth: bandwidthUL,
  1634. DownloadBandwidth: bandwidthDL,
  1635. UploadDataTransfer: dataTransferUL,
  1636. DownloadDataTransfer: dataTransferDL,
  1637. TotalDataTransfer: dataTransferTotal,
  1638. Status: status,
  1639. ExpirationDate: expirationDateMillis,
  1640. AdditionalInfo: r.Form.Get("additional_info"),
  1641. Description: r.Form.Get("description"),
  1642. },
  1643. Filters: dataprovider.UserFilters{
  1644. BaseUserFilters: filters,
  1645. },
  1646. VirtualFolders: getVirtualFoldersFromPostFields(r),
  1647. FsConfig: fsConfig,
  1648. Groups: getGroupsFromUserPostFields(r),
  1649. }
  1650. return user, nil
  1651. }
  1652. func getGroupFromPostFields(r *http.Request) (dataprovider.Group, error) {
  1653. group := dataprovider.Group{}
  1654. err := r.ParseMultipartForm(maxRequestSize)
  1655. if err != nil {
  1656. return group, err
  1657. }
  1658. defer r.MultipartForm.RemoveAll() //nolint:errcheck
  1659. maxSessions, err := strconv.Atoi(r.Form.Get("max_sessions"))
  1660. if err != nil {
  1661. return group, fmt.Errorf("invalid max sessions: %w", err)
  1662. }
  1663. quotaSize, quotaFiles, err := getQuotaLimits(r)
  1664. if err != nil {
  1665. return group, err
  1666. }
  1667. bandwidthUL, err := strconv.ParseInt(r.Form.Get("upload_bandwidth"), 10, 64)
  1668. if err != nil {
  1669. return group, fmt.Errorf("invalid upload bandwidth: %w", err)
  1670. }
  1671. bandwidthDL, err := strconv.ParseInt(r.Form.Get("download_bandwidth"), 10, 64)
  1672. if err != nil {
  1673. return group, fmt.Errorf("invalid download bandwidth: %w", err)
  1674. }
  1675. dataTransferUL, dataTransferDL, dataTransferTotal, err := getTransferLimits(r)
  1676. if err != nil {
  1677. return group, err
  1678. }
  1679. fsConfig, err := getFsConfigFromPostFields(r)
  1680. if err != nil {
  1681. return group, err
  1682. }
  1683. filters, err := getFiltersFromUserPostFields(r)
  1684. if err != nil {
  1685. return group, err
  1686. }
  1687. group = dataprovider.Group{
  1688. BaseGroup: sdk.BaseGroup{
  1689. Name: r.Form.Get("name"),
  1690. Description: r.Form.Get("description"),
  1691. },
  1692. UserSettings: dataprovider.GroupUserSettings{
  1693. BaseGroupUserSettings: sdk.BaseGroupUserSettings{
  1694. HomeDir: r.Form.Get("home_dir"),
  1695. MaxSessions: maxSessions,
  1696. QuotaSize: quotaSize,
  1697. QuotaFiles: quotaFiles,
  1698. Permissions: getSubDirPermissionsFromPostFields(r),
  1699. UploadBandwidth: bandwidthUL,
  1700. DownloadBandwidth: bandwidthDL,
  1701. UploadDataTransfer: dataTransferUL,
  1702. DownloadDataTransfer: dataTransferDL,
  1703. TotalDataTransfer: dataTransferTotal,
  1704. Filters: filters,
  1705. },
  1706. FsConfig: fsConfig,
  1707. },
  1708. VirtualFolders: getVirtualFoldersFromPostFields(r),
  1709. }
  1710. return group, nil
  1711. }
  1712. func getKeyValsFromPostFields(r *http.Request, key, val string) []dataprovider.KeyValue {
  1713. var res []dataprovider.KeyValue
  1714. for k := range r.Form {
  1715. if strings.HasPrefix(k, key) {
  1716. formKey := r.Form.Get(k)
  1717. idx := strings.TrimPrefix(k, key)
  1718. formVal := r.Form.Get(fmt.Sprintf("%s%s", val, idx))
  1719. if formKey != "" && formVal != "" {
  1720. res = append(res, dataprovider.KeyValue{
  1721. Key: formKey,
  1722. Value: formVal,
  1723. })
  1724. }
  1725. }
  1726. }
  1727. return res
  1728. }
  1729. func getFoldersRetentionFromPostFields(r *http.Request) ([]dataprovider.FolderRetention, error) {
  1730. var res []dataprovider.FolderRetention
  1731. for k := range r.Form {
  1732. if strings.HasPrefix(k, "folder_retention_path") {
  1733. folderPath := r.Form.Get(k)
  1734. if folderPath != "" {
  1735. idx := strings.TrimPrefix(k, "folder_retention_path")
  1736. retention, err := strconv.Atoi(r.Form.Get(fmt.Sprintf("folder_retention_val%s", idx)))
  1737. if err != nil {
  1738. return nil, fmt.Errorf("invalid retention for path %q: %w", folderPath, err)
  1739. }
  1740. options := r.Form[fmt.Sprintf("folder_retention_options%s", idx)]
  1741. res = append(res, dataprovider.FolderRetention{
  1742. Path: folderPath,
  1743. Retention: retention,
  1744. DeleteEmptyDirs: util.Contains(options, "1"),
  1745. IgnoreUserPermissions: util.Contains(options, "2"),
  1746. })
  1747. }
  1748. }
  1749. }
  1750. return res, nil
  1751. }
  1752. func getHTTPPartsFromPostFields(r *http.Request) []dataprovider.HTTPPart {
  1753. var result []dataprovider.HTTPPart
  1754. for k := range r.Form {
  1755. if strings.HasPrefix(k, "http_part_name") {
  1756. partName := r.Form.Get(k)
  1757. if partName != "" {
  1758. idx := strings.TrimPrefix(k, "http_part_name")
  1759. order, err := strconv.Atoi(idx)
  1760. if err != nil {
  1761. continue
  1762. }
  1763. filePath := r.Form.Get(fmt.Sprintf("http_part_file%s", idx))
  1764. body := r.Form.Get(fmt.Sprintf("http_part_body%s", idx))
  1765. concatHeaders := getSliceFromDelimitedValues(r.Form.Get(fmt.Sprintf("http_part_headers%s", idx)), "\n")
  1766. var headers []dataprovider.KeyValue
  1767. for _, h := range concatHeaders {
  1768. values := strings.SplitN(h, ":", 2)
  1769. if len(values) > 1 {
  1770. headers = append(headers, dataprovider.KeyValue{
  1771. Key: strings.TrimSpace(values[0]),
  1772. Value: strings.TrimSpace(values[1]),
  1773. })
  1774. }
  1775. }
  1776. result = append(result, dataprovider.HTTPPart{
  1777. Name: partName,
  1778. Filepath: filePath,
  1779. Headers: headers,
  1780. Body: body,
  1781. Order: order,
  1782. })
  1783. }
  1784. }
  1785. }
  1786. sort.Slice(result, func(i, j int) bool {
  1787. return result[i].Order < result[j].Order
  1788. })
  1789. return result
  1790. }
  1791. func getEventActionOptionsFromPostFields(r *http.Request) (dataprovider.BaseEventActionOptions, error) {
  1792. httpTimeout, err := strconv.Atoi(r.Form.Get("http_timeout"))
  1793. if err != nil {
  1794. return dataprovider.BaseEventActionOptions{}, fmt.Errorf("invalid http timeout: %w", err)
  1795. }
  1796. cmdTimeout, err := strconv.Atoi(r.Form.Get("cmd_timeout"))
  1797. if err != nil {
  1798. return dataprovider.BaseEventActionOptions{}, fmt.Errorf("invalid command timeout: %w", err)
  1799. }
  1800. foldersRetention, err := getFoldersRetentionFromPostFields(r)
  1801. if err != nil {
  1802. return dataprovider.BaseEventActionOptions{}, err
  1803. }
  1804. fsActionType, err := strconv.Atoi(r.Form.Get("fs_action_type"))
  1805. if err != nil {
  1806. return dataprovider.BaseEventActionOptions{}, fmt.Errorf("invalid fs action type: %w", err)
  1807. }
  1808. var emailAttachments []string
  1809. if r.Form.Get("email_attachments") != "" {
  1810. emailAttachments = strings.Split(strings.ReplaceAll(r.Form.Get("email_attachments"), " ", ""), ",")
  1811. }
  1812. var cmdArgs []string
  1813. if r.Form.Get("cmd_arguments") != "" {
  1814. cmdArgs = strings.Split(strings.ReplaceAll(r.Form.Get("cmd_arguments"), " ", ""), ",")
  1815. }
  1816. options := dataprovider.BaseEventActionOptions{
  1817. HTTPConfig: dataprovider.EventActionHTTPConfig{
  1818. Endpoint: r.Form.Get("http_endpoint"),
  1819. Username: r.Form.Get("http_username"),
  1820. Password: getSecretFromFormField(r, "http_password"),
  1821. Headers: getKeyValsFromPostFields(r, "http_header_key", "http_header_val"),
  1822. Timeout: httpTimeout,
  1823. SkipTLSVerify: r.Form.Get("http_skip_tls_verify") != "",
  1824. Method: r.Form.Get("http_method"),
  1825. QueryParameters: getKeyValsFromPostFields(r, "http_query_key", "http_query_val"),
  1826. Body: r.Form.Get("http_body"),
  1827. Parts: getHTTPPartsFromPostFields(r),
  1828. },
  1829. CmdConfig: dataprovider.EventActionCommandConfig{
  1830. Cmd: r.Form.Get("cmd_path"),
  1831. Args: cmdArgs,
  1832. Timeout: cmdTimeout,
  1833. EnvVars: getKeyValsFromPostFields(r, "cmd_env_key", "cmd_env_val"),
  1834. },
  1835. EmailConfig: dataprovider.EventActionEmailConfig{
  1836. Recipients: strings.Split(strings.ReplaceAll(r.Form.Get("email_recipients"), " ", ""), ","),
  1837. Subject: r.Form.Get("email_subject"),
  1838. Body: r.Form.Get("email_body"),
  1839. Attachments: emailAttachments,
  1840. },
  1841. RetentionConfig: dataprovider.EventActionDataRetentionConfig{
  1842. Folders: foldersRetention,
  1843. },
  1844. FsConfig: dataprovider.EventActionFilesystemConfig{
  1845. Type: fsActionType,
  1846. Renames: getKeyValsFromPostFields(r, "fs_rename_source", "fs_rename_target"),
  1847. Deletes: strings.Split(strings.ReplaceAll(r.Form.Get("fs_delete_paths"), " ", ""), ","),
  1848. MkDirs: strings.Split(strings.ReplaceAll(r.Form.Get("fs_mkdir_paths"), " ", ""), ","),
  1849. Exist: strings.Split(strings.ReplaceAll(r.Form.Get("fs_exist_paths"), " ", ""), ","),
  1850. },
  1851. }
  1852. return options, nil
  1853. }
  1854. func getEventActionFromPostFields(r *http.Request) (dataprovider.BaseEventAction, error) {
  1855. err := r.ParseForm()
  1856. if err != nil {
  1857. return dataprovider.BaseEventAction{}, err
  1858. }
  1859. actionType, err := strconv.Atoi(r.Form.Get("type"))
  1860. if err != nil {
  1861. return dataprovider.BaseEventAction{}, fmt.Errorf("invalid action type: %w", err)
  1862. }
  1863. options, err := getEventActionOptionsFromPostFields(r)
  1864. if err != nil {
  1865. return dataprovider.BaseEventAction{}, err
  1866. }
  1867. action := dataprovider.BaseEventAction{
  1868. Name: r.Form.Get("name"),
  1869. Description: r.Form.Get("description"),
  1870. Type: actionType,
  1871. Options: options,
  1872. }
  1873. return action, nil
  1874. }
  1875. func getEventRuleConditionsFromPostFields(r *http.Request) (dataprovider.EventConditions, error) {
  1876. var schedules []dataprovider.Schedule
  1877. var names, groupNames, fsPaths []dataprovider.ConditionPattern
  1878. for k := range r.Form {
  1879. if strings.HasPrefix(k, "schedule_hour") {
  1880. hour := r.Form.Get(k)
  1881. if hour != "" {
  1882. idx := strings.TrimPrefix(k, "schedule_hour")
  1883. dayOfWeek := r.Form.Get(fmt.Sprintf("schedule_day_of_week%s", idx))
  1884. dayOfMonth := r.Form.Get(fmt.Sprintf("schedule_day_of_month%s", idx))
  1885. month := r.Form.Get(fmt.Sprintf("schedule_month%s", idx))
  1886. schedules = append(schedules, dataprovider.Schedule{
  1887. Hours: hour,
  1888. DayOfWeek: dayOfWeek,
  1889. DayOfMonth: dayOfMonth,
  1890. Month: month,
  1891. })
  1892. }
  1893. }
  1894. if strings.HasPrefix(k, "name_pattern") {
  1895. pattern := r.Form.Get(k)
  1896. if pattern != "" {
  1897. idx := strings.TrimPrefix(k, "name_pattern")
  1898. patternType := r.Form.Get(fmt.Sprintf("type_name_pattern%s", idx))
  1899. names = append(names, dataprovider.ConditionPattern{
  1900. Pattern: pattern,
  1901. InverseMatch: patternType == inversePatternType,
  1902. })
  1903. }
  1904. }
  1905. if strings.HasPrefix(k, "group_name_pattern") {
  1906. pattern := r.Form.Get(k)
  1907. if pattern != "" {
  1908. idx := strings.TrimPrefix(k, "group_name_pattern")
  1909. patternType := r.Form.Get(fmt.Sprintf("type_group_name_pattern%s", idx))
  1910. groupNames = append(groupNames, dataprovider.ConditionPattern{
  1911. Pattern: pattern,
  1912. InverseMatch: patternType == inversePatternType,
  1913. })
  1914. }
  1915. }
  1916. if strings.HasPrefix(k, "fs_path_pattern") {
  1917. pattern := r.Form.Get(k)
  1918. if pattern != "" {
  1919. idx := strings.TrimPrefix(k, "fs_path_pattern")
  1920. patternType := r.Form.Get(fmt.Sprintf("type_fs_path_pattern%s", idx))
  1921. fsPaths = append(fsPaths, dataprovider.ConditionPattern{
  1922. Pattern: pattern,
  1923. InverseMatch: patternType == inversePatternType,
  1924. })
  1925. }
  1926. }
  1927. }
  1928. minFileSize, err := strconv.ParseInt(r.Form.Get("fs_min_size"), 10, 64)
  1929. if err != nil {
  1930. return dataprovider.EventConditions{}, fmt.Errorf("invalid min file size: %w", err)
  1931. }
  1932. maxFileSize, err := strconv.ParseInt(r.Form.Get("fs_max_size"), 10, 64)
  1933. if err != nil {
  1934. return dataprovider.EventConditions{}, fmt.Errorf("invalid max file size: %w", err)
  1935. }
  1936. conditions := dataprovider.EventConditions{
  1937. FsEvents: r.Form["fs_events"],
  1938. ProviderEvents: r.Form["provider_events"],
  1939. Schedules: schedules,
  1940. Options: dataprovider.ConditionOptions{
  1941. Names: names,
  1942. GroupNames: groupNames,
  1943. FsPaths: fsPaths,
  1944. Protocols: r.Form["fs_protocols"],
  1945. ProviderObjects: r.Form["provider_objects"],
  1946. MinFileSize: minFileSize,
  1947. MaxFileSize: maxFileSize,
  1948. ConcurrentExecution: r.Form.Get("concurrent_execution") != "",
  1949. },
  1950. }
  1951. return conditions, nil
  1952. }
  1953. func getEventRuleActionsFromPostFields(r *http.Request) ([]dataprovider.EventAction, error) {
  1954. var actions []dataprovider.EventAction
  1955. for k := range r.Form {
  1956. if strings.HasPrefix(k, "action_name") {
  1957. name := r.Form.Get(k)
  1958. if name != "" {
  1959. idx := strings.TrimPrefix(k, "action_name")
  1960. order, err := strconv.Atoi(r.Form.Get(fmt.Sprintf("action_order%s", idx)))
  1961. if err != nil {
  1962. return actions, fmt.Errorf("invalid order: %w", err)
  1963. }
  1964. options := r.Form[fmt.Sprintf("action_options%s", idx)]
  1965. actions = append(actions, dataprovider.EventAction{
  1966. BaseEventAction: dataprovider.BaseEventAction{
  1967. Name: name,
  1968. },
  1969. Order: order + 1,
  1970. Options: dataprovider.EventActionOptions{
  1971. IsFailureAction: util.Contains(options, "1"),
  1972. StopOnFailure: util.Contains(options, "2"),
  1973. ExecuteSync: util.Contains(options, "3"),
  1974. },
  1975. })
  1976. }
  1977. }
  1978. }
  1979. return actions, nil
  1980. }
  1981. func getEventRuleFromPostFields(r *http.Request) (dataprovider.EventRule, error) {
  1982. err := r.ParseForm()
  1983. if err != nil {
  1984. return dataprovider.EventRule{}, err
  1985. }
  1986. trigger, err := strconv.Atoi(r.Form.Get("trigger"))
  1987. if err != nil {
  1988. return dataprovider.EventRule{}, fmt.Errorf("invalid trigger: %w", err)
  1989. }
  1990. conditions, err := getEventRuleConditionsFromPostFields(r)
  1991. if err != nil {
  1992. return dataprovider.EventRule{}, err
  1993. }
  1994. actions, err := getEventRuleActionsFromPostFields(r)
  1995. if err != nil {
  1996. return dataprovider.EventRule{}, err
  1997. }
  1998. rule := dataprovider.EventRule{
  1999. Name: r.Form.Get("name"),
  2000. Description: r.Form.Get("description"),
  2001. Trigger: trigger,
  2002. Conditions: conditions,
  2003. Actions: actions,
  2004. }
  2005. return rule, nil
  2006. }
  2007. func (s *httpdServer) handleWebAdminForgotPwd(w http.ResponseWriter, r *http.Request) {
  2008. r.Body = http.MaxBytesReader(w, r.Body, maxRequestSize)
  2009. if !smtp.IsEnabled() {
  2010. s.renderNotFoundPage(w, r, errors.New("this page does not exist"))
  2011. return
  2012. }
  2013. s.renderForgotPwdPage(w, "", util.GetIPFromRemoteAddress(r.RemoteAddr))
  2014. }
  2015. func (s *httpdServer) handleWebAdminForgotPwdPost(w http.ResponseWriter, r *http.Request) {
  2016. r.Body = http.MaxBytesReader(w, r.Body, maxRequestSize)
  2017. ipAddr := util.GetIPFromRemoteAddress(r.RemoteAddr)
  2018. err := r.ParseForm()
  2019. if err != nil {
  2020. s.renderForgotPwdPage(w, err.Error(), ipAddr)
  2021. return
  2022. }
  2023. if err := verifyCSRFToken(r.Form.Get(csrfFormToken), ipAddr); err != nil {
  2024. s.renderForbiddenPage(w, r, err.Error())
  2025. return
  2026. }
  2027. err = handleForgotPassword(r, r.Form.Get("username"), true)
  2028. if err != nil {
  2029. if e, ok := err.(*util.ValidationError); ok {
  2030. s.renderForgotPwdPage(w, e.GetErrorString(), ipAddr)
  2031. return
  2032. }
  2033. s.renderForgotPwdPage(w, err.Error(), ipAddr)
  2034. return
  2035. }
  2036. http.Redirect(w, r, webAdminResetPwdPath, http.StatusFound)
  2037. }
  2038. func (s *httpdServer) handleWebAdminPasswordReset(w http.ResponseWriter, r *http.Request) {
  2039. r.Body = http.MaxBytesReader(w, r.Body, maxLoginBodySize)
  2040. if !smtp.IsEnabled() {
  2041. s.renderNotFoundPage(w, r, errors.New("this page does not exist"))
  2042. return
  2043. }
  2044. s.renderResetPwdPage(w, "", util.GetIPFromRemoteAddress(r.RemoteAddr))
  2045. }
  2046. func (s *httpdServer) handleWebAdminTwoFactor(w http.ResponseWriter, r *http.Request) {
  2047. r.Body = http.MaxBytesReader(w, r.Body, maxRequestSize)
  2048. s.renderTwoFactorPage(w, "", util.GetIPFromRemoteAddress(r.RemoteAddr))
  2049. }
  2050. func (s *httpdServer) handleWebAdminTwoFactorRecovery(w http.ResponseWriter, r *http.Request) {
  2051. r.Body = http.MaxBytesReader(w, r.Body, maxRequestSize)
  2052. s.renderTwoFactorRecoveryPage(w, "", util.GetIPFromRemoteAddress(r.RemoteAddr))
  2053. }
  2054. func (s *httpdServer) handleWebAdminMFA(w http.ResponseWriter, r *http.Request) {
  2055. r.Body = http.MaxBytesReader(w, r.Body, maxRequestSize)
  2056. s.renderMFAPage(w, r)
  2057. }
  2058. func (s *httpdServer) handleWebAdminProfile(w http.ResponseWriter, r *http.Request) {
  2059. r.Body = http.MaxBytesReader(w, r.Body, maxRequestSize)
  2060. s.renderProfilePage(w, r, "")
  2061. }
  2062. func (s *httpdServer) handleWebAdminChangePwd(w http.ResponseWriter, r *http.Request) {
  2063. r.Body = http.MaxBytesReader(w, r.Body, maxRequestSize)
  2064. s.renderChangePasswordPage(w, r, "")
  2065. }
  2066. func (s *httpdServer) handleWebAdminProfilePost(w http.ResponseWriter, r *http.Request) {
  2067. r.Body = http.MaxBytesReader(w, r.Body, maxRequestSize)
  2068. err := r.ParseForm()
  2069. if err != nil {
  2070. s.renderProfilePage(w, r, err.Error())
  2071. return
  2072. }
  2073. ipAddr := util.GetIPFromRemoteAddress(r.RemoteAddr)
  2074. if err := verifyCSRFToken(r.Form.Get(csrfFormToken), ipAddr); err != nil {
  2075. s.renderForbiddenPage(w, r, err.Error())
  2076. return
  2077. }
  2078. claims, err := getTokenClaims(r)
  2079. if err != nil || claims.Username == "" {
  2080. s.renderProfilePage(w, r, "Invalid token claims")
  2081. return
  2082. }
  2083. admin, err := dataprovider.AdminExists(claims.Username)
  2084. if err != nil {
  2085. s.renderProfilePage(w, r, err.Error())
  2086. return
  2087. }
  2088. admin.Filters.AllowAPIKeyAuth = r.Form.Get("allow_api_key_auth") != ""
  2089. admin.Email = r.Form.Get("email")
  2090. admin.Description = r.Form.Get("description")
  2091. err = dataprovider.UpdateAdmin(&admin, dataprovider.ActionExecutorSelf, ipAddr)
  2092. if err != nil {
  2093. s.renderProfilePage(w, r, err.Error())
  2094. return
  2095. }
  2096. s.renderMessagePage(w, r, "Profile updated", "", http.StatusOK, nil,
  2097. "Your profile has been successfully updated")
  2098. }
  2099. func (s *httpdServer) handleWebMaintenance(w http.ResponseWriter, r *http.Request) {
  2100. r.Body = http.MaxBytesReader(w, r.Body, maxRequestSize)
  2101. s.renderMaintenancePage(w, r, "")
  2102. }
  2103. func (s *httpdServer) handleWebRestore(w http.ResponseWriter, r *http.Request) {
  2104. r.Body = http.MaxBytesReader(w, r.Body, MaxRestoreSize)
  2105. claims, err := getTokenClaims(r)
  2106. if err != nil || claims.Username == "" {
  2107. s.renderBadRequestPage(w, r, errors.New("invalid token claims"))
  2108. return
  2109. }
  2110. err = r.ParseMultipartForm(MaxRestoreSize)
  2111. if err != nil {
  2112. s.renderMaintenancePage(w, r, err.Error())
  2113. return
  2114. }
  2115. defer r.MultipartForm.RemoveAll() //nolint:errcheck
  2116. ipAddr := util.GetIPFromRemoteAddress(r.RemoteAddr)
  2117. if err := verifyCSRFToken(r.Form.Get(csrfFormToken), ipAddr); err != nil {
  2118. s.renderForbiddenPage(w, r, err.Error())
  2119. return
  2120. }
  2121. restoreMode, err := strconv.Atoi(r.Form.Get("mode"))
  2122. if err != nil {
  2123. s.renderMaintenancePage(w, r, err.Error())
  2124. return
  2125. }
  2126. scanQuota, err := strconv.Atoi(r.Form.Get("quota"))
  2127. if err != nil {
  2128. s.renderMaintenancePage(w, r, err.Error())
  2129. return
  2130. }
  2131. backupFile, _, err := r.FormFile("backup_file")
  2132. if err != nil {
  2133. s.renderMaintenancePage(w, r, err.Error())
  2134. return
  2135. }
  2136. defer backupFile.Close()
  2137. backupContent, err := io.ReadAll(backupFile)
  2138. if err != nil || len(backupContent) == 0 {
  2139. if len(backupContent) == 0 {
  2140. err = errors.New("backup file size must be greater than 0")
  2141. }
  2142. s.renderMaintenancePage(w, r, err.Error())
  2143. return
  2144. }
  2145. if err := restoreBackup(backupContent, "", scanQuota, restoreMode, claims.Username, ipAddr); err != nil {
  2146. s.renderMaintenancePage(w, r, err.Error())
  2147. return
  2148. }
  2149. s.renderMessagePage(w, r, "Data restored", "", http.StatusOK, nil, "Your backup was successfully restored")
  2150. }
  2151. func (s *httpdServer) handleGetWebAdmins(w http.ResponseWriter, r *http.Request) {
  2152. r.Body = http.MaxBytesReader(w, r.Body, maxRequestSize)
  2153. limit := defaultQueryLimit
  2154. if _, ok := r.URL.Query()["qlimit"]; ok {
  2155. var err error
  2156. limit, err = strconv.Atoi(r.URL.Query().Get("qlimit"))
  2157. if err != nil {
  2158. limit = defaultQueryLimit
  2159. }
  2160. }
  2161. admins := make([]dataprovider.Admin, 0, limit)
  2162. for {
  2163. a, err := dataprovider.GetAdmins(limit, len(admins), dataprovider.OrderASC)
  2164. if err != nil {
  2165. s.renderInternalServerErrorPage(w, r, err)
  2166. return
  2167. }
  2168. admins = append(admins, a...)
  2169. if len(a) < limit {
  2170. break
  2171. }
  2172. }
  2173. data := adminsPage{
  2174. basePage: s.getBasePageData(pageAdminsTitle, webAdminsPath, r),
  2175. Admins: admins,
  2176. }
  2177. renderAdminTemplate(w, templateAdmins, data)
  2178. }
  2179. func (s *httpdServer) handleWebAdminSetupGet(w http.ResponseWriter, r *http.Request) {
  2180. r.Body = http.MaxBytesReader(w, r.Body, maxLoginBodySize)
  2181. if dataprovider.HasAdmin() {
  2182. http.Redirect(w, r, webAdminLoginPath, http.StatusFound)
  2183. return
  2184. }
  2185. s.renderAdminSetupPage(w, r, "", "")
  2186. }
  2187. func (s *httpdServer) handleWebAddAdminGet(w http.ResponseWriter, r *http.Request) {
  2188. r.Body = http.MaxBytesReader(w, r.Body, maxRequestSize)
  2189. admin := &dataprovider.Admin{
  2190. Status: 1,
  2191. Permissions: []string{dataprovider.PermAdminAny},
  2192. }
  2193. s.renderAddUpdateAdminPage(w, r, admin, "", true)
  2194. }
  2195. func (s *httpdServer) handleWebUpdateAdminGet(w http.ResponseWriter, r *http.Request) {
  2196. r.Body = http.MaxBytesReader(w, r.Body, maxRequestSize)
  2197. username := getURLParam(r, "username")
  2198. admin, err := dataprovider.AdminExists(username)
  2199. if err == nil {
  2200. s.renderAddUpdateAdminPage(w, r, &admin, "", false)
  2201. } else if _, ok := err.(*util.RecordNotFoundError); ok {
  2202. s.renderNotFoundPage(w, r, err)
  2203. } else {
  2204. s.renderInternalServerErrorPage(w, r, err)
  2205. }
  2206. }
  2207. func (s *httpdServer) handleWebAddAdminPost(w http.ResponseWriter, r *http.Request) {
  2208. r.Body = http.MaxBytesReader(w, r.Body, maxRequestSize)
  2209. claims, err := getTokenClaims(r)
  2210. if err != nil || claims.Username == "" {
  2211. s.renderBadRequestPage(w, r, errors.New("invalid token claims"))
  2212. return
  2213. }
  2214. admin, err := getAdminFromPostFields(r)
  2215. if err != nil {
  2216. s.renderAddUpdateAdminPage(w, r, &admin, err.Error(), true)
  2217. return
  2218. }
  2219. if admin.Password == "" && s.binding.isWebAdminLoginFormDisabled() {
  2220. admin.Password = util.GenerateUniqueID()
  2221. }
  2222. ipAddr := util.GetIPFromRemoteAddress(r.RemoteAddr)
  2223. if err := verifyCSRFToken(r.Form.Get(csrfFormToken), ipAddr); err != nil {
  2224. s.renderForbiddenPage(w, r, err.Error())
  2225. return
  2226. }
  2227. err = dataprovider.AddAdmin(&admin, claims.Username, ipAddr)
  2228. if err != nil {
  2229. s.renderAddUpdateAdminPage(w, r, &admin, err.Error(), true)
  2230. return
  2231. }
  2232. http.Redirect(w, r, webAdminsPath, http.StatusSeeOther)
  2233. }
  2234. func (s *httpdServer) handleWebUpdateAdminPost(w http.ResponseWriter, r *http.Request) {
  2235. r.Body = http.MaxBytesReader(w, r.Body, maxRequestSize)
  2236. username := getURLParam(r, "username")
  2237. admin, err := dataprovider.AdminExists(username)
  2238. if _, ok := err.(*util.RecordNotFoundError); ok {
  2239. s.renderNotFoundPage(w, r, err)
  2240. return
  2241. } else if err != nil {
  2242. s.renderInternalServerErrorPage(w, r, err)
  2243. return
  2244. }
  2245. updatedAdmin, err := getAdminFromPostFields(r)
  2246. if err != nil {
  2247. s.renderAddUpdateAdminPage(w, r, &updatedAdmin, err.Error(), false)
  2248. return
  2249. }
  2250. ipAddr := util.GetIPFromRemoteAddress(r.RemoteAddr)
  2251. if err := verifyCSRFToken(r.Form.Get(csrfFormToken), ipAddr); err != nil {
  2252. s.renderForbiddenPage(w, r, err.Error())
  2253. return
  2254. }
  2255. updatedAdmin.ID = admin.ID
  2256. updatedAdmin.Username = admin.Username
  2257. if updatedAdmin.Password == "" {
  2258. updatedAdmin.Password = admin.Password
  2259. }
  2260. updatedAdmin.Filters.TOTPConfig = admin.Filters.TOTPConfig
  2261. updatedAdmin.Filters.RecoveryCodes = admin.Filters.RecoveryCodes
  2262. claims, err := getTokenClaims(r)
  2263. if err != nil || claims.Username == "" {
  2264. s.renderAddUpdateAdminPage(w, r, &updatedAdmin, "Invalid token claims", false)
  2265. return
  2266. }
  2267. if username == claims.Username {
  2268. if claims.isCriticalPermRemoved(updatedAdmin.Permissions) {
  2269. s.renderAddUpdateAdminPage(w, r, &updatedAdmin, "You cannot remove these permissions to yourself", false)
  2270. return
  2271. }
  2272. if updatedAdmin.Status == 0 {
  2273. s.renderAddUpdateAdminPage(w, r, &updatedAdmin, "You cannot disable yourself", false)
  2274. return
  2275. }
  2276. }
  2277. err = dataprovider.UpdateAdmin(&updatedAdmin, claims.Username, ipAddr)
  2278. if err != nil {
  2279. s.renderAddUpdateAdminPage(w, r, &admin, err.Error(), false)
  2280. return
  2281. }
  2282. http.Redirect(w, r, webAdminsPath, http.StatusSeeOther)
  2283. }
  2284. func (s *httpdServer) handleWebDefenderPage(w http.ResponseWriter, r *http.Request) {
  2285. r.Body = http.MaxBytesReader(w, r.Body, maxRequestSize)
  2286. data := defenderHostsPage{
  2287. basePage: s.getBasePageData(pageDefenderTitle, webDefenderPath, r),
  2288. DefenderHostsURL: webDefenderHostsPath,
  2289. }
  2290. renderAdminTemplate(w, templateDefender, data)
  2291. }
  2292. func (s *httpdServer) handleGetWebUsers(w http.ResponseWriter, r *http.Request) {
  2293. r.Body = http.MaxBytesReader(w, r.Body, maxRequestSize)
  2294. var limit int
  2295. if _, ok := r.URL.Query()["qlimit"]; ok {
  2296. var err error
  2297. limit, err = strconv.Atoi(r.URL.Query().Get("qlimit"))
  2298. if err != nil {
  2299. limit = defaultQueryLimit
  2300. }
  2301. } else {
  2302. limit = defaultQueryLimit
  2303. }
  2304. users := make([]dataprovider.User, 0, limit)
  2305. for {
  2306. u, err := dataprovider.GetUsers(limit, len(users), dataprovider.OrderASC)
  2307. if err != nil {
  2308. s.renderInternalServerErrorPage(w, r, err)
  2309. return
  2310. }
  2311. users = append(users, u...)
  2312. if len(u) < limit {
  2313. break
  2314. }
  2315. }
  2316. data := usersPage{
  2317. basePage: s.getBasePageData(pageUsersTitle, webUsersPath, r),
  2318. Users: users,
  2319. }
  2320. renderAdminTemplate(w, templateUsers, data)
  2321. }
  2322. func (s *httpdServer) handleWebTemplateFolderGet(w http.ResponseWriter, r *http.Request) {
  2323. r.Body = http.MaxBytesReader(w, r.Body, maxRequestSize)
  2324. if r.URL.Query().Get("from") != "" {
  2325. name := r.URL.Query().Get("from")
  2326. folder, err := dataprovider.GetFolderByName(name)
  2327. if err == nil {
  2328. folder.FsConfig.SetEmptySecrets()
  2329. s.renderFolderPage(w, r, folder, folderPageModeTemplate, "")
  2330. } else if _, ok := err.(*util.RecordNotFoundError); ok {
  2331. s.renderNotFoundPage(w, r, err)
  2332. } else {
  2333. s.renderInternalServerErrorPage(w, r, err)
  2334. }
  2335. } else {
  2336. folder := vfs.BaseVirtualFolder{}
  2337. s.renderFolderPage(w, r, folder, folderPageModeTemplate, "")
  2338. }
  2339. }
  2340. func (s *httpdServer) handleWebTemplateFolderPost(w http.ResponseWriter, r *http.Request) {
  2341. r.Body = http.MaxBytesReader(w, r.Body, maxRequestSize)
  2342. claims, err := getTokenClaims(r)
  2343. if err != nil || claims.Username == "" {
  2344. s.renderBadRequestPage(w, r, errors.New("invalid token claims"))
  2345. return
  2346. }
  2347. templateFolder := vfs.BaseVirtualFolder{}
  2348. err = r.ParseMultipartForm(maxRequestSize)
  2349. if err != nil {
  2350. s.renderMessagePage(w, r, "Error parsing folders fields", "", http.StatusBadRequest, err, "")
  2351. return
  2352. }
  2353. defer r.MultipartForm.RemoveAll() //nolint:errcheck
  2354. ipAddr := util.GetIPFromRemoteAddress(r.RemoteAddr)
  2355. if err := verifyCSRFToken(r.Form.Get(csrfFormToken), ipAddr); err != nil {
  2356. s.renderForbiddenPage(w, r, err.Error())
  2357. return
  2358. }
  2359. templateFolder.MappedPath = r.Form.Get("mapped_path")
  2360. templateFolder.Description = r.Form.Get("description")
  2361. fsConfig, err := getFsConfigFromPostFields(r)
  2362. if err != nil {
  2363. s.renderMessagePage(w, r, "Error parsing folders fields", "", http.StatusBadRequest, err, "")
  2364. return
  2365. }
  2366. templateFolder.FsConfig = fsConfig
  2367. var dump dataprovider.BackupData
  2368. dump.Version = dataprovider.DumpVersion
  2369. foldersFields := getFoldersForTemplate(r)
  2370. for _, tmpl := range foldersFields {
  2371. f := getFolderFromTemplate(templateFolder, tmpl)
  2372. if err := dataprovider.ValidateFolder(&f); err != nil {
  2373. s.renderMessagePage(w, r, "Folder validation error", fmt.Sprintf("Error validating folder %#v", f.Name),
  2374. http.StatusBadRequest, err, "")
  2375. return
  2376. }
  2377. dump.Folders = append(dump.Folders, f)
  2378. }
  2379. if len(dump.Folders) == 0 {
  2380. s.renderMessagePage(w, r, "No folders defined", "No valid folders defined, unable to complete the requested action",
  2381. http.StatusBadRequest, nil, "")
  2382. return
  2383. }
  2384. if r.Form.Get("form_action") == "export_from_template" {
  2385. w.Header().Set("Content-Disposition", fmt.Sprintf("attachment; filename=\"sftpgo-%v-folders-from-template.json\"",
  2386. len(dump.Folders)))
  2387. render.JSON(w, r, dump)
  2388. return
  2389. }
  2390. if err = RestoreFolders(dump.Folders, "", 1, 0, claims.Username, ipAddr); err != nil {
  2391. s.renderMessagePage(w, r, "Unable to save folders", "Cannot save the defined folders:",
  2392. getRespStatus(err), err, "")
  2393. return
  2394. }
  2395. http.Redirect(w, r, webFoldersPath, http.StatusSeeOther)
  2396. }
  2397. func (s *httpdServer) handleWebTemplateUserGet(w http.ResponseWriter, r *http.Request) {
  2398. r.Body = http.MaxBytesReader(w, r.Body, maxRequestSize)
  2399. if r.URL.Query().Get("from") != "" {
  2400. username := r.URL.Query().Get("from")
  2401. user, err := dataprovider.UserExists(username)
  2402. if err == nil {
  2403. user.SetEmptySecrets()
  2404. user.PublicKeys = nil
  2405. user.Email = ""
  2406. user.Description = ""
  2407. s.renderUserPage(w, r, &user, userPageModeTemplate, "")
  2408. } else if _, ok := err.(*util.RecordNotFoundError); ok {
  2409. s.renderNotFoundPage(w, r, err)
  2410. } else {
  2411. s.renderInternalServerErrorPage(w, r, err)
  2412. }
  2413. } else {
  2414. user := dataprovider.User{BaseUser: sdk.BaseUser{
  2415. Status: 1,
  2416. Permissions: map[string][]string{
  2417. "/": {dataprovider.PermAny},
  2418. },
  2419. }}
  2420. s.renderUserPage(w, r, &user, userPageModeTemplate, "")
  2421. }
  2422. }
  2423. func (s *httpdServer) handleWebTemplateUserPost(w http.ResponseWriter, r *http.Request) {
  2424. r.Body = http.MaxBytesReader(w, r.Body, maxRequestSize)
  2425. claims, err := getTokenClaims(r)
  2426. if err != nil || claims.Username == "" {
  2427. s.renderBadRequestPage(w, r, errors.New("invalid token claims"))
  2428. return
  2429. }
  2430. templateUser, err := getUserFromPostFields(r)
  2431. if err != nil {
  2432. s.renderMessagePage(w, r, "Error parsing user fields", "", http.StatusBadRequest, err, "")
  2433. return
  2434. }
  2435. ipAddr := util.GetIPFromRemoteAddress(r.RemoteAddr)
  2436. if err := verifyCSRFToken(r.Form.Get(csrfFormToken), ipAddr); err != nil {
  2437. s.renderForbiddenPage(w, r, err.Error())
  2438. return
  2439. }
  2440. var dump dataprovider.BackupData
  2441. dump.Version = dataprovider.DumpVersion
  2442. userTmplFields := getUsersForTemplate(r)
  2443. for _, tmpl := range userTmplFields {
  2444. u := getUserFromTemplate(templateUser, tmpl)
  2445. if err := dataprovider.ValidateUser(&u); err != nil {
  2446. s.renderMessagePage(w, r, "User validation error", fmt.Sprintf("Error validating user %#v", u.Username),
  2447. http.StatusBadRequest, err, "")
  2448. return
  2449. }
  2450. dump.Users = append(dump.Users, u)
  2451. for _, folder := range u.VirtualFolders {
  2452. if !dump.HasFolder(folder.Name) {
  2453. dump.Folders = append(dump.Folders, folder.BaseVirtualFolder)
  2454. }
  2455. }
  2456. }
  2457. if len(dump.Users) == 0 {
  2458. s.renderMessagePage(w, r, "No users defined", "No valid users defined, unable to complete the requested action",
  2459. http.StatusBadRequest, nil, "")
  2460. return
  2461. }
  2462. if r.Form.Get("form_action") == "export_from_template" {
  2463. w.Header().Set("Content-Disposition", fmt.Sprintf("attachment; filename=\"sftpgo-%v-users-from-template.json\"",
  2464. len(dump.Users)))
  2465. render.JSON(w, r, dump)
  2466. return
  2467. }
  2468. if err = RestoreUsers(dump.Users, "", 1, 0, claims.Username, ipAddr); err != nil {
  2469. s.renderMessagePage(w, r, "Unable to save users", "Cannot save the defined users:",
  2470. getRespStatus(err), err, "")
  2471. return
  2472. }
  2473. http.Redirect(w, r, webUsersPath, http.StatusSeeOther)
  2474. }
  2475. func (s *httpdServer) handleWebAddUserGet(w http.ResponseWriter, r *http.Request) {
  2476. r.Body = http.MaxBytesReader(w, r.Body, maxRequestSize)
  2477. user := dataprovider.User{BaseUser: sdk.BaseUser{
  2478. Status: 1,
  2479. Permissions: map[string][]string{
  2480. "/": {dataprovider.PermAny},
  2481. }},
  2482. }
  2483. s.renderUserPage(w, r, &user, userPageModeAdd, "")
  2484. }
  2485. func (s *httpdServer) handleWebUpdateUserGet(w http.ResponseWriter, r *http.Request) {
  2486. r.Body = http.MaxBytesReader(w, r.Body, maxRequestSize)
  2487. username := getURLParam(r, "username")
  2488. user, err := dataprovider.UserExists(username)
  2489. if err == nil {
  2490. s.renderUserPage(w, r, &user, userPageModeUpdate, "")
  2491. } else if _, ok := err.(*util.RecordNotFoundError); ok {
  2492. s.renderNotFoundPage(w, r, err)
  2493. } else {
  2494. s.renderInternalServerErrorPage(w, r, err)
  2495. }
  2496. }
  2497. func (s *httpdServer) handleWebAddUserPost(w http.ResponseWriter, r *http.Request) {
  2498. r.Body = http.MaxBytesReader(w, r.Body, maxRequestSize)
  2499. claims, err := getTokenClaims(r)
  2500. if err != nil || claims.Username == "" {
  2501. s.renderBadRequestPage(w, r, errors.New("invalid token claims"))
  2502. return
  2503. }
  2504. user, err := getUserFromPostFields(r)
  2505. if err != nil {
  2506. s.renderUserPage(w, r, &user, userPageModeAdd, err.Error())
  2507. return
  2508. }
  2509. ipAddr := util.GetIPFromRemoteAddress(r.RemoteAddr)
  2510. if err := verifyCSRFToken(r.Form.Get(csrfFormToken), ipAddr); err != nil {
  2511. s.renderForbiddenPage(w, r, err.Error())
  2512. return
  2513. }
  2514. user = getUserFromTemplate(user, userTemplateFields{
  2515. Username: user.Username,
  2516. Password: user.Password,
  2517. PublicKeys: user.PublicKeys,
  2518. })
  2519. err = dataprovider.AddUser(&user, claims.Username, ipAddr)
  2520. if err != nil {
  2521. s.renderUserPage(w, r, &user, userPageModeAdd, err.Error())
  2522. return
  2523. }
  2524. http.Redirect(w, r, webUsersPath, http.StatusSeeOther)
  2525. }
  2526. func (s *httpdServer) handleWebUpdateUserPost(w http.ResponseWriter, r *http.Request) {
  2527. r.Body = http.MaxBytesReader(w, r.Body, maxRequestSize)
  2528. claims, err := getTokenClaims(r)
  2529. if err != nil || claims.Username == "" {
  2530. s.renderBadRequestPage(w, r, errors.New("invalid token claims"))
  2531. return
  2532. }
  2533. username := getURLParam(r, "username")
  2534. user, err := dataprovider.UserExists(username)
  2535. if _, ok := err.(*util.RecordNotFoundError); ok {
  2536. s.renderNotFoundPage(w, r, err)
  2537. return
  2538. } else if err != nil {
  2539. s.renderInternalServerErrorPage(w, r, err)
  2540. return
  2541. }
  2542. updatedUser, err := getUserFromPostFields(r)
  2543. if err != nil {
  2544. s.renderUserPage(w, r, &user, userPageModeUpdate, err.Error())
  2545. return
  2546. }
  2547. ipAddr := util.GetIPFromRemoteAddress(r.RemoteAddr)
  2548. if err := verifyCSRFToken(r.Form.Get(csrfFormToken), ipAddr); err != nil {
  2549. s.renderForbiddenPage(w, r, err.Error())
  2550. return
  2551. }
  2552. updatedUser.ID = user.ID
  2553. updatedUser.Username = user.Username
  2554. updatedUser.Filters.RecoveryCodes = user.Filters.RecoveryCodes
  2555. updatedUser.Filters.TOTPConfig = user.Filters.TOTPConfig
  2556. updatedUser.SetEmptySecretsIfNil()
  2557. if updatedUser.Password == redactedSecret {
  2558. updatedUser.Password = user.Password
  2559. }
  2560. updateEncryptedSecrets(&updatedUser.FsConfig, user.FsConfig.S3Config.AccessSecret, user.FsConfig.AzBlobConfig.AccountKey,
  2561. user.FsConfig.AzBlobConfig.SASURL, user.FsConfig.GCSConfig.Credentials, user.FsConfig.CryptConfig.Passphrase,
  2562. user.FsConfig.SFTPConfig.Password, user.FsConfig.SFTPConfig.PrivateKey, user.FsConfig.SFTPConfig.KeyPassphrase,
  2563. user.FsConfig.HTTPConfig.Password, user.FsConfig.HTTPConfig.APIKey)
  2564. updatedUser = getUserFromTemplate(updatedUser, userTemplateFields{
  2565. Username: updatedUser.Username,
  2566. Password: updatedUser.Password,
  2567. PublicKeys: updatedUser.PublicKeys,
  2568. })
  2569. err = dataprovider.UpdateUser(&updatedUser, claims.Username, ipAddr)
  2570. if err != nil {
  2571. s.renderUserPage(w, r, &updatedUser, userPageModeUpdate, err.Error())
  2572. return
  2573. }
  2574. if r.Form.Get("disconnect") != "" {
  2575. disconnectUser(user.Username)
  2576. }
  2577. http.Redirect(w, r, webUsersPath, http.StatusSeeOther)
  2578. }
  2579. func (s *httpdServer) handleWebGetStatus(w http.ResponseWriter, r *http.Request) {
  2580. r.Body = http.MaxBytesReader(w, r.Body, maxRequestSize)
  2581. data := statusPage{
  2582. basePage: s.getBasePageData(pageStatusTitle, webStatusPath, r),
  2583. Status: getServicesStatus(),
  2584. }
  2585. renderAdminTemplate(w, templateStatus, data)
  2586. }
  2587. func (s *httpdServer) handleWebGetConnections(w http.ResponseWriter, r *http.Request) {
  2588. r.Body = http.MaxBytesReader(w, r.Body, maxRequestSize)
  2589. connectionStats := common.Connections.GetStats()
  2590. data := connectionsPage{
  2591. basePage: s.getBasePageData(pageConnectionsTitle, webConnectionsPath, r),
  2592. Connections: connectionStats,
  2593. }
  2594. renderAdminTemplate(w, templateConnections, data)
  2595. }
  2596. func (s *httpdServer) handleWebAddFolderGet(w http.ResponseWriter, r *http.Request) {
  2597. r.Body = http.MaxBytesReader(w, r.Body, maxRequestSize)
  2598. s.renderFolderPage(w, r, vfs.BaseVirtualFolder{}, folderPageModeAdd, "")
  2599. }
  2600. func (s *httpdServer) handleWebAddFolderPost(w http.ResponseWriter, r *http.Request) {
  2601. r.Body = http.MaxBytesReader(w, r.Body, maxRequestSize)
  2602. claims, err := getTokenClaims(r)
  2603. if err != nil || claims.Username == "" {
  2604. s.renderBadRequestPage(w, r, errors.New("invalid token claims"))
  2605. return
  2606. }
  2607. folder := vfs.BaseVirtualFolder{}
  2608. err = r.ParseMultipartForm(maxRequestSize)
  2609. if err != nil {
  2610. s.renderFolderPage(w, r, folder, folderPageModeAdd, err.Error())
  2611. return
  2612. }
  2613. defer r.MultipartForm.RemoveAll() //nolint:errcheck
  2614. ipAddr := util.GetIPFromRemoteAddress(r.RemoteAddr)
  2615. if err := verifyCSRFToken(r.Form.Get(csrfFormToken), ipAddr); err != nil {
  2616. s.renderForbiddenPage(w, r, err.Error())
  2617. return
  2618. }
  2619. folder.MappedPath = r.Form.Get("mapped_path")
  2620. folder.Name = r.Form.Get("name")
  2621. folder.Description = r.Form.Get("description")
  2622. fsConfig, err := getFsConfigFromPostFields(r)
  2623. if err != nil {
  2624. s.renderFolderPage(w, r, folder, folderPageModeAdd, err.Error())
  2625. return
  2626. }
  2627. folder.FsConfig = fsConfig
  2628. folder = getFolderFromTemplate(folder, folder.Name)
  2629. err = dataprovider.AddFolder(&folder, claims.Username, ipAddr)
  2630. if err == nil {
  2631. http.Redirect(w, r, webFoldersPath, http.StatusSeeOther)
  2632. } else {
  2633. s.renderFolderPage(w, r, folder, folderPageModeAdd, err.Error())
  2634. }
  2635. }
  2636. func (s *httpdServer) handleWebUpdateFolderGet(w http.ResponseWriter, r *http.Request) {
  2637. r.Body = http.MaxBytesReader(w, r.Body, maxRequestSize)
  2638. name := getURLParam(r, "name")
  2639. folder, err := dataprovider.GetFolderByName(name)
  2640. if err == nil {
  2641. s.renderFolderPage(w, r, folder, folderPageModeUpdate, "")
  2642. } else if _, ok := err.(*util.RecordNotFoundError); ok {
  2643. s.renderNotFoundPage(w, r, err)
  2644. } else {
  2645. s.renderInternalServerErrorPage(w, r, err)
  2646. }
  2647. }
  2648. func (s *httpdServer) handleWebUpdateFolderPost(w http.ResponseWriter, r *http.Request) {
  2649. r.Body = http.MaxBytesReader(w, r.Body, maxRequestSize)
  2650. claims, err := getTokenClaims(r)
  2651. if err != nil || claims.Username == "" {
  2652. s.renderBadRequestPage(w, r, errors.New("invalid token claims"))
  2653. return
  2654. }
  2655. name := getURLParam(r, "name")
  2656. folder, err := dataprovider.GetFolderByName(name)
  2657. if _, ok := err.(*util.RecordNotFoundError); ok {
  2658. s.renderNotFoundPage(w, r, err)
  2659. return
  2660. } else if err != nil {
  2661. s.renderInternalServerErrorPage(w, r, err)
  2662. return
  2663. }
  2664. err = r.ParseMultipartForm(maxRequestSize)
  2665. if err != nil {
  2666. s.renderFolderPage(w, r, folder, folderPageModeUpdate, err.Error())
  2667. return
  2668. }
  2669. defer r.MultipartForm.RemoveAll() //nolint:errcheck
  2670. ipAddr := util.GetIPFromRemoteAddress(r.RemoteAddr)
  2671. if err := verifyCSRFToken(r.Form.Get(csrfFormToken), ipAddr); err != nil {
  2672. s.renderForbiddenPage(w, r, err.Error())
  2673. return
  2674. }
  2675. fsConfig, err := getFsConfigFromPostFields(r)
  2676. if err != nil {
  2677. s.renderFolderPage(w, r, folder, folderPageModeUpdate, err.Error())
  2678. return
  2679. }
  2680. updatedFolder := vfs.BaseVirtualFolder{
  2681. MappedPath: r.Form.Get("mapped_path"),
  2682. Description: r.Form.Get("description"),
  2683. }
  2684. updatedFolder.ID = folder.ID
  2685. updatedFolder.Name = folder.Name
  2686. updatedFolder.FsConfig = fsConfig
  2687. updatedFolder.FsConfig.SetEmptySecretsIfNil()
  2688. updateEncryptedSecrets(&updatedFolder.FsConfig, folder.FsConfig.S3Config.AccessSecret, folder.FsConfig.AzBlobConfig.AccountKey,
  2689. folder.FsConfig.AzBlobConfig.SASURL, folder.FsConfig.GCSConfig.Credentials, folder.FsConfig.CryptConfig.Passphrase,
  2690. folder.FsConfig.SFTPConfig.Password, folder.FsConfig.SFTPConfig.PrivateKey, folder.FsConfig.SFTPConfig.KeyPassphrase,
  2691. folder.FsConfig.HTTPConfig.Password, folder.FsConfig.HTTPConfig.APIKey)
  2692. updatedFolder = getFolderFromTemplate(updatedFolder, updatedFolder.Name)
  2693. err = dataprovider.UpdateFolder(&updatedFolder, folder.Users, folder.Groups, claims.Username, ipAddr)
  2694. if err != nil {
  2695. s.renderFolderPage(w, r, updatedFolder, folderPageModeUpdate, err.Error())
  2696. return
  2697. }
  2698. http.Redirect(w, r, webFoldersPath, http.StatusSeeOther)
  2699. }
  2700. func (s *httpdServer) getWebVirtualFolders(w http.ResponseWriter, r *http.Request, limit int, minimal bool) ([]vfs.BaseVirtualFolder, error) {
  2701. folders := make([]vfs.BaseVirtualFolder, 0, limit)
  2702. for {
  2703. f, err := dataprovider.GetFolders(limit, len(folders), dataprovider.OrderASC, minimal)
  2704. if err != nil {
  2705. s.renderInternalServerErrorPage(w, r, err)
  2706. return folders, err
  2707. }
  2708. folders = append(folders, f...)
  2709. if len(f) < limit {
  2710. break
  2711. }
  2712. }
  2713. return folders, nil
  2714. }
  2715. func (s *httpdServer) handleWebGetFolders(w http.ResponseWriter, r *http.Request) {
  2716. r.Body = http.MaxBytesReader(w, r.Body, maxRequestSize)
  2717. limit := defaultQueryLimit
  2718. if _, ok := r.URL.Query()["qlimit"]; ok {
  2719. var err error
  2720. limit, err = strconv.Atoi(r.URL.Query().Get("qlimit"))
  2721. if err != nil {
  2722. limit = defaultQueryLimit
  2723. }
  2724. }
  2725. folders, err := s.getWebVirtualFolders(w, r, limit, false)
  2726. if err != nil {
  2727. return
  2728. }
  2729. data := foldersPage{
  2730. basePage: s.getBasePageData(pageFoldersTitle, webFoldersPath, r),
  2731. Folders: folders,
  2732. }
  2733. renderAdminTemplate(w, templateFolders, data)
  2734. }
  2735. func (s *httpdServer) getWebGroups(w http.ResponseWriter, r *http.Request, limit int, minimal bool) ([]dataprovider.Group, error) {
  2736. groups := make([]dataprovider.Group, 0, limit)
  2737. for {
  2738. f, err := dataprovider.GetGroups(limit, len(groups), dataprovider.OrderASC, minimal)
  2739. if err != nil {
  2740. s.renderInternalServerErrorPage(w, r, err)
  2741. return groups, err
  2742. }
  2743. groups = append(groups, f...)
  2744. if len(f) < limit {
  2745. break
  2746. }
  2747. }
  2748. return groups, nil
  2749. }
  2750. func (s *httpdServer) handleWebGetGroups(w http.ResponseWriter, r *http.Request) {
  2751. r.Body = http.MaxBytesReader(w, r.Body, maxRequestSize)
  2752. limit := defaultQueryLimit
  2753. if _, ok := r.URL.Query()["qlimit"]; ok {
  2754. var err error
  2755. limit, err = strconv.Atoi(r.URL.Query().Get("qlimit"))
  2756. if err != nil {
  2757. limit = defaultQueryLimit
  2758. }
  2759. }
  2760. groups, err := s.getWebGroups(w, r, limit, false)
  2761. if err != nil {
  2762. return
  2763. }
  2764. data := groupsPage{
  2765. basePage: s.getBasePageData(pageGroupsTitle, webGroupsPath, r),
  2766. Groups: groups,
  2767. }
  2768. renderAdminTemplate(w, templateGroups, data)
  2769. }
  2770. func (s *httpdServer) handleWebAddGroupGet(w http.ResponseWriter, r *http.Request) {
  2771. r.Body = http.MaxBytesReader(w, r.Body, maxRequestSize)
  2772. s.renderGroupPage(w, r, dataprovider.Group{}, genericPageModeAdd, "")
  2773. }
  2774. func (s *httpdServer) handleWebAddGroupPost(w http.ResponseWriter, r *http.Request) {
  2775. r.Body = http.MaxBytesReader(w, r.Body, maxRequestSize)
  2776. claims, err := getTokenClaims(r)
  2777. if err != nil || claims.Username == "" {
  2778. s.renderBadRequestPage(w, r, errors.New("invalid token claims"))
  2779. return
  2780. }
  2781. group, err := getGroupFromPostFields(r)
  2782. if err != nil {
  2783. s.renderGroupPage(w, r, group, genericPageModeAdd, err.Error())
  2784. return
  2785. }
  2786. ipAddr := util.GetIPFromRemoteAddress(r.RemoteAddr)
  2787. if err := verifyCSRFToken(r.Form.Get(csrfFormToken), ipAddr); err != nil {
  2788. s.renderForbiddenPage(w, r, err.Error())
  2789. return
  2790. }
  2791. err = dataprovider.AddGroup(&group, claims.Username, ipAddr)
  2792. if err != nil {
  2793. s.renderGroupPage(w, r, group, genericPageModeAdd, err.Error())
  2794. return
  2795. }
  2796. http.Redirect(w, r, webGroupsPath, http.StatusSeeOther)
  2797. }
  2798. func (s *httpdServer) handleWebUpdateGroupGet(w http.ResponseWriter, r *http.Request) {
  2799. r.Body = http.MaxBytesReader(w, r.Body, maxRequestSize)
  2800. name := getURLParam(r, "name")
  2801. group, err := dataprovider.GroupExists(name)
  2802. if err == nil {
  2803. s.renderGroupPage(w, r, group, genericPageModeUpdate, "")
  2804. } else if _, ok := err.(*util.RecordNotFoundError); ok {
  2805. s.renderNotFoundPage(w, r, err)
  2806. } else {
  2807. s.renderInternalServerErrorPage(w, r, err)
  2808. }
  2809. }
  2810. func (s *httpdServer) handleWebUpdateGroupPost(w http.ResponseWriter, r *http.Request) {
  2811. r.Body = http.MaxBytesReader(w, r.Body, maxRequestSize)
  2812. claims, err := getTokenClaims(r)
  2813. if err != nil || claims.Username == "" {
  2814. s.renderBadRequestPage(w, r, errors.New("invalid token claims"))
  2815. return
  2816. }
  2817. name := getURLParam(r, "name")
  2818. group, err := dataprovider.GroupExists(name)
  2819. if _, ok := err.(*util.RecordNotFoundError); ok {
  2820. s.renderNotFoundPage(w, r, err)
  2821. return
  2822. } else if err != nil {
  2823. s.renderInternalServerErrorPage(w, r, err)
  2824. return
  2825. }
  2826. updatedGroup, err := getGroupFromPostFields(r)
  2827. if err != nil {
  2828. s.renderGroupPage(w, r, group, genericPageModeUpdate, err.Error())
  2829. return
  2830. }
  2831. ipAddr := util.GetIPFromRemoteAddress(r.RemoteAddr)
  2832. if err := verifyCSRFToken(r.Form.Get(csrfFormToken), ipAddr); err != nil {
  2833. s.renderForbiddenPage(w, r, err.Error())
  2834. return
  2835. }
  2836. updatedGroup.ID = group.ID
  2837. updatedGroup.Name = group.Name
  2838. updatedGroup.SetEmptySecretsIfNil()
  2839. updateEncryptedSecrets(&updatedGroup.UserSettings.FsConfig, group.UserSettings.FsConfig.S3Config.AccessSecret,
  2840. group.UserSettings.FsConfig.AzBlobConfig.AccountKey, group.UserSettings.FsConfig.AzBlobConfig.SASURL,
  2841. group.UserSettings.FsConfig.GCSConfig.Credentials, group.UserSettings.FsConfig.CryptConfig.Passphrase,
  2842. group.UserSettings.FsConfig.SFTPConfig.Password, group.UserSettings.FsConfig.SFTPConfig.PrivateKey,
  2843. group.UserSettings.FsConfig.SFTPConfig.KeyPassphrase, group.UserSettings.FsConfig.HTTPConfig.Password,
  2844. group.UserSettings.FsConfig.HTTPConfig.APIKey)
  2845. err = dataprovider.UpdateGroup(&updatedGroup, group.Users, claims.Username, ipAddr)
  2846. if err != nil {
  2847. s.renderGroupPage(w, r, updatedGroup, genericPageModeUpdate, err.Error())
  2848. return
  2849. }
  2850. http.Redirect(w, r, webGroupsPath, http.StatusSeeOther)
  2851. }
  2852. func (s *httpdServer) getWebEventActions(w http.ResponseWriter, r *http.Request, limit int, minimal bool,
  2853. ) ([]dataprovider.BaseEventAction, error) {
  2854. actions := make([]dataprovider.BaseEventAction, 0, limit)
  2855. for {
  2856. res, err := dataprovider.GetEventActions(limit, len(actions), dataprovider.OrderASC, minimal)
  2857. if err != nil {
  2858. s.renderInternalServerErrorPage(w, r, err)
  2859. return actions, err
  2860. }
  2861. actions = append(actions, res...)
  2862. if len(res) < limit {
  2863. break
  2864. }
  2865. }
  2866. return actions, nil
  2867. }
  2868. func (s *httpdServer) handleWebGetEventActions(w http.ResponseWriter, r *http.Request) {
  2869. r.Body = http.MaxBytesReader(w, r.Body, maxRequestSize)
  2870. limit := defaultQueryLimit
  2871. if _, ok := r.URL.Query()["qlimit"]; ok {
  2872. var err error
  2873. limit, err = strconv.Atoi(r.URL.Query().Get("qlimit"))
  2874. if err != nil {
  2875. limit = defaultQueryLimit
  2876. }
  2877. }
  2878. actions, err := s.getWebEventActions(w, r, limit, false)
  2879. if err != nil {
  2880. return
  2881. }
  2882. data := eventActionsPage{
  2883. basePage: s.getBasePageData(pageEventActionsTitle, webAdminEventActionsPath, r),
  2884. Actions: actions,
  2885. }
  2886. renderAdminTemplate(w, templateEventActions, data)
  2887. }
  2888. func (s *httpdServer) handleWebAddEventActionGet(w http.ResponseWriter, r *http.Request) {
  2889. r.Body = http.MaxBytesReader(w, r.Body, maxRequestSize)
  2890. action := dataprovider.BaseEventAction{
  2891. Type: dataprovider.ActionTypeHTTP,
  2892. }
  2893. s.renderEventActionPage(w, r, action, genericPageModeAdd, "")
  2894. }
  2895. func (s *httpdServer) handleWebAddEventActionPost(w http.ResponseWriter, r *http.Request) {
  2896. r.Body = http.MaxBytesReader(w, r.Body, maxRequestSize)
  2897. claims, err := getTokenClaims(r)
  2898. if err != nil || claims.Username == "" {
  2899. s.renderBadRequestPage(w, r, errors.New("invalid token claims"))
  2900. return
  2901. }
  2902. action, err := getEventActionFromPostFields(r)
  2903. if err != nil {
  2904. s.renderEventActionPage(w, r, action, genericPageModeAdd, err.Error())
  2905. return
  2906. }
  2907. ipAddr := util.GetIPFromRemoteAddress(r.RemoteAddr)
  2908. if err := verifyCSRFToken(r.Form.Get(csrfFormToken), ipAddr); err != nil {
  2909. s.renderForbiddenPage(w, r, err.Error())
  2910. return
  2911. }
  2912. if err = dataprovider.AddEventAction(&action, claims.Username, ipAddr); err != nil {
  2913. s.renderEventActionPage(w, r, action, genericPageModeAdd, err.Error())
  2914. return
  2915. }
  2916. http.Redirect(w, r, webAdminEventActionsPath, http.StatusSeeOther)
  2917. }
  2918. func (s *httpdServer) handleWebUpdateEventActionGet(w http.ResponseWriter, r *http.Request) {
  2919. r.Body = http.MaxBytesReader(w, r.Body, maxRequestSize)
  2920. name := getURLParam(r, "name")
  2921. action, err := dataprovider.EventActionExists(name)
  2922. if err == nil {
  2923. s.renderEventActionPage(w, r, action, genericPageModeUpdate, "")
  2924. } else if _, ok := err.(*util.RecordNotFoundError); ok {
  2925. s.renderNotFoundPage(w, r, err)
  2926. } else {
  2927. s.renderInternalServerErrorPage(w, r, err)
  2928. }
  2929. }
  2930. func (s *httpdServer) handleWebUpdateEventActionPost(w http.ResponseWriter, r *http.Request) {
  2931. r.Body = http.MaxBytesReader(w, r.Body, maxRequestSize)
  2932. claims, err := getTokenClaims(r)
  2933. if err != nil || claims.Username == "" {
  2934. s.renderBadRequestPage(w, r, errors.New("invalid token claims"))
  2935. return
  2936. }
  2937. name := getURLParam(r, "name")
  2938. action, err := dataprovider.EventActionExists(name)
  2939. if _, ok := err.(*util.RecordNotFoundError); ok {
  2940. s.renderNotFoundPage(w, r, err)
  2941. return
  2942. } else if err != nil {
  2943. s.renderInternalServerErrorPage(w, r, err)
  2944. return
  2945. }
  2946. updatedAction, err := getEventActionFromPostFields(r)
  2947. if err != nil {
  2948. s.renderEventActionPage(w, r, updatedAction, genericPageModeUpdate, err.Error())
  2949. return
  2950. }
  2951. ipAddr := util.GetIPFromRemoteAddress(r.RemoteAddr)
  2952. if err := verifyCSRFToken(r.Form.Get(csrfFormToken), ipAddr); err != nil {
  2953. s.renderForbiddenPage(w, r, err.Error())
  2954. return
  2955. }
  2956. updatedAction.ID = action.ID
  2957. updatedAction.Name = action.Name
  2958. updatedAction.Options.SetEmptySecretsIfNil()
  2959. switch updatedAction.Type {
  2960. case dataprovider.ActionTypeHTTP:
  2961. if updatedAction.Options.HTTPConfig.Password.IsNotPlainAndNotEmpty() {
  2962. updatedAction.Options.HTTPConfig.Password = action.Options.HTTPConfig.Password
  2963. }
  2964. }
  2965. err = dataprovider.UpdateEventAction(&updatedAction, claims.Username, ipAddr)
  2966. if err != nil {
  2967. s.renderEventActionPage(w, r, updatedAction, genericPageModeUpdate, err.Error())
  2968. return
  2969. }
  2970. http.Redirect(w, r, webAdminEventActionsPath, http.StatusSeeOther)
  2971. }
  2972. func (s *httpdServer) handleWebGetEventRules(w http.ResponseWriter, r *http.Request) {
  2973. r.Body = http.MaxBytesReader(w, r.Body, maxRequestSize)
  2974. limit := defaultQueryLimit
  2975. if _, ok := r.URL.Query()["qlimit"]; ok {
  2976. if lim, err := strconv.Atoi(r.URL.Query().Get("qlimit")); err == nil {
  2977. limit = lim
  2978. }
  2979. }
  2980. rules := make([]dataprovider.EventRule, 0, limit)
  2981. for {
  2982. res, err := dataprovider.GetEventRules(limit, len(rules), dataprovider.OrderASC)
  2983. if err != nil {
  2984. s.renderInternalServerErrorPage(w, r, err)
  2985. return
  2986. }
  2987. rules = append(rules, res...)
  2988. if len(res) < limit {
  2989. break
  2990. }
  2991. }
  2992. data := eventRulesPage{
  2993. basePage: s.getBasePageData(pageEventRulesTitle, webAdminEventRulesPath, r),
  2994. Rules: rules,
  2995. }
  2996. renderAdminTemplate(w, templateEventRules, data)
  2997. }
  2998. func (s *httpdServer) handleWebAddEventRuleGet(w http.ResponseWriter, r *http.Request) {
  2999. r.Body = http.MaxBytesReader(w, r.Body, maxRequestSize)
  3000. rule := dataprovider.EventRule{
  3001. Trigger: dataprovider.EventTriggerFsEvent,
  3002. }
  3003. s.renderEventRulePage(w, r, rule, genericPageModeAdd, "")
  3004. }
  3005. func (s *httpdServer) handleWebAddEventRulePost(w http.ResponseWriter, r *http.Request) {
  3006. r.Body = http.MaxBytesReader(w, r.Body, maxRequestSize)
  3007. claims, err := getTokenClaims(r)
  3008. if err != nil || claims.Username == "" {
  3009. s.renderBadRequestPage(w, r, errors.New("invalid token claims"))
  3010. return
  3011. }
  3012. rule, err := getEventRuleFromPostFields(r)
  3013. if err != nil {
  3014. s.renderEventRulePage(w, r, rule, genericPageModeAdd, err.Error())
  3015. return
  3016. }
  3017. ipAddr := util.GetIPFromRemoteAddress(r.RemoteAddr)
  3018. err = verifyCSRFToken(r.Form.Get(csrfFormToken), ipAddr)
  3019. if err != nil {
  3020. s.renderForbiddenPage(w, r, err.Error())
  3021. return
  3022. }
  3023. if err = dataprovider.AddEventRule(&rule, claims.Username, ipAddr); err != nil {
  3024. s.renderEventRulePage(w, r, rule, genericPageModeAdd, err.Error())
  3025. return
  3026. }
  3027. http.Redirect(w, r, webAdminEventRulesPath, http.StatusSeeOther)
  3028. }
  3029. func (s *httpdServer) handleWebUpdateEventRuleGet(w http.ResponseWriter, r *http.Request) {
  3030. r.Body = http.MaxBytesReader(w, r.Body, maxRequestSize)
  3031. name := getURLParam(r, "name")
  3032. rule, err := dataprovider.EventRuleExists(name)
  3033. if err == nil {
  3034. s.renderEventRulePage(w, r, rule, genericPageModeUpdate, "")
  3035. } else if _, ok := err.(*util.RecordNotFoundError); ok {
  3036. s.renderNotFoundPage(w, r, err)
  3037. } else {
  3038. s.renderInternalServerErrorPage(w, r, err)
  3039. }
  3040. }
  3041. func (s *httpdServer) handleWebUpdateEventRulePost(w http.ResponseWriter, r *http.Request) {
  3042. r.Body = http.MaxBytesReader(w, r.Body, maxRequestSize)
  3043. claims, err := getTokenClaims(r)
  3044. if err != nil || claims.Username == "" {
  3045. s.renderBadRequestPage(w, r, errors.New("invalid token claims"))
  3046. return
  3047. }
  3048. name := getURLParam(r, "name")
  3049. rule, err := dataprovider.EventRuleExists(name)
  3050. if _, ok := err.(*util.RecordNotFoundError); ok {
  3051. s.renderNotFoundPage(w, r, err)
  3052. return
  3053. } else if err != nil {
  3054. s.renderInternalServerErrorPage(w, r, err)
  3055. return
  3056. }
  3057. updatedRule, err := getEventRuleFromPostFields(r)
  3058. if err != nil {
  3059. s.renderEventRulePage(w, r, updatedRule, genericPageModeUpdate, err.Error())
  3060. return
  3061. }
  3062. ipAddr := util.GetIPFromRemoteAddress(r.RemoteAddr)
  3063. if err := verifyCSRFToken(r.Form.Get(csrfFormToken), ipAddr); err != nil {
  3064. s.renderForbiddenPage(w, r, err.Error())
  3065. return
  3066. }
  3067. updatedRule.ID = rule.ID
  3068. updatedRule.Name = rule.Name
  3069. err = dataprovider.UpdateEventRule(&updatedRule, claims.Username, ipAddr)
  3070. if err != nil {
  3071. s.renderEventRulePage(w, r, updatedRule, genericPageModeUpdate, err.Error())
  3072. return
  3073. }
  3074. http.Redirect(w, r, webAdminEventRulesPath, http.StatusSeeOther)
  3075. }