webadmin.go 133 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869287028712872287328742875287628772878287928802881288228832884288528862887288828892890289128922893289428952896289728982899290029012902290329042905290629072908290929102911291229132914291529162917291829192920292129222923292429252926292729282929293029312932293329342935293629372938293929402941294229432944294529462947294829492950295129522953295429552956295729582959296029612962296329642965296629672968296929702971297229732974297529762977297829792980298129822983298429852986298729882989299029912992299329942995299629972998299930003001300230033004300530063007300830093010301130123013301430153016301730183019302030213022302330243025302630273028302930303031303230333034303530363037303830393040304130423043304430453046304730483049305030513052305330543055305630573058305930603061306230633064306530663067306830693070307130723073307430753076307730783079308030813082308330843085308630873088308930903091309230933094309530963097309830993100310131023103310431053106310731083109311031113112311331143115311631173118311931203121312231233124312531263127312831293130313131323133313431353136313731383139314031413142314331443145314631473148314931503151315231533154315531563157315831593160316131623163316431653166316731683169317031713172317331743175317631773178317931803181318231833184318531863187318831893190319131923193319431953196319731983199320032013202320332043205320632073208320932103211321232133214321532163217321832193220322132223223322432253226322732283229323032313232323332343235323632373238323932403241324232433244324532463247324832493250325132523253325432553256325732583259326032613262326332643265326632673268326932703271327232733274327532763277327832793280328132823283328432853286328732883289329032913292329332943295329632973298329933003301330233033304330533063307330833093310331133123313331433153316331733183319332033213322332333243325332633273328332933303331333233333334333533363337333833393340334133423343334433453346334733483349335033513352335333543355335633573358335933603361336233633364336533663367336833693370337133723373337433753376337733783379338033813382338333843385338633873388338933903391339233933394339533963397339833993400340134023403340434053406340734083409341034113412341334143415341634173418341934203421342234233424342534263427342834293430343134323433343434353436343734383439344034413442344334443445344634473448344934503451345234533454345534563457345834593460346134623463346434653466346734683469347034713472347334743475347634773478347934803481348234833484348534863487348834893490349134923493349434953496349734983499350035013502350335043505350635073508350935103511351235133514351535163517351835193520352135223523352435253526352735283529353035313532353335343535353635373538353935403541354235433544354535463547354835493550355135523553355435553556355735583559356035613562356335643565356635673568356935703571357235733574357535763577357835793580358135823583358435853586358735883589359035913592359335943595359635973598359936003601360236033604360536063607360836093610361136123613361436153616361736183619362036213622362336243625362636273628362936303631363236333634363536363637363836393640364136423643364436453646364736483649365036513652365336543655365636573658365936603661366236633664366536663667366836693670367136723673367436753676367736783679368036813682368336843685368636873688368936903691369236933694369536963697369836993700370137023703370437053706370737083709371037113712371337143715371637173718371937203721372237233724372537263727372837293730373137323733373437353736373737383739374037413742374337443745374637473748374937503751375237533754375537563757375837593760376137623763376437653766376737683769377037713772377337743775377637773778377937803781378237833784378537863787378837893790379137923793379437953796379737983799380038013802380338043805380638073808380938103811381238133814381538163817381838193820382138223823382438253826382738283829383038313832383338343835383638373838383938403841384238433844384538463847384838493850385138523853385438553856385738583859386038613862386338643865386638673868386938703871387238733874387538763877387838793880388138823883388438853886388738883889389038913892389338943895389638973898389939003901390239033904390539063907390839093910391139123913391439153916391739183919392039213922392339243925392639273928392939303931393239333934393539363937393839393940394139423943394439453946394739483949395039513952395339543955395639573958395939603961396239633964396539663967396839693970397139723973397439753976397739783979398039813982398339843985398639873988398939903991399239933994399539963997399839994000400140024003400440054006400740084009401040114012401340144015401640174018401940204021402240234024402540264027402840294030403140324033403440354036403740384039404040414042404340444045404640474048404940504051405240534054405540564057405840594060406140624063406440654066406740684069407040714072
  1. // Copyright (C) 2019-2023 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/logger"
  35. "github.com/drakkan/sftpgo/v2/internal/mfa"
  36. "github.com/drakkan/sftpgo/v2/internal/plugin"
  37. "github.com/drakkan/sftpgo/v2/internal/smtp"
  38. "github.com/drakkan/sftpgo/v2/internal/util"
  39. "github.com/drakkan/sftpgo/v2/internal/version"
  40. "github.com/drakkan/sftpgo/v2/internal/vfs"
  41. )
  42. type userPageMode int
  43. const (
  44. userPageModeAdd userPageMode = iota + 1
  45. userPageModeUpdate
  46. userPageModeTemplate
  47. )
  48. type folderPageMode int
  49. const (
  50. folderPageModeAdd folderPageMode = iota + 1
  51. folderPageModeUpdate
  52. folderPageModeTemplate
  53. )
  54. type genericPageMode int
  55. const (
  56. genericPageModeAdd genericPageMode = iota + 1
  57. genericPageModeUpdate
  58. )
  59. const (
  60. templateAdminDir = "webadmin"
  61. templateBase = "base.html"
  62. templateBaseLogin = "baselogin.html"
  63. templateFsConfig = "fsconfig.html"
  64. templateSharedComponents = "sharedcomponents.html"
  65. templateUsers = "users.html"
  66. templateUser = "user.html"
  67. templateAdmins = "admins.html"
  68. templateAdmin = "admin.html"
  69. templateConnections = "connections.html"
  70. templateGroups = "groups.html"
  71. templateGroup = "group.html"
  72. templateFolders = "folders.html"
  73. templateFolder = "folder.html"
  74. templateEventRules = "eventrules.html"
  75. templateEventRule = "eventrule.html"
  76. templateEventActions = "eventactions.html"
  77. templateEventAction = "eventaction.html"
  78. templateRoles = "roles.html"
  79. templateRole = "role.html"
  80. templateEvents = "events.html"
  81. templateMessage = "message.html"
  82. templateStatus = "status.html"
  83. templateLogin = "login.html"
  84. templateDefender = "defender.html"
  85. templateIPLists = "iplists.html"
  86. templateIPList = "iplist.html"
  87. templateConfigs = "configs.html"
  88. templateProfile = "profile.html"
  89. templateChangePwd = "changepassword.html"
  90. templateMaintenance = "maintenance.html"
  91. templateMFA = "mfa.html"
  92. templateSetup = "adminsetup.html"
  93. pageUsersTitle = "Users"
  94. pageAdminsTitle = "Admins"
  95. pageConnectionsTitle = "Connections"
  96. pageStatusTitle = "Status"
  97. pageFoldersTitle = "Folders"
  98. pageGroupsTitle = "Groups"
  99. pageEventRulesTitle = "Event rules"
  100. pageEventActionsTitle = "Event actions"
  101. pageRolesTitle = "Roles"
  102. pageProfileTitle = "My profile"
  103. pageChangePwdTitle = "Change password"
  104. pageMaintenanceTitle = "Maintenance"
  105. pageDefenderTitle = "Auto Blocklist"
  106. pageIPListsTitle = "IP Lists"
  107. pageEventsTitle = "Logs"
  108. pageConfigsTitle = "Configurations"
  109. pageForgotPwdTitle = "SFTPGo Admin - Forgot password"
  110. pageResetPwdTitle = "SFTPGo Admin - Reset password"
  111. pageSetupTitle = "Create first admin user"
  112. defaultQueryLimit = 500
  113. inversePatternType = "inverse"
  114. )
  115. var (
  116. adminTemplates = make(map[string]*template.Template)
  117. )
  118. type basePage struct {
  119. Title string
  120. CurrentURL string
  121. UsersURL string
  122. UserURL string
  123. UserTemplateURL string
  124. AdminsURL string
  125. AdminURL string
  126. QuotaScanURL string
  127. ConnectionsURL string
  128. GroupsURL string
  129. GroupURL string
  130. FoldersURL string
  131. FolderURL string
  132. FolderTemplateURL string
  133. DefenderURL string
  134. IPListsURL string
  135. IPListURL string
  136. EventsURL string
  137. ConfigsURL string
  138. LogoutURL string
  139. ProfileURL string
  140. ChangePwdURL string
  141. MFAURL string
  142. EventRulesURL string
  143. EventRuleURL string
  144. EventActionsURL string
  145. EventActionURL string
  146. RolesURL string
  147. RoleURL string
  148. FolderQuotaScanURL string
  149. StatusURL string
  150. MaintenanceURL string
  151. StaticURL string
  152. UsersTitle string
  153. AdminsTitle string
  154. ConnectionsTitle string
  155. FoldersTitle string
  156. GroupsTitle string
  157. EventRulesTitle string
  158. EventActionsTitle string
  159. RolesTitle string
  160. StatusTitle string
  161. MaintenanceTitle string
  162. DefenderTitle string
  163. IPListsTitle string
  164. EventsTitle string
  165. ConfigsTitle string
  166. Version string
  167. CSRFToken string
  168. IsEventManagerPage bool
  169. IsIPManagerPage bool
  170. IsServerManagerPage bool
  171. HasDefender bool
  172. HasSearcher bool
  173. HasExternalLogin bool
  174. LoggedAdmin *dataprovider.Admin
  175. Branding UIBranding
  176. }
  177. type usersPage struct {
  178. basePage
  179. Users []dataprovider.User
  180. }
  181. type adminsPage struct {
  182. basePage
  183. Admins []dataprovider.Admin
  184. }
  185. type foldersPage struct {
  186. basePage
  187. Folders []vfs.BaseVirtualFolder
  188. }
  189. type groupsPage struct {
  190. basePage
  191. Groups []dataprovider.Group
  192. }
  193. type rolesPage struct {
  194. basePage
  195. Roles []dataprovider.Role
  196. }
  197. type eventRulesPage struct {
  198. basePage
  199. Rules []dataprovider.EventRule
  200. }
  201. type eventActionsPage struct {
  202. basePage
  203. Actions []dataprovider.BaseEventAction
  204. }
  205. type connectionsPage struct {
  206. basePage
  207. Connections []common.ConnectionStatus
  208. }
  209. type statusPage struct {
  210. basePage
  211. Status *ServicesStatus
  212. }
  213. type fsWrapper struct {
  214. vfs.Filesystem
  215. IsUserPage bool
  216. IsGroupPage bool
  217. IsHidden bool
  218. HasUsersBaseDir bool
  219. DirPath string
  220. }
  221. type userPage struct {
  222. basePage
  223. User *dataprovider.User
  224. RootPerms []string
  225. Error string
  226. ValidPerms []string
  227. ValidLoginMethods []string
  228. ValidProtocols []string
  229. TwoFactorProtocols []string
  230. WebClientOptions []string
  231. RootDirPerms []string
  232. Mode userPageMode
  233. VirtualFolders []vfs.BaseVirtualFolder
  234. Groups []dataprovider.Group
  235. Roles []dataprovider.Role
  236. CanImpersonate bool
  237. FsWrapper fsWrapper
  238. }
  239. type adminPage struct {
  240. basePage
  241. Admin *dataprovider.Admin
  242. Groups []dataprovider.Group
  243. Roles []dataprovider.Role
  244. Error string
  245. IsAdd bool
  246. }
  247. type profilePage struct {
  248. basePage
  249. Error string
  250. AllowAPIKeyAuth bool
  251. Email string
  252. Description string
  253. }
  254. type changePasswordPage struct {
  255. basePage
  256. Error string
  257. }
  258. type mfaPage struct {
  259. basePage
  260. TOTPConfigs []string
  261. TOTPConfig dataprovider.AdminTOTPConfig
  262. GenerateTOTPURL string
  263. ValidateTOTPURL string
  264. SaveTOTPURL string
  265. RecCodesURL string
  266. }
  267. type maintenancePage struct {
  268. basePage
  269. BackupPath string
  270. RestorePath string
  271. Error string
  272. }
  273. type defenderHostsPage struct {
  274. basePage
  275. DefenderHostsURL string
  276. }
  277. type ipListsPage struct {
  278. basePage
  279. IPListsSearchURL string
  280. RateLimitersStatus bool
  281. RateLimitersProtocols string
  282. IsAllowListEnabled bool
  283. }
  284. type ipListPage struct {
  285. basePage
  286. Entry *dataprovider.IPListEntry
  287. Error string
  288. Mode genericPageMode
  289. }
  290. type setupPage struct {
  291. basePage
  292. Username string
  293. HasInstallationCode bool
  294. InstallationCodeHint string
  295. HideSupportLink bool
  296. Error string
  297. }
  298. type folderPage struct {
  299. basePage
  300. Folder vfs.BaseVirtualFolder
  301. Error string
  302. Mode folderPageMode
  303. FsWrapper fsWrapper
  304. }
  305. type groupPage struct {
  306. basePage
  307. Group *dataprovider.Group
  308. Error string
  309. Mode genericPageMode
  310. ValidPerms []string
  311. ValidLoginMethods []string
  312. ValidProtocols []string
  313. TwoFactorProtocols []string
  314. WebClientOptions []string
  315. VirtualFolders []vfs.BaseVirtualFolder
  316. FsWrapper fsWrapper
  317. }
  318. type rolePage struct {
  319. basePage
  320. Role *dataprovider.Role
  321. Error string
  322. Mode genericPageMode
  323. }
  324. type eventActionPage struct {
  325. basePage
  326. Action dataprovider.BaseEventAction
  327. ActionTypes []dataprovider.EnumMapping
  328. FsActions []dataprovider.EnumMapping
  329. HTTPMethods []string
  330. RedactedSecret string
  331. Error string
  332. Mode genericPageMode
  333. }
  334. type eventRulePage struct {
  335. basePage
  336. Rule dataprovider.EventRule
  337. TriggerTypes []dataprovider.EnumMapping
  338. Actions []dataprovider.BaseEventAction
  339. FsEvents []string
  340. Protocols []string
  341. ProviderEvents []string
  342. ProviderObjects []string
  343. Error string
  344. Mode genericPageMode
  345. IsShared bool
  346. }
  347. type eventsPage struct {
  348. basePage
  349. FsEventsSearchURL string
  350. ProviderEventsSearchURL string
  351. }
  352. type configsPage struct {
  353. basePage
  354. Configs dataprovider.Configs
  355. ConfigSection int
  356. RedactedSecret string
  357. Error string
  358. }
  359. type messagePage struct {
  360. basePage
  361. Error string
  362. Success string
  363. }
  364. type userTemplateFields struct {
  365. Username string
  366. Password string
  367. PublicKeys []string
  368. }
  369. func loadAdminTemplates(templatesPath string) {
  370. usersPaths := []string{
  371. filepath.Join(templatesPath, templateCommonDir, templateCommonCSS),
  372. filepath.Join(templatesPath, templateAdminDir, templateBase),
  373. filepath.Join(templatesPath, templateAdminDir, templateUsers),
  374. }
  375. userPaths := []string{
  376. filepath.Join(templatesPath, templateCommonDir, templateCommonCSS),
  377. filepath.Join(templatesPath, templateAdminDir, templateBase),
  378. filepath.Join(templatesPath, templateAdminDir, templateSharedComponents),
  379. filepath.Join(templatesPath, templateAdminDir, templateFsConfig),
  380. filepath.Join(templatesPath, templateAdminDir, templateUser),
  381. }
  382. adminsPaths := []string{
  383. filepath.Join(templatesPath, templateCommonDir, templateCommonCSS),
  384. filepath.Join(templatesPath, templateAdminDir, templateBase),
  385. filepath.Join(templatesPath, templateAdminDir, templateAdmins),
  386. }
  387. adminPaths := []string{
  388. filepath.Join(templatesPath, templateCommonDir, templateCommonCSS),
  389. filepath.Join(templatesPath, templateAdminDir, templateBase),
  390. filepath.Join(templatesPath, templateAdminDir, templateAdmin),
  391. }
  392. profilePaths := []string{
  393. filepath.Join(templatesPath, templateCommonDir, templateCommonCSS),
  394. filepath.Join(templatesPath, templateAdminDir, templateBase),
  395. filepath.Join(templatesPath, templateAdminDir, templateProfile),
  396. }
  397. changePwdPaths := []string{
  398. filepath.Join(templatesPath, templateCommonDir, templateCommonCSS),
  399. filepath.Join(templatesPath, templateAdminDir, templateBase),
  400. filepath.Join(templatesPath, templateAdminDir, templateChangePwd),
  401. }
  402. connectionsPaths := []string{
  403. filepath.Join(templatesPath, templateCommonDir, templateCommonCSS),
  404. filepath.Join(templatesPath, templateAdminDir, templateBase),
  405. filepath.Join(templatesPath, templateAdminDir, templateConnections),
  406. }
  407. messagePaths := []string{
  408. filepath.Join(templatesPath, templateCommonDir, templateCommonCSS),
  409. filepath.Join(templatesPath, templateAdminDir, templateBase),
  410. filepath.Join(templatesPath, templateAdminDir, templateMessage),
  411. }
  412. foldersPaths := []string{
  413. filepath.Join(templatesPath, templateCommonDir, templateCommonCSS),
  414. filepath.Join(templatesPath, templateAdminDir, templateBase),
  415. filepath.Join(templatesPath, templateAdminDir, templateFolders),
  416. }
  417. folderPaths := []string{
  418. filepath.Join(templatesPath, templateCommonDir, templateCommonCSS),
  419. filepath.Join(templatesPath, templateAdminDir, templateBase),
  420. filepath.Join(templatesPath, templateAdminDir, templateFsConfig),
  421. filepath.Join(templatesPath, templateAdminDir, templateFolder),
  422. }
  423. groupsPaths := []string{
  424. filepath.Join(templatesPath, templateCommonDir, templateCommonCSS),
  425. filepath.Join(templatesPath, templateAdminDir, templateBase),
  426. filepath.Join(templatesPath, templateAdminDir, templateGroups),
  427. }
  428. groupPaths := []string{
  429. filepath.Join(templatesPath, templateCommonDir, templateCommonCSS),
  430. filepath.Join(templatesPath, templateAdminDir, templateBase),
  431. filepath.Join(templatesPath, templateAdminDir, templateFsConfig),
  432. filepath.Join(templatesPath, templateAdminDir, templateSharedComponents),
  433. filepath.Join(templatesPath, templateAdminDir, templateGroup),
  434. }
  435. eventRulesPaths := []string{
  436. filepath.Join(templatesPath, templateCommonDir, templateCommonCSS),
  437. filepath.Join(templatesPath, templateAdminDir, templateBase),
  438. filepath.Join(templatesPath, templateAdminDir, templateEventRules),
  439. }
  440. eventRulePaths := []string{
  441. filepath.Join(templatesPath, templateCommonDir, templateCommonCSS),
  442. filepath.Join(templatesPath, templateAdminDir, templateBase),
  443. filepath.Join(templatesPath, templateAdminDir, templateEventRule),
  444. }
  445. eventActionsPaths := []string{
  446. filepath.Join(templatesPath, templateCommonDir, templateCommonCSS),
  447. filepath.Join(templatesPath, templateAdminDir, templateBase),
  448. filepath.Join(templatesPath, templateAdminDir, templateEventActions),
  449. }
  450. eventActionPaths := []string{
  451. filepath.Join(templatesPath, templateCommonDir, templateCommonCSS),
  452. filepath.Join(templatesPath, templateAdminDir, templateBase),
  453. filepath.Join(templatesPath, templateAdminDir, templateEventAction),
  454. }
  455. statusPaths := []string{
  456. filepath.Join(templatesPath, templateCommonDir, templateCommonCSS),
  457. filepath.Join(templatesPath, templateAdminDir, templateBase),
  458. filepath.Join(templatesPath, templateAdminDir, templateStatus),
  459. }
  460. loginPaths := []string{
  461. filepath.Join(templatesPath, templateCommonDir, templateCommonCSS),
  462. filepath.Join(templatesPath, templateAdminDir, templateBaseLogin),
  463. filepath.Join(templatesPath, templateAdminDir, templateLogin),
  464. }
  465. maintenancePaths := []string{
  466. filepath.Join(templatesPath, templateCommonDir, templateCommonCSS),
  467. filepath.Join(templatesPath, templateAdminDir, templateBase),
  468. filepath.Join(templatesPath, templateAdminDir, templateMaintenance),
  469. }
  470. defenderPaths := []string{
  471. filepath.Join(templatesPath, templateCommonDir, templateCommonCSS),
  472. filepath.Join(templatesPath, templateAdminDir, templateBase),
  473. filepath.Join(templatesPath, templateAdminDir, templateDefender),
  474. }
  475. ipListsPaths := []string{
  476. filepath.Join(templatesPath, templateCommonDir, templateCommonCSS),
  477. filepath.Join(templatesPath, templateAdminDir, templateBase),
  478. filepath.Join(templatesPath, templateAdminDir, templateIPLists),
  479. }
  480. ipListPaths := []string{
  481. filepath.Join(templatesPath, templateCommonDir, templateCommonCSS),
  482. filepath.Join(templatesPath, templateAdminDir, templateBase),
  483. filepath.Join(templatesPath, templateAdminDir, templateIPList),
  484. }
  485. mfaPaths := []string{
  486. filepath.Join(templatesPath, templateCommonDir, templateCommonCSS),
  487. filepath.Join(templatesPath, templateAdminDir, templateBase),
  488. filepath.Join(templatesPath, templateAdminDir, templateMFA),
  489. }
  490. twoFactorPaths := []string{
  491. filepath.Join(templatesPath, templateCommonDir, templateCommonCSS),
  492. filepath.Join(templatesPath, templateAdminDir, templateBaseLogin),
  493. filepath.Join(templatesPath, templateAdminDir, templateTwoFactor),
  494. }
  495. twoFactorRecoveryPaths := []string{
  496. filepath.Join(templatesPath, templateCommonDir, templateCommonCSS),
  497. filepath.Join(templatesPath, templateAdminDir, templateBaseLogin),
  498. filepath.Join(templatesPath, templateAdminDir, templateTwoFactorRecovery),
  499. }
  500. setupPaths := []string{
  501. filepath.Join(templatesPath, templateCommonDir, templateCommonCSS),
  502. filepath.Join(templatesPath, templateAdminDir, templateBaseLogin),
  503. filepath.Join(templatesPath, templateAdminDir, templateSetup),
  504. }
  505. forgotPwdPaths := []string{
  506. filepath.Join(templatesPath, templateCommonDir, templateCommonCSS),
  507. filepath.Join(templatesPath, templateCommonDir, templateForgotPassword),
  508. }
  509. resetPwdPaths := []string{
  510. filepath.Join(templatesPath, templateCommonDir, templateCommonCSS),
  511. filepath.Join(templatesPath, templateCommonDir, templateResetPassword),
  512. }
  513. rolesPaths := []string{
  514. filepath.Join(templatesPath, templateCommonDir, templateCommonCSS),
  515. filepath.Join(templatesPath, templateAdminDir, templateBase),
  516. filepath.Join(templatesPath, templateAdminDir, templateRoles),
  517. }
  518. rolePaths := []string{
  519. filepath.Join(templatesPath, templateCommonDir, templateCommonCSS),
  520. filepath.Join(templatesPath, templateAdminDir, templateBase),
  521. filepath.Join(templatesPath, templateAdminDir, templateRole),
  522. }
  523. eventsPaths := []string{
  524. filepath.Join(templatesPath, templateCommonDir, templateCommonCSS),
  525. filepath.Join(templatesPath, templateAdminDir, templateBase),
  526. filepath.Join(templatesPath, templateAdminDir, templateEvents),
  527. }
  528. configsPaths := []string{
  529. filepath.Join(templatesPath, templateCommonDir, templateCommonCSS),
  530. filepath.Join(templatesPath, templateAdminDir, templateBase),
  531. filepath.Join(templatesPath, templateAdminDir, templateConfigs),
  532. }
  533. fsBaseTpl := template.New("fsBaseTemplate").Funcs(template.FuncMap{
  534. "ListFSProviders": func() []sdk.FilesystemProvider {
  535. return []sdk.FilesystemProvider{sdk.LocalFilesystemProvider, sdk.CryptedFilesystemProvider,
  536. sdk.S3FilesystemProvider, sdk.GCSFilesystemProvider, sdk.AzureBlobFilesystemProvider,
  537. sdk.SFTPFilesystemProvider, sdk.HTTPFilesystemProvider,
  538. }
  539. },
  540. "HumanizeBytes": util.ByteCountSI,
  541. })
  542. usersTmpl := util.LoadTemplate(nil, usersPaths...)
  543. userTmpl := util.LoadTemplate(fsBaseTpl, userPaths...)
  544. adminsTmpl := util.LoadTemplate(nil, adminsPaths...)
  545. adminTmpl := util.LoadTemplate(nil, adminPaths...)
  546. connectionsTmpl := util.LoadTemplate(nil, connectionsPaths...)
  547. messageTmpl := util.LoadTemplate(nil, messagePaths...)
  548. groupsTmpl := util.LoadTemplate(nil, groupsPaths...)
  549. groupTmpl := util.LoadTemplate(fsBaseTpl, groupPaths...)
  550. foldersTmpl := util.LoadTemplate(nil, foldersPaths...)
  551. folderTmpl := util.LoadTemplate(fsBaseTpl, folderPaths...)
  552. eventRulesTmpl := util.LoadTemplate(nil, eventRulesPaths...)
  553. eventRuleTmpl := util.LoadTemplate(fsBaseTpl, eventRulePaths...)
  554. eventActionsTmpl := util.LoadTemplate(nil, eventActionsPaths...)
  555. eventActionTmpl := util.LoadTemplate(nil, eventActionPaths...)
  556. statusTmpl := util.LoadTemplate(nil, statusPaths...)
  557. loginTmpl := util.LoadTemplate(nil, loginPaths...)
  558. profileTmpl := util.LoadTemplate(nil, profilePaths...)
  559. changePwdTmpl := util.LoadTemplate(nil, changePwdPaths...)
  560. maintenanceTmpl := util.LoadTemplate(nil, maintenancePaths...)
  561. defenderTmpl := util.LoadTemplate(nil, defenderPaths...)
  562. ipListsTmpl := util.LoadTemplate(nil, ipListsPaths...)
  563. ipListTmpl := util.LoadTemplate(nil, ipListPaths...)
  564. mfaTmpl := util.LoadTemplate(nil, mfaPaths...)
  565. twoFactorTmpl := util.LoadTemplate(nil, twoFactorPaths...)
  566. twoFactorRecoveryTmpl := util.LoadTemplate(nil, twoFactorRecoveryPaths...)
  567. setupTmpl := util.LoadTemplate(nil, setupPaths...)
  568. forgotPwdTmpl := util.LoadTemplate(nil, forgotPwdPaths...)
  569. resetPwdTmpl := util.LoadTemplate(nil, resetPwdPaths...)
  570. rolesTmpl := util.LoadTemplate(nil, rolesPaths...)
  571. roleTmpl := util.LoadTemplate(nil, rolePaths...)
  572. eventsTmpl := util.LoadTemplate(nil, eventsPaths...)
  573. configsTmpl := util.LoadTemplate(nil, configsPaths...)
  574. adminTemplates[templateUsers] = usersTmpl
  575. adminTemplates[templateUser] = userTmpl
  576. adminTemplates[templateAdmins] = adminsTmpl
  577. adminTemplates[templateAdmin] = adminTmpl
  578. adminTemplates[templateConnections] = connectionsTmpl
  579. adminTemplates[templateMessage] = messageTmpl
  580. adminTemplates[templateGroups] = groupsTmpl
  581. adminTemplates[templateGroup] = groupTmpl
  582. adminTemplates[templateFolders] = foldersTmpl
  583. adminTemplates[templateFolder] = folderTmpl
  584. adminTemplates[templateEventRules] = eventRulesTmpl
  585. adminTemplates[templateEventRule] = eventRuleTmpl
  586. adminTemplates[templateEventActions] = eventActionsTmpl
  587. adminTemplates[templateEventAction] = eventActionTmpl
  588. adminTemplates[templateStatus] = statusTmpl
  589. adminTemplates[templateLogin] = loginTmpl
  590. adminTemplates[templateProfile] = profileTmpl
  591. adminTemplates[templateChangePwd] = changePwdTmpl
  592. adminTemplates[templateMaintenance] = maintenanceTmpl
  593. adminTemplates[templateDefender] = defenderTmpl
  594. adminTemplates[templateIPLists] = ipListsTmpl
  595. adminTemplates[templateIPList] = ipListTmpl
  596. adminTemplates[templateMFA] = mfaTmpl
  597. adminTemplates[templateTwoFactor] = twoFactorTmpl
  598. adminTemplates[templateTwoFactorRecovery] = twoFactorRecoveryTmpl
  599. adminTemplates[templateSetup] = setupTmpl
  600. adminTemplates[templateForgotPassword] = forgotPwdTmpl
  601. adminTemplates[templateResetPassword] = resetPwdTmpl
  602. adminTemplates[templateRoles] = rolesTmpl
  603. adminTemplates[templateRole] = roleTmpl
  604. adminTemplates[templateEvents] = eventsTmpl
  605. adminTemplates[templateConfigs] = configsTmpl
  606. }
  607. func isEventManagerResource(currentURL string) bool {
  608. if currentURL == webAdminEventRulesPath {
  609. return true
  610. }
  611. if currentURL == webAdminEventActionsPath {
  612. return true
  613. }
  614. if currentURL == webAdminEventRulePath || strings.HasPrefix(currentURL, webAdminEventRulePath+"/") {
  615. return true
  616. }
  617. if currentURL == webAdminEventActionPath || strings.HasPrefix(currentURL, webAdminEventActionPath+"/") {
  618. return true
  619. }
  620. return false
  621. }
  622. func isIPListsResource(currentURL string) bool {
  623. if currentURL == webDefenderPath {
  624. return true
  625. }
  626. if currentURL == webIPListsPath {
  627. return true
  628. }
  629. if strings.HasPrefix(currentURL, webIPListPath+"/") {
  630. return true
  631. }
  632. return false
  633. }
  634. func isServerManagerResource(currentURL string) bool {
  635. return currentURL == webEventsPath || currentURL == webStatusPath || currentURL == webMaintenancePath ||
  636. currentURL == webConfigsPath
  637. }
  638. func (s *httpdServer) getBasePageData(title, currentURL string, r *http.Request) basePage {
  639. var csrfToken string
  640. if currentURL != "" {
  641. csrfToken = createCSRFToken(util.GetIPFromRemoteAddress(r.RemoteAddr))
  642. }
  643. return basePage{
  644. Title: title,
  645. CurrentURL: currentURL,
  646. UsersURL: webUsersPath,
  647. UserURL: webUserPath,
  648. UserTemplateURL: webTemplateUser,
  649. AdminsURL: webAdminsPath,
  650. AdminURL: webAdminPath,
  651. GroupsURL: webGroupsPath,
  652. GroupURL: webGroupPath,
  653. FoldersURL: webFoldersPath,
  654. FolderURL: webFolderPath,
  655. FolderTemplateURL: webTemplateFolder,
  656. DefenderURL: webDefenderPath,
  657. IPListsURL: webIPListsPath,
  658. IPListURL: webIPListPath,
  659. EventsURL: webEventsPath,
  660. ConfigsURL: webConfigsPath,
  661. LogoutURL: webLogoutPath,
  662. ProfileURL: webAdminProfilePath,
  663. ChangePwdURL: webChangeAdminPwdPath,
  664. MFAURL: webAdminMFAPath,
  665. EventRulesURL: webAdminEventRulesPath,
  666. EventRuleURL: webAdminEventRulePath,
  667. EventActionsURL: webAdminEventActionsPath,
  668. EventActionURL: webAdminEventActionPath,
  669. RolesURL: webAdminRolesPath,
  670. RoleURL: webAdminRolePath,
  671. QuotaScanURL: webQuotaScanPath,
  672. ConnectionsURL: webConnectionsPath,
  673. StatusURL: webStatusPath,
  674. FolderQuotaScanURL: webScanVFolderPath,
  675. MaintenanceURL: webMaintenancePath,
  676. StaticURL: webStaticFilesPath,
  677. UsersTitle: pageUsersTitle,
  678. AdminsTitle: pageAdminsTitle,
  679. ConnectionsTitle: pageConnectionsTitle,
  680. FoldersTitle: pageFoldersTitle,
  681. GroupsTitle: pageGroupsTitle,
  682. EventRulesTitle: pageEventRulesTitle,
  683. EventActionsTitle: pageEventActionsTitle,
  684. RolesTitle: pageRolesTitle,
  685. StatusTitle: pageStatusTitle,
  686. MaintenanceTitle: pageMaintenanceTitle,
  687. DefenderTitle: pageDefenderTitle,
  688. IPListsTitle: pageIPListsTitle,
  689. EventsTitle: pageEventsTitle,
  690. ConfigsTitle: pageConfigsTitle,
  691. Version: version.GetAsString(),
  692. LoggedAdmin: getAdminFromToken(r),
  693. IsEventManagerPage: isEventManagerResource(currentURL),
  694. IsIPManagerPage: isIPListsResource(currentURL),
  695. IsServerManagerPage: isServerManagerResource(currentURL),
  696. HasDefender: common.Config.DefenderConfig.Enabled,
  697. HasSearcher: plugin.Handler.HasSearcher(),
  698. HasExternalLogin: isLoggedInWithOIDC(r),
  699. CSRFToken: csrfToken,
  700. Branding: s.binding.Branding.WebAdmin,
  701. }
  702. }
  703. func renderAdminTemplate(w http.ResponseWriter, tmplName string, data any) {
  704. err := adminTemplates[tmplName].ExecuteTemplate(w, tmplName, data)
  705. if err != nil {
  706. http.Error(w, err.Error(), http.StatusInternalServerError)
  707. }
  708. }
  709. func (s *httpdServer) renderMessagePage(w http.ResponseWriter, r *http.Request, title, body string, statusCode int,
  710. err error, message string,
  711. ) {
  712. var errorString string
  713. if body != "" {
  714. errorString = body + " "
  715. }
  716. if err != nil {
  717. errorString += err.Error()
  718. }
  719. data := messagePage{
  720. basePage: s.getBasePageData(title, "", r),
  721. Error: errorString,
  722. Success: message,
  723. }
  724. w.WriteHeader(statusCode)
  725. renderAdminTemplate(w, templateMessage, data)
  726. }
  727. func (s *httpdServer) renderInternalServerErrorPage(w http.ResponseWriter, r *http.Request, err error) {
  728. s.renderMessagePage(w, r, page500Title, page500Body, http.StatusInternalServerError, err, "")
  729. }
  730. func (s *httpdServer) renderBadRequestPage(w http.ResponseWriter, r *http.Request, err error) {
  731. s.renderMessagePage(w, r, page400Title, "", http.StatusBadRequest, err, "")
  732. }
  733. func (s *httpdServer) renderForbiddenPage(w http.ResponseWriter, r *http.Request, body string) {
  734. s.renderMessagePage(w, r, page403Title, "", http.StatusForbidden, nil, body)
  735. }
  736. func (s *httpdServer) renderNotFoundPage(w http.ResponseWriter, r *http.Request, err error) {
  737. s.renderMessagePage(w, r, page404Title, page404Body, http.StatusNotFound, err, "")
  738. }
  739. func (s *httpdServer) renderForgotPwdPage(w http.ResponseWriter, error, ip string) {
  740. data := forgotPwdPage{
  741. CurrentURL: webAdminForgotPwdPath,
  742. Error: error,
  743. CSRFToken: createCSRFToken(ip),
  744. StaticURL: webStaticFilesPath,
  745. Title: pageForgotPwdTitle,
  746. Branding: s.binding.Branding.WebAdmin,
  747. }
  748. renderAdminTemplate(w, templateForgotPassword, data)
  749. }
  750. func (s *httpdServer) renderResetPwdPage(w http.ResponseWriter, error, ip string) {
  751. data := resetPwdPage{
  752. CurrentURL: webAdminResetPwdPath,
  753. Error: error,
  754. CSRFToken: createCSRFToken(ip),
  755. StaticURL: webStaticFilesPath,
  756. Title: pageResetPwdTitle,
  757. Branding: s.binding.Branding.WebAdmin,
  758. }
  759. renderAdminTemplate(w, templateResetPassword, data)
  760. }
  761. func (s *httpdServer) renderTwoFactorPage(w http.ResponseWriter, error, ip string) {
  762. data := twoFactorPage{
  763. CurrentURL: webAdminTwoFactorPath,
  764. Version: version.Get().Version,
  765. Error: error,
  766. CSRFToken: createCSRFToken(ip),
  767. StaticURL: webStaticFilesPath,
  768. RecoveryURL: webAdminTwoFactorRecoveryPath,
  769. Branding: s.binding.Branding.WebAdmin,
  770. }
  771. renderAdminTemplate(w, templateTwoFactor, data)
  772. }
  773. func (s *httpdServer) renderTwoFactorRecoveryPage(w http.ResponseWriter, error, ip string) {
  774. data := twoFactorPage{
  775. CurrentURL: webAdminTwoFactorRecoveryPath,
  776. Version: version.Get().Version,
  777. Error: error,
  778. CSRFToken: createCSRFToken(ip),
  779. StaticURL: webStaticFilesPath,
  780. Branding: s.binding.Branding.WebAdmin,
  781. }
  782. renderAdminTemplate(w, templateTwoFactorRecovery, data)
  783. }
  784. func (s *httpdServer) renderMFAPage(w http.ResponseWriter, r *http.Request) {
  785. data := mfaPage{
  786. basePage: s.getBasePageData(pageMFATitle, webAdminMFAPath, r),
  787. TOTPConfigs: mfa.GetAvailableTOTPConfigNames(),
  788. GenerateTOTPURL: webAdminTOTPGeneratePath,
  789. ValidateTOTPURL: webAdminTOTPValidatePath,
  790. SaveTOTPURL: webAdminTOTPSavePath,
  791. RecCodesURL: webAdminRecoveryCodesPath,
  792. }
  793. admin, err := dataprovider.AdminExists(data.LoggedAdmin.Username)
  794. if err != nil {
  795. s.renderInternalServerErrorPage(w, r, err)
  796. return
  797. }
  798. data.TOTPConfig = admin.Filters.TOTPConfig
  799. renderAdminTemplate(w, templateMFA, data)
  800. }
  801. func (s *httpdServer) renderProfilePage(w http.ResponseWriter, r *http.Request, error string) {
  802. data := profilePage{
  803. basePage: s.getBasePageData(pageProfileTitle, webAdminProfilePath, r),
  804. Error: error,
  805. }
  806. admin, err := dataprovider.AdminExists(data.LoggedAdmin.Username)
  807. if err != nil {
  808. s.renderInternalServerErrorPage(w, r, err)
  809. return
  810. }
  811. data.AllowAPIKeyAuth = admin.Filters.AllowAPIKeyAuth
  812. data.Email = admin.Email
  813. data.Description = admin.Description
  814. renderAdminTemplate(w, templateProfile, data)
  815. }
  816. func (s *httpdServer) renderChangePasswordPage(w http.ResponseWriter, r *http.Request, error string) {
  817. data := changePasswordPage{
  818. basePage: s.getBasePageData(pageChangePwdTitle, webChangeAdminPwdPath, r),
  819. Error: error,
  820. }
  821. renderAdminTemplate(w, templateChangePwd, data)
  822. }
  823. func (s *httpdServer) renderMaintenancePage(w http.ResponseWriter, r *http.Request, error string) {
  824. data := maintenancePage{
  825. basePage: s.getBasePageData(pageMaintenanceTitle, webMaintenancePath, r),
  826. BackupPath: webBackupPath,
  827. RestorePath: webRestorePath,
  828. Error: error,
  829. }
  830. renderAdminTemplate(w, templateMaintenance, data)
  831. }
  832. func (s *httpdServer) renderConfigsPage(w http.ResponseWriter, r *http.Request, configs dataprovider.Configs,
  833. error string, section int,
  834. ) {
  835. configs.SetNilsToEmpty()
  836. if configs.SMTP.Port == 0 {
  837. configs.SMTP.Port = 587
  838. }
  839. data := configsPage{
  840. basePage: s.getBasePageData(pageConfigsTitle, webConfigsPath, r),
  841. Configs: configs,
  842. ConfigSection: section,
  843. RedactedSecret: redactedSecret,
  844. Error: error,
  845. }
  846. renderAdminTemplate(w, templateConfigs, data)
  847. }
  848. func (s *httpdServer) renderAdminSetupPage(w http.ResponseWriter, r *http.Request, username, error string) {
  849. data := setupPage{
  850. basePage: s.getBasePageData(pageSetupTitle, webAdminSetupPath, r),
  851. Username: username,
  852. HasInstallationCode: installationCode != "",
  853. InstallationCodeHint: installationCodeHint,
  854. HideSupportLink: hideSupportLink,
  855. Error: error,
  856. }
  857. renderAdminTemplate(w, templateSetup, data)
  858. }
  859. func (s *httpdServer) renderAddUpdateAdminPage(w http.ResponseWriter, r *http.Request, admin *dataprovider.Admin,
  860. error string, isAdd bool) {
  861. groups, err := s.getWebGroups(w, r, defaultQueryLimit, true)
  862. if err != nil {
  863. return
  864. }
  865. roles, err := s.getWebRoles(w, r, 10, true)
  866. if err != nil {
  867. return
  868. }
  869. currentURL := webAdminPath
  870. title := "Add a new admin"
  871. if !isAdd {
  872. currentURL = fmt.Sprintf("%v/%v", webAdminPath, url.PathEscape(admin.Username))
  873. title = "Update admin"
  874. }
  875. data := adminPage{
  876. basePage: s.getBasePageData(title, currentURL, r),
  877. Admin: admin,
  878. Groups: groups,
  879. Roles: roles,
  880. Error: error,
  881. IsAdd: isAdd,
  882. }
  883. renderAdminTemplate(w, templateAdmin, data)
  884. }
  885. func (s *httpdServer) getUserPageTitleAndURL(mode userPageMode, username string) (string, string) {
  886. var title, currentURL string
  887. switch mode {
  888. case userPageModeAdd:
  889. title = "Add a new user"
  890. currentURL = webUserPath
  891. case userPageModeUpdate:
  892. title = "Update user"
  893. currentURL = fmt.Sprintf("%v/%v", webUserPath, url.PathEscape(username))
  894. case userPageModeTemplate:
  895. title = "User template"
  896. currentURL = webTemplateUser
  897. }
  898. return title, currentURL
  899. }
  900. func (s *httpdServer) renderUserPage(w http.ResponseWriter, r *http.Request, user *dataprovider.User,
  901. mode userPageMode, errorString string, admin *dataprovider.Admin,
  902. ) {
  903. user.SetEmptySecretsIfNil()
  904. title, currentURL := s.getUserPageTitleAndURL(mode, user.Username)
  905. if user.Password != "" && user.IsPasswordHashed() {
  906. switch mode {
  907. case userPageModeUpdate:
  908. user.Password = redactedSecret
  909. default:
  910. user.Password = ""
  911. }
  912. }
  913. user.FsConfig.RedactedSecret = redactedSecret
  914. basePage := s.getBasePageData(title, currentURL, r)
  915. if (mode == userPageModeAdd || mode == userPageModeTemplate) && len(user.Groups) == 0 && admin != nil {
  916. for _, group := range admin.Groups {
  917. user.Groups = append(user.Groups, sdk.GroupMapping{
  918. Name: group.Name,
  919. Type: group.Options.GetUserGroupType(),
  920. })
  921. }
  922. }
  923. var roles []dataprovider.Role
  924. if basePage.LoggedAdmin.Role == "" {
  925. var err error
  926. roles, err = s.getWebRoles(w, r, 10, true)
  927. if err != nil {
  928. return
  929. }
  930. }
  931. folders, err := s.getWebVirtualFolders(w, r, defaultQueryLimit, true)
  932. if err != nil {
  933. return
  934. }
  935. groups, err := s.getWebGroups(w, r, defaultQueryLimit, true)
  936. if err != nil {
  937. return
  938. }
  939. data := userPage{
  940. basePage: basePage,
  941. Mode: mode,
  942. Error: errorString,
  943. User: user,
  944. ValidPerms: dataprovider.ValidPerms,
  945. ValidLoginMethods: dataprovider.ValidLoginMethods,
  946. ValidProtocols: dataprovider.ValidProtocols,
  947. TwoFactorProtocols: dataprovider.MFAProtocols,
  948. WebClientOptions: sdk.WebClientOptions,
  949. RootDirPerms: user.GetPermissionsForPath("/"),
  950. VirtualFolders: folders,
  951. Groups: groups,
  952. Roles: roles,
  953. CanImpersonate: os.Getuid() == 0,
  954. FsWrapper: fsWrapper{
  955. Filesystem: user.FsConfig,
  956. IsUserPage: true,
  957. IsGroupPage: false,
  958. IsHidden: basePage.LoggedAdmin.Filters.Preferences.HideFilesystem(),
  959. HasUsersBaseDir: dataprovider.HasUsersBaseDir(),
  960. DirPath: user.HomeDir,
  961. },
  962. }
  963. renderAdminTemplate(w, templateUser, data)
  964. }
  965. func (s *httpdServer) renderIPListPage(w http.ResponseWriter, r *http.Request, entry dataprovider.IPListEntry,
  966. mode genericPageMode, error string,
  967. ) {
  968. var title, currentURL string
  969. switch mode {
  970. case genericPageModeAdd:
  971. title = "Add a new IP List entry"
  972. currentURL = fmt.Sprintf("%s/%d", webIPListPath, entry.Type)
  973. case genericPageModeUpdate:
  974. title = "Update IP List entry"
  975. currentURL = fmt.Sprintf("%s/%d/%s", webIPListPath, entry.Type, url.PathEscape(entry.IPOrNet))
  976. }
  977. data := ipListPage{
  978. basePage: s.getBasePageData(title, currentURL, r),
  979. Error: error,
  980. Entry: &entry,
  981. Mode: mode,
  982. }
  983. renderAdminTemplate(w, templateIPList, data)
  984. }
  985. func (s *httpdServer) renderRolePage(w http.ResponseWriter, r *http.Request, role dataprovider.Role,
  986. mode genericPageMode, error string,
  987. ) {
  988. var title, currentURL string
  989. switch mode {
  990. case genericPageModeAdd:
  991. title = "Add a new role"
  992. currentURL = webAdminRolePath
  993. case genericPageModeUpdate:
  994. title = "Update role"
  995. currentURL = fmt.Sprintf("%s/%s", webAdminRolePath, url.PathEscape(role.Name))
  996. }
  997. data := rolePage{
  998. basePage: s.getBasePageData(title, currentURL, r),
  999. Error: error,
  1000. Role: &role,
  1001. Mode: mode,
  1002. }
  1003. renderAdminTemplate(w, templateRole, data)
  1004. }
  1005. func (s *httpdServer) renderGroupPage(w http.ResponseWriter, r *http.Request, group dataprovider.Group,
  1006. mode genericPageMode, error string,
  1007. ) {
  1008. folders, err := s.getWebVirtualFolders(w, r, defaultQueryLimit, true)
  1009. if err != nil {
  1010. return
  1011. }
  1012. group.SetEmptySecretsIfNil()
  1013. group.UserSettings.FsConfig.RedactedSecret = redactedSecret
  1014. var title, currentURL string
  1015. switch mode {
  1016. case genericPageModeAdd:
  1017. title = "Add a new group"
  1018. currentURL = webGroupPath
  1019. case genericPageModeUpdate:
  1020. title = "Update group"
  1021. currentURL = fmt.Sprintf("%v/%v", webGroupPath, url.PathEscape(group.Name))
  1022. }
  1023. group.UserSettings.FsConfig.RedactedSecret = redactedSecret
  1024. group.UserSettings.FsConfig.SetEmptySecretsIfNil()
  1025. data := groupPage{
  1026. basePage: s.getBasePageData(title, currentURL, r),
  1027. Error: error,
  1028. Group: &group,
  1029. Mode: mode,
  1030. ValidPerms: dataprovider.ValidPerms,
  1031. ValidLoginMethods: dataprovider.ValidLoginMethods,
  1032. ValidProtocols: dataprovider.ValidProtocols,
  1033. TwoFactorProtocols: dataprovider.MFAProtocols,
  1034. WebClientOptions: sdk.WebClientOptions,
  1035. VirtualFolders: folders,
  1036. FsWrapper: fsWrapper{
  1037. Filesystem: group.UserSettings.FsConfig,
  1038. IsUserPage: false,
  1039. IsGroupPage: true,
  1040. HasUsersBaseDir: false,
  1041. DirPath: group.UserSettings.HomeDir,
  1042. },
  1043. }
  1044. renderAdminTemplate(w, templateGroup, data)
  1045. }
  1046. func (s *httpdServer) renderEventActionPage(w http.ResponseWriter, r *http.Request, action dataprovider.BaseEventAction,
  1047. mode genericPageMode, error string,
  1048. ) {
  1049. action.Options.SetEmptySecretsIfNil()
  1050. var title, currentURL string
  1051. switch mode {
  1052. case genericPageModeAdd:
  1053. title = "Add a new event action"
  1054. currentURL = webAdminEventActionPath
  1055. case genericPageModeUpdate:
  1056. title = "Update event action"
  1057. currentURL = fmt.Sprintf("%s/%s", webAdminEventActionPath, url.PathEscape(action.Name))
  1058. }
  1059. if action.Options.HTTPConfig.Timeout == 0 {
  1060. action.Options.HTTPConfig.Timeout = 20
  1061. }
  1062. if action.Options.CmdConfig.Timeout == 0 {
  1063. action.Options.CmdConfig.Timeout = 20
  1064. }
  1065. if action.Options.PwdExpirationConfig.Threshold == 0 {
  1066. action.Options.PwdExpirationConfig.Threshold = 10
  1067. }
  1068. data := eventActionPage{
  1069. basePage: s.getBasePageData(title, currentURL, r),
  1070. Action: action,
  1071. ActionTypes: dataprovider.EventActionTypes,
  1072. FsActions: dataprovider.FsActionTypes,
  1073. HTTPMethods: dataprovider.SupportedHTTPActionMethods,
  1074. RedactedSecret: redactedSecret,
  1075. Error: error,
  1076. Mode: mode,
  1077. }
  1078. renderAdminTemplate(w, templateEventAction, data)
  1079. }
  1080. func (s *httpdServer) renderEventRulePage(w http.ResponseWriter, r *http.Request, rule dataprovider.EventRule,
  1081. mode genericPageMode, error string,
  1082. ) {
  1083. actions, err := s.getWebEventActions(w, r, defaultQueryLimit, true)
  1084. if err != nil {
  1085. return
  1086. }
  1087. var title, currentURL string
  1088. switch mode {
  1089. case genericPageModeAdd:
  1090. title = "Add new event rules"
  1091. currentURL = webAdminEventRulePath
  1092. case genericPageModeUpdate:
  1093. title = "Update event rules"
  1094. currentURL = fmt.Sprintf("%v/%v", webAdminEventRulePath, url.PathEscape(rule.Name))
  1095. }
  1096. data := eventRulePage{
  1097. basePage: s.getBasePageData(title, currentURL, r),
  1098. Rule: rule,
  1099. TriggerTypes: dataprovider.EventTriggerTypes,
  1100. Actions: actions,
  1101. FsEvents: dataprovider.SupportedFsEvents,
  1102. Protocols: dataprovider.SupportedRuleConditionProtocols,
  1103. ProviderEvents: dataprovider.SupportedProviderEvents,
  1104. ProviderObjects: dataprovider.SupporteRuleConditionProviderObjects,
  1105. Error: error,
  1106. Mode: mode,
  1107. IsShared: s.isShared > 0,
  1108. }
  1109. renderAdminTemplate(w, templateEventRule, data)
  1110. }
  1111. func (s *httpdServer) renderFolderPage(w http.ResponseWriter, r *http.Request, folder vfs.BaseVirtualFolder,
  1112. mode folderPageMode, error string,
  1113. ) {
  1114. var title, currentURL string
  1115. switch mode {
  1116. case folderPageModeAdd:
  1117. title = "Add a new folder"
  1118. currentURL = webFolderPath
  1119. case folderPageModeUpdate:
  1120. title = "Update folder"
  1121. currentURL = fmt.Sprintf("%v/%v", webFolderPath, url.PathEscape(folder.Name))
  1122. case folderPageModeTemplate:
  1123. title = "Folder template"
  1124. currentURL = webTemplateFolder
  1125. }
  1126. folder.FsConfig.RedactedSecret = redactedSecret
  1127. folder.FsConfig.SetEmptySecretsIfNil()
  1128. data := folderPage{
  1129. basePage: s.getBasePageData(title, currentURL, r),
  1130. Error: error,
  1131. Folder: folder,
  1132. Mode: mode,
  1133. FsWrapper: fsWrapper{
  1134. Filesystem: folder.FsConfig,
  1135. IsUserPage: false,
  1136. IsGroupPage: false,
  1137. HasUsersBaseDir: false,
  1138. DirPath: folder.MappedPath,
  1139. },
  1140. }
  1141. renderAdminTemplate(w, templateFolder, data)
  1142. }
  1143. func getFoldersForTemplate(r *http.Request) []string {
  1144. var res []string
  1145. folderNames := r.Form["tpl_foldername"]
  1146. folders := make(map[string]bool)
  1147. for _, name := range folderNames {
  1148. name = strings.TrimSpace(name)
  1149. if name == "" {
  1150. continue
  1151. }
  1152. if _, ok := folders[name]; ok {
  1153. continue
  1154. }
  1155. folders[name] = true
  1156. res = append(res, name)
  1157. }
  1158. return res
  1159. }
  1160. func getUsersForTemplate(r *http.Request) []userTemplateFields {
  1161. var res []userTemplateFields
  1162. tplUsernames := r.Form["tpl_username"]
  1163. tplPasswords := r.Form["tpl_password"]
  1164. tplPublicKeys := r.Form["tpl_public_keys"]
  1165. users := make(map[string]bool)
  1166. for idx, username := range tplUsernames {
  1167. username = strings.TrimSpace(username)
  1168. password := ""
  1169. publicKey := ""
  1170. if len(tplPasswords) > idx {
  1171. password = strings.TrimSpace(tplPasswords[idx])
  1172. }
  1173. if len(tplPublicKeys) > idx {
  1174. publicKey = strings.TrimSpace(tplPublicKeys[idx])
  1175. }
  1176. if username == "" {
  1177. continue
  1178. }
  1179. if _, ok := users[username]; ok {
  1180. continue
  1181. }
  1182. users[username] = true
  1183. res = append(res, userTemplateFields{
  1184. Username: username,
  1185. Password: password,
  1186. PublicKeys: []string{publicKey},
  1187. })
  1188. }
  1189. return res
  1190. }
  1191. func getVirtualFoldersFromPostFields(r *http.Request) []vfs.VirtualFolder {
  1192. var virtualFolders []vfs.VirtualFolder
  1193. folderPaths := r.Form["vfolder_path"]
  1194. folderNames := r.Form["vfolder_name"]
  1195. folderQuotaSizes := r.Form["vfolder_quota_size"]
  1196. folderQuotaFiles := r.Form["vfolder_quota_files"]
  1197. for idx, p := range folderPaths {
  1198. p = strings.TrimSpace(p)
  1199. name := ""
  1200. if len(folderNames) > idx {
  1201. name = folderNames[idx]
  1202. }
  1203. if p != "" && name != "" {
  1204. vfolder := vfs.VirtualFolder{
  1205. BaseVirtualFolder: vfs.BaseVirtualFolder{
  1206. Name: name,
  1207. },
  1208. VirtualPath: p,
  1209. QuotaFiles: -1,
  1210. QuotaSize: -1,
  1211. }
  1212. if len(folderQuotaSizes) > idx {
  1213. quotaSize, err := util.ParseBytes(folderQuotaSizes[idx])
  1214. if err == nil {
  1215. vfolder.QuotaSize = quotaSize
  1216. }
  1217. }
  1218. if len(folderQuotaFiles) > idx {
  1219. quotaFiles, err := strconv.Atoi(strings.TrimSpace(folderQuotaFiles[idx]))
  1220. if err == nil {
  1221. vfolder.QuotaFiles = quotaFiles
  1222. }
  1223. }
  1224. virtualFolders = append(virtualFolders, vfolder)
  1225. }
  1226. }
  1227. return virtualFolders
  1228. }
  1229. func getSubDirPermissionsFromPostFields(r *http.Request) map[string][]string {
  1230. permissions := make(map[string][]string)
  1231. for k := range r.Form {
  1232. if strings.HasPrefix(k, "sub_perm_path") {
  1233. p := strings.TrimSpace(r.Form.Get(k))
  1234. if p != "" {
  1235. idx := strings.TrimPrefix(k, "sub_perm_path")
  1236. permissions[p] = r.Form[fmt.Sprintf("sub_perm_permissions%v", idx)]
  1237. }
  1238. }
  1239. }
  1240. return permissions
  1241. }
  1242. func getUserPermissionsFromPostFields(r *http.Request) map[string][]string {
  1243. permissions := getSubDirPermissionsFromPostFields(r)
  1244. permissions["/"] = r.Form["permissions"]
  1245. return permissions
  1246. }
  1247. func getDataTransferLimitsFromPostFields(r *http.Request) ([]sdk.DataTransferLimit, error) {
  1248. var result []sdk.DataTransferLimit
  1249. for k := range r.Form {
  1250. if strings.HasPrefix(k, "data_transfer_limit_sources") {
  1251. sources := getSliceFromDelimitedValues(r.Form.Get(k), ",")
  1252. if len(sources) > 0 {
  1253. dtLimit := sdk.DataTransferLimit{
  1254. Sources: sources,
  1255. }
  1256. idx := strings.TrimPrefix(k, "data_transfer_limit_sources")
  1257. ul := r.Form.Get(fmt.Sprintf("upload_data_transfer_source%v", idx))
  1258. dl := r.Form.Get(fmt.Sprintf("download_data_transfer_source%v", idx))
  1259. total := r.Form.Get(fmt.Sprintf("total_data_transfer_source%v", idx))
  1260. if ul != "" {
  1261. dataUL, err := strconv.ParseInt(ul, 10, 64)
  1262. if err != nil {
  1263. return result, fmt.Errorf("invalid upload_data_transfer_source%v %#v: %w", idx, ul, err)
  1264. }
  1265. dtLimit.UploadDataTransfer = dataUL
  1266. }
  1267. if dl != "" {
  1268. dataDL, err := strconv.ParseInt(dl, 10, 64)
  1269. if err != nil {
  1270. return result, fmt.Errorf("invalid download_data_transfer_source%v %#v: %w", idx, dl, err)
  1271. }
  1272. dtLimit.DownloadDataTransfer = dataDL
  1273. }
  1274. if total != "" {
  1275. dataTotal, err := strconv.ParseInt(total, 10, 64)
  1276. if err != nil {
  1277. return result, fmt.Errorf("invalid total_data_transfer_source%v %#v: %w", idx, total, err)
  1278. }
  1279. dtLimit.TotalDataTransfer = dataTotal
  1280. }
  1281. result = append(result, dtLimit)
  1282. }
  1283. }
  1284. }
  1285. return result, nil
  1286. }
  1287. func getBandwidthLimitsFromPostFields(r *http.Request) ([]sdk.BandwidthLimit, error) {
  1288. var result []sdk.BandwidthLimit
  1289. for k := range r.Form {
  1290. if strings.HasPrefix(k, "bandwidth_limit_sources") {
  1291. sources := getSliceFromDelimitedValues(r.Form.Get(k), ",")
  1292. if len(sources) > 0 {
  1293. bwLimit := sdk.BandwidthLimit{
  1294. Sources: sources,
  1295. }
  1296. idx := strings.TrimPrefix(k, "bandwidth_limit_sources")
  1297. ul := r.Form.Get(fmt.Sprintf("upload_bandwidth_source%v", idx))
  1298. dl := r.Form.Get(fmt.Sprintf("download_bandwidth_source%v", idx))
  1299. if ul != "" {
  1300. bandwidthUL, err := strconv.ParseInt(ul, 10, 64)
  1301. if err != nil {
  1302. return result, fmt.Errorf("invalid upload_bandwidth_source%v %#v: %w", idx, ul, err)
  1303. }
  1304. bwLimit.UploadBandwidth = bandwidthUL
  1305. }
  1306. if dl != "" {
  1307. bandwidthDL, err := strconv.ParseInt(dl, 10, 64)
  1308. if err != nil {
  1309. return result, fmt.Errorf("invalid download_bandwidth_source%v %#v: %w", idx, ul, err)
  1310. }
  1311. bwLimit.DownloadBandwidth = bandwidthDL
  1312. }
  1313. result = append(result, bwLimit)
  1314. }
  1315. }
  1316. }
  1317. return result, nil
  1318. }
  1319. func getPatterDenyPolicyFromString(policy string) int {
  1320. denyPolicy := sdk.DenyPolicyDefault
  1321. if policy == "1" {
  1322. denyPolicy = sdk.DenyPolicyHide
  1323. }
  1324. return denyPolicy
  1325. }
  1326. func getFilePatternsFromPostField(r *http.Request) []sdk.PatternsFilter {
  1327. var result []sdk.PatternsFilter
  1328. allowedPatterns := make(map[string][]string)
  1329. deniedPatterns := make(map[string][]string)
  1330. patternPolicies := make(map[string]string)
  1331. for k := range r.Form {
  1332. if strings.HasPrefix(k, "pattern_path") {
  1333. p := strings.TrimSpace(r.Form.Get(k))
  1334. idx := strings.TrimPrefix(k, "pattern_path")
  1335. filters := strings.TrimSpace(r.Form.Get(fmt.Sprintf("patterns%v", idx)))
  1336. filters = strings.ReplaceAll(filters, " ", "")
  1337. patternType := r.Form.Get(fmt.Sprintf("pattern_type%v", idx))
  1338. patternPolicy := r.Form.Get(fmt.Sprintf("pattern_policy%v", idx))
  1339. if p != "" && filters != "" {
  1340. if patternType == "allowed" {
  1341. allowedPatterns[p] = append(allowedPatterns[p], strings.Split(filters, ",")...)
  1342. } else {
  1343. deniedPatterns[p] = append(deniedPatterns[p], strings.Split(filters, ",")...)
  1344. }
  1345. if patternPolicy != "" && patternPolicy != "0" {
  1346. patternPolicies[p] = patternPolicy
  1347. }
  1348. }
  1349. }
  1350. }
  1351. for dirAllowed, allowPatterns := range allowedPatterns {
  1352. filter := sdk.PatternsFilter{
  1353. Path: dirAllowed,
  1354. AllowedPatterns: allowPatterns,
  1355. DenyPolicy: getPatterDenyPolicyFromString(patternPolicies[dirAllowed]),
  1356. }
  1357. for dirDenied, denPatterns := range deniedPatterns {
  1358. if dirAllowed == dirDenied {
  1359. filter.DeniedPatterns = denPatterns
  1360. break
  1361. }
  1362. }
  1363. result = append(result, filter)
  1364. }
  1365. for dirDenied, denPatterns := range deniedPatterns {
  1366. found := false
  1367. for _, res := range result {
  1368. if res.Path == dirDenied {
  1369. found = true
  1370. break
  1371. }
  1372. }
  1373. if !found {
  1374. result = append(result, sdk.PatternsFilter{
  1375. Path: dirDenied,
  1376. DeniedPatterns: denPatterns,
  1377. DenyPolicy: getPatterDenyPolicyFromString(patternPolicies[dirDenied]),
  1378. })
  1379. }
  1380. }
  1381. return result
  1382. }
  1383. func getGroupsFromUserPostFields(r *http.Request) []sdk.GroupMapping {
  1384. var groups []sdk.GroupMapping
  1385. primaryGroup := r.Form.Get("primary_group")
  1386. if primaryGroup != "" {
  1387. groups = append(groups, sdk.GroupMapping{
  1388. Name: primaryGroup,
  1389. Type: sdk.GroupTypePrimary,
  1390. })
  1391. }
  1392. secondaryGroups := r.Form["secondary_groups"]
  1393. for _, name := range secondaryGroups {
  1394. groups = append(groups, sdk.GroupMapping{
  1395. Name: name,
  1396. Type: sdk.GroupTypeSecondary,
  1397. })
  1398. }
  1399. membershipGroups := r.Form["membership_groups"]
  1400. for _, name := range membershipGroups {
  1401. groups = append(groups, sdk.GroupMapping{
  1402. Name: name,
  1403. Type: sdk.GroupTypeMembership,
  1404. })
  1405. }
  1406. return groups
  1407. }
  1408. func getFiltersFromUserPostFields(r *http.Request) (sdk.BaseUserFilters, error) {
  1409. var filters sdk.BaseUserFilters
  1410. bwLimits, err := getBandwidthLimitsFromPostFields(r)
  1411. if err != nil {
  1412. return filters, err
  1413. }
  1414. dtLimits, err := getDataTransferLimitsFromPostFields(r)
  1415. if err != nil {
  1416. return filters, err
  1417. }
  1418. maxFileSize, err := util.ParseBytes(r.Form.Get("max_upload_file_size"))
  1419. if err != nil {
  1420. return filters, fmt.Errorf("invalid max upload file size: %w", err)
  1421. }
  1422. defaultSharesExpiration, err := strconv.ParseInt(r.Form.Get("default_shares_expiration"), 10, 64)
  1423. if err != nil {
  1424. return filters, fmt.Errorf("invalid default shares expiration: %w", err)
  1425. }
  1426. passwordExpiration, err := strconv.ParseInt(r.Form.Get("password_expiration"), 10, 64)
  1427. if err != nil {
  1428. return filters, fmt.Errorf("invalid password expiration: %w", err)
  1429. }
  1430. if r.Form.Get("ftp_security") == "1" {
  1431. filters.FTPSecurity = 1
  1432. }
  1433. filters.BandwidthLimits = bwLimits
  1434. filters.DataTransferLimits = dtLimits
  1435. filters.AllowedIP = getSliceFromDelimitedValues(r.Form.Get("allowed_ip"), ",")
  1436. filters.DeniedIP = getSliceFromDelimitedValues(r.Form.Get("denied_ip"), ",")
  1437. filters.DeniedLoginMethods = r.Form["denied_login_methods"]
  1438. filters.DeniedProtocols = r.Form["denied_protocols"]
  1439. filters.TwoFactorAuthProtocols = r.Form["required_two_factor_protocols"]
  1440. filters.FilePatterns = getFilePatternsFromPostField(r)
  1441. filters.TLSUsername = sdk.TLSUsername(r.Form.Get("tls_username"))
  1442. filters.WebClient = r.Form["web_client_options"]
  1443. filters.DefaultSharesExpiration = int(defaultSharesExpiration)
  1444. filters.PasswordExpiration = int(passwordExpiration)
  1445. hooks := r.Form["hooks"]
  1446. if util.Contains(hooks, "external_auth_disabled") {
  1447. filters.Hooks.ExternalAuthDisabled = true
  1448. }
  1449. if util.Contains(hooks, "pre_login_disabled") {
  1450. filters.Hooks.PreLoginDisabled = true
  1451. }
  1452. if util.Contains(hooks, "check_password_disabled") {
  1453. filters.Hooks.CheckPasswordDisabled = true
  1454. }
  1455. filters.IsAnonymous = r.Form.Get("is_anonymous") != ""
  1456. filters.DisableFsChecks = r.Form.Get("disable_fs_checks") != ""
  1457. filters.AllowAPIKeyAuth = r.Form.Get("allow_api_key_auth") != ""
  1458. filters.StartDirectory = r.Form.Get("start_directory")
  1459. filters.MaxUploadFileSize = maxFileSize
  1460. filters.ExternalAuthCacheTime, err = strconv.ParseInt(r.Form.Get("external_auth_cache_time"), 10, 64)
  1461. if err != nil {
  1462. return filters, fmt.Errorf("invalid external auth cache time: %w", err)
  1463. }
  1464. return filters, nil
  1465. }
  1466. func getSecretFromFormField(r *http.Request, field string) *kms.Secret {
  1467. secret := kms.NewPlainSecret(r.Form.Get(field))
  1468. if strings.TrimSpace(secret.GetPayload()) == redactedSecret {
  1469. secret.SetStatus(sdkkms.SecretStatusRedacted)
  1470. }
  1471. if strings.TrimSpace(secret.GetPayload()) == "" {
  1472. secret.SetStatus("")
  1473. }
  1474. return secret
  1475. }
  1476. func getS3Config(r *http.Request) (vfs.S3FsConfig, error) {
  1477. var err error
  1478. config := vfs.S3FsConfig{}
  1479. config.Bucket = strings.TrimSpace(r.Form.Get("s3_bucket"))
  1480. config.Region = strings.TrimSpace(r.Form.Get("s3_region"))
  1481. config.AccessKey = strings.TrimSpace(r.Form.Get("s3_access_key"))
  1482. config.RoleARN = strings.TrimSpace(r.Form.Get("s3_role_arn"))
  1483. config.AccessSecret = getSecretFromFormField(r, "s3_access_secret")
  1484. config.Endpoint = strings.TrimSpace(r.Form.Get("s3_endpoint"))
  1485. config.StorageClass = strings.TrimSpace(r.Form.Get("s3_storage_class"))
  1486. config.ACL = strings.TrimSpace(r.Form.Get("s3_acl"))
  1487. config.KeyPrefix = r.Form.Get("s3_key_prefix")
  1488. config.UploadPartSize, err = strconv.ParseInt(r.Form.Get("s3_upload_part_size"), 10, 64)
  1489. if err != nil {
  1490. return config, fmt.Errorf("invalid s3 upload part size: %w", err)
  1491. }
  1492. config.UploadConcurrency, err = strconv.Atoi(r.Form.Get("s3_upload_concurrency"))
  1493. if err != nil {
  1494. return config, fmt.Errorf("invalid s3 upload concurrency: %w", err)
  1495. }
  1496. config.DownloadPartSize, err = strconv.ParseInt(r.Form.Get("s3_download_part_size"), 10, 64)
  1497. if err != nil {
  1498. return config, fmt.Errorf("invalid s3 download part size: %w", err)
  1499. }
  1500. config.DownloadConcurrency, err = strconv.Atoi(r.Form.Get("s3_download_concurrency"))
  1501. if err != nil {
  1502. return config, fmt.Errorf("invalid s3 download concurrency: %w", err)
  1503. }
  1504. config.ForcePathStyle = r.Form.Get("s3_force_path_style") != ""
  1505. config.DownloadPartMaxTime, err = strconv.Atoi(r.Form.Get("s3_download_part_max_time"))
  1506. if err != nil {
  1507. return config, fmt.Errorf("invalid s3 download part max time: %w", err)
  1508. }
  1509. config.UploadPartMaxTime, err = strconv.Atoi(r.Form.Get("s3_upload_part_max_time"))
  1510. if err != nil {
  1511. return config, fmt.Errorf("invalid s3 upload part max time: %w", err)
  1512. }
  1513. return config, nil
  1514. }
  1515. func getGCSConfig(r *http.Request) (vfs.GCSFsConfig, error) {
  1516. var err error
  1517. config := vfs.GCSFsConfig{}
  1518. config.Bucket = strings.TrimSpace(r.Form.Get("gcs_bucket"))
  1519. config.StorageClass = strings.TrimSpace(r.Form.Get("gcs_storage_class"))
  1520. config.ACL = strings.TrimSpace(r.Form.Get("gcs_acl"))
  1521. config.KeyPrefix = r.Form.Get("gcs_key_prefix")
  1522. uploadPartSize, err := strconv.ParseInt(r.Form.Get("gcs_upload_part_size"), 10, 64)
  1523. if err == nil {
  1524. config.UploadPartSize = uploadPartSize
  1525. }
  1526. uploadPartMaxTime, err := strconv.Atoi(r.Form.Get("gcs_upload_part_max_time"))
  1527. if err == nil {
  1528. config.UploadPartMaxTime = uploadPartMaxTime
  1529. }
  1530. autoCredentials := r.Form.Get("gcs_auto_credentials")
  1531. if autoCredentials != "" {
  1532. config.AutomaticCredentials = 1
  1533. } else {
  1534. config.AutomaticCredentials = 0
  1535. }
  1536. credentials, _, err := r.FormFile("gcs_credential_file")
  1537. if err == http.ErrMissingFile {
  1538. return config, nil
  1539. }
  1540. if err != nil {
  1541. return config, err
  1542. }
  1543. defer credentials.Close()
  1544. fileBytes, err := io.ReadAll(credentials)
  1545. if err != nil || len(fileBytes) == 0 {
  1546. if len(fileBytes) == 0 {
  1547. err = errors.New("credentials file size must be greater than 0")
  1548. }
  1549. return config, err
  1550. }
  1551. config.Credentials = kms.NewPlainSecret(string(fileBytes))
  1552. config.AutomaticCredentials = 0
  1553. return config, err
  1554. }
  1555. func getSFTPConfig(r *http.Request) (vfs.SFTPFsConfig, error) {
  1556. var err error
  1557. config := vfs.SFTPFsConfig{}
  1558. config.Endpoint = strings.TrimSpace(r.Form.Get("sftp_endpoint"))
  1559. config.Username = r.Form.Get("sftp_username")
  1560. config.Password = getSecretFromFormField(r, "sftp_password")
  1561. config.PrivateKey = getSecretFromFormField(r, "sftp_private_key")
  1562. config.KeyPassphrase = getSecretFromFormField(r, "sftp_key_passphrase")
  1563. fingerprintsFormValue := r.Form.Get("sftp_fingerprints")
  1564. config.Fingerprints = getSliceFromDelimitedValues(fingerprintsFormValue, "\n")
  1565. config.Prefix = r.Form.Get("sftp_prefix")
  1566. config.DisableCouncurrentReads = r.Form.Get("sftp_disable_concurrent_reads") != ""
  1567. config.BufferSize, err = strconv.ParseInt(r.Form.Get("sftp_buffer_size"), 10, 64)
  1568. if r.Form.Get("sftp_equality_check_mode") != "" {
  1569. config.EqualityCheckMode = 1
  1570. } else {
  1571. config.EqualityCheckMode = 0
  1572. }
  1573. if err != nil {
  1574. return config, fmt.Errorf("invalid SFTP buffer size: %w", err)
  1575. }
  1576. return config, nil
  1577. }
  1578. func getHTTPFsConfig(r *http.Request) vfs.HTTPFsConfig {
  1579. config := vfs.HTTPFsConfig{}
  1580. config.Endpoint = strings.TrimSpace(r.Form.Get("http_endpoint"))
  1581. config.Username = r.Form.Get("http_username")
  1582. config.SkipTLSVerify = r.Form.Get("http_skip_tls_verify") != ""
  1583. config.Password = getSecretFromFormField(r, "http_password")
  1584. config.APIKey = getSecretFromFormField(r, "http_api_key")
  1585. if r.Form.Get("http_equality_check_mode") != "" {
  1586. config.EqualityCheckMode = 1
  1587. } else {
  1588. config.EqualityCheckMode = 0
  1589. }
  1590. return config
  1591. }
  1592. func getAzureConfig(r *http.Request) (vfs.AzBlobFsConfig, error) {
  1593. var err error
  1594. config := vfs.AzBlobFsConfig{}
  1595. config.Container = strings.TrimSpace(r.Form.Get("az_container"))
  1596. config.AccountName = strings.TrimSpace(r.Form.Get("az_account_name"))
  1597. config.AccountKey = getSecretFromFormField(r, "az_account_key")
  1598. config.SASURL = getSecretFromFormField(r, "az_sas_url")
  1599. config.Endpoint = strings.TrimSpace(r.Form.Get("az_endpoint"))
  1600. config.KeyPrefix = r.Form.Get("az_key_prefix")
  1601. config.AccessTier = strings.TrimSpace(r.Form.Get("az_access_tier"))
  1602. config.UseEmulator = r.Form.Get("az_use_emulator") != ""
  1603. config.UploadPartSize, err = strconv.ParseInt(r.Form.Get("az_upload_part_size"), 10, 64)
  1604. if err != nil {
  1605. return config, fmt.Errorf("invalid azure upload part size: %w", err)
  1606. }
  1607. config.UploadConcurrency, err = strconv.Atoi(r.Form.Get("az_upload_concurrency"))
  1608. if err != nil {
  1609. return config, fmt.Errorf("invalid azure upload concurrency: %w", err)
  1610. }
  1611. config.DownloadPartSize, err = strconv.ParseInt(r.Form.Get("az_download_part_size"), 10, 64)
  1612. if err != nil {
  1613. return config, fmt.Errorf("invalid azure download part size: %w", err)
  1614. }
  1615. config.DownloadConcurrency, err = strconv.Atoi(r.Form.Get("az_download_concurrency"))
  1616. if err != nil {
  1617. return config, fmt.Errorf("invalid azure download concurrency: %w", err)
  1618. }
  1619. return config, nil
  1620. }
  1621. func getFsConfigFromPostFields(r *http.Request) (vfs.Filesystem, error) {
  1622. var fs vfs.Filesystem
  1623. fs.Provider = sdk.GetProviderByName(r.Form.Get("fs_provider"))
  1624. switch fs.Provider {
  1625. case sdk.S3FilesystemProvider:
  1626. config, err := getS3Config(r)
  1627. if err != nil {
  1628. return fs, err
  1629. }
  1630. fs.S3Config = config
  1631. case sdk.AzureBlobFilesystemProvider:
  1632. config, err := getAzureConfig(r)
  1633. if err != nil {
  1634. return fs, err
  1635. }
  1636. fs.AzBlobConfig = config
  1637. case sdk.GCSFilesystemProvider:
  1638. config, err := getGCSConfig(r)
  1639. if err != nil {
  1640. return fs, err
  1641. }
  1642. fs.GCSConfig = config
  1643. case sdk.CryptedFilesystemProvider:
  1644. fs.CryptConfig.Passphrase = getSecretFromFormField(r, "crypt_passphrase")
  1645. case sdk.SFTPFilesystemProvider:
  1646. config, err := getSFTPConfig(r)
  1647. if err != nil {
  1648. return fs, err
  1649. }
  1650. fs.SFTPConfig = config
  1651. case sdk.HTTPFilesystemProvider:
  1652. fs.HTTPConfig = getHTTPFsConfig(r)
  1653. }
  1654. return fs, nil
  1655. }
  1656. func getAdminHiddenUserPageSections(r *http.Request) int {
  1657. var result int
  1658. for _, val := range r.Form["user_page_hidden_sections"] {
  1659. switch val {
  1660. case "1":
  1661. result++
  1662. case "2":
  1663. result += 2
  1664. case "3":
  1665. result += 4
  1666. case "4":
  1667. result += 8
  1668. case "5":
  1669. result += 16
  1670. case "6":
  1671. result += 32
  1672. case "7":
  1673. result += 64
  1674. }
  1675. }
  1676. return result
  1677. }
  1678. func getAdminFromPostFields(r *http.Request) (dataprovider.Admin, error) {
  1679. var admin dataprovider.Admin
  1680. err := r.ParseForm()
  1681. if err != nil {
  1682. return admin, err
  1683. }
  1684. status, err := strconv.Atoi(r.Form.Get("status"))
  1685. if err != nil {
  1686. return admin, fmt.Errorf("invalid status: %w", err)
  1687. }
  1688. admin.Username = r.Form.Get("username")
  1689. admin.Password = r.Form.Get("password")
  1690. admin.Permissions = r.Form["permissions"]
  1691. admin.Email = r.Form.Get("email")
  1692. admin.Status = status
  1693. admin.Role = r.Form.Get("role")
  1694. admin.Filters.AllowList = getSliceFromDelimitedValues(r.Form.Get("allowed_ip"), ",")
  1695. admin.Filters.AllowAPIKeyAuth = r.Form.Get("allow_api_key_auth") != ""
  1696. admin.AdditionalInfo = r.Form.Get("additional_info")
  1697. admin.Description = r.Form.Get("description")
  1698. admin.Filters.Preferences.HideUserPageSections = getAdminHiddenUserPageSections(r)
  1699. admin.Filters.Preferences.DefaultUsersExpiration = 0
  1700. if val := r.Form.Get("default_users_expiration"); val != "" {
  1701. defaultUsersExpiration, err := strconv.ParseInt(r.Form.Get("default_users_expiration"), 10, 64)
  1702. if err != nil {
  1703. return admin, fmt.Errorf("invalid default users expiration: %w", err)
  1704. }
  1705. admin.Filters.Preferences.DefaultUsersExpiration = int(defaultUsersExpiration)
  1706. }
  1707. for k := range r.Form {
  1708. if strings.HasPrefix(k, "group") {
  1709. groupName := strings.TrimSpace(r.Form.Get(k))
  1710. if groupName != "" {
  1711. idx := strings.TrimPrefix(k, "group")
  1712. addAsGroupType := r.Form.Get(fmt.Sprintf("add_as_group_type%s", idx))
  1713. group := dataprovider.AdminGroupMapping{
  1714. Name: groupName,
  1715. }
  1716. switch addAsGroupType {
  1717. case "1":
  1718. group.Options.AddToUsersAs = dataprovider.GroupAddToUsersAsPrimary
  1719. case "2":
  1720. group.Options.AddToUsersAs = dataprovider.GroupAddToUsersAsSecondary
  1721. default:
  1722. group.Options.AddToUsersAs = dataprovider.GroupAddToUsersAsMembership
  1723. }
  1724. admin.Groups = append(admin.Groups, group)
  1725. }
  1726. }
  1727. }
  1728. return admin, nil
  1729. }
  1730. func replacePlaceholders(field string, replacements map[string]string) string {
  1731. for k, v := range replacements {
  1732. field = strings.ReplaceAll(field, k, v)
  1733. }
  1734. return field
  1735. }
  1736. func getFolderFromTemplate(folder vfs.BaseVirtualFolder, name string) vfs.BaseVirtualFolder {
  1737. folder.Name = name
  1738. replacements := make(map[string]string)
  1739. replacements["%name%"] = folder.Name
  1740. folder.MappedPath = replacePlaceholders(folder.MappedPath, replacements)
  1741. folder.Description = replacePlaceholders(folder.Description, replacements)
  1742. switch folder.FsConfig.Provider {
  1743. case sdk.CryptedFilesystemProvider:
  1744. folder.FsConfig.CryptConfig = getCryptFsFromTemplate(folder.FsConfig.CryptConfig, replacements)
  1745. case sdk.S3FilesystemProvider:
  1746. folder.FsConfig.S3Config = getS3FsFromTemplate(folder.FsConfig.S3Config, replacements)
  1747. case sdk.GCSFilesystemProvider:
  1748. folder.FsConfig.GCSConfig = getGCSFsFromTemplate(folder.FsConfig.GCSConfig, replacements)
  1749. case sdk.AzureBlobFilesystemProvider:
  1750. folder.FsConfig.AzBlobConfig = getAzBlobFsFromTemplate(folder.FsConfig.AzBlobConfig, replacements)
  1751. case sdk.SFTPFilesystemProvider:
  1752. folder.FsConfig.SFTPConfig = getSFTPFsFromTemplate(folder.FsConfig.SFTPConfig, replacements)
  1753. case sdk.HTTPFilesystemProvider:
  1754. folder.FsConfig.HTTPConfig = getHTTPFsFromTemplate(folder.FsConfig.HTTPConfig, replacements)
  1755. }
  1756. return folder
  1757. }
  1758. func getCryptFsFromTemplate(fsConfig vfs.CryptFsConfig, replacements map[string]string) vfs.CryptFsConfig {
  1759. if fsConfig.Passphrase != nil {
  1760. if fsConfig.Passphrase.IsPlain() {
  1761. payload := replacePlaceholders(fsConfig.Passphrase.GetPayload(), replacements)
  1762. fsConfig.Passphrase = kms.NewPlainSecret(payload)
  1763. }
  1764. }
  1765. return fsConfig
  1766. }
  1767. func getS3FsFromTemplate(fsConfig vfs.S3FsConfig, replacements map[string]string) vfs.S3FsConfig {
  1768. fsConfig.KeyPrefix = replacePlaceholders(fsConfig.KeyPrefix, replacements)
  1769. fsConfig.AccessKey = replacePlaceholders(fsConfig.AccessKey, replacements)
  1770. if fsConfig.AccessSecret != nil && fsConfig.AccessSecret.IsPlain() {
  1771. payload := replacePlaceholders(fsConfig.AccessSecret.GetPayload(), replacements)
  1772. fsConfig.AccessSecret = kms.NewPlainSecret(payload)
  1773. }
  1774. return fsConfig
  1775. }
  1776. func getGCSFsFromTemplate(fsConfig vfs.GCSFsConfig, replacements map[string]string) vfs.GCSFsConfig {
  1777. fsConfig.KeyPrefix = replacePlaceholders(fsConfig.KeyPrefix, replacements)
  1778. return fsConfig
  1779. }
  1780. func getAzBlobFsFromTemplate(fsConfig vfs.AzBlobFsConfig, replacements map[string]string) vfs.AzBlobFsConfig {
  1781. fsConfig.KeyPrefix = replacePlaceholders(fsConfig.KeyPrefix, replacements)
  1782. fsConfig.AccountName = replacePlaceholders(fsConfig.AccountName, replacements)
  1783. if fsConfig.AccountKey != nil && fsConfig.AccountKey.IsPlain() {
  1784. payload := replacePlaceholders(fsConfig.AccountKey.GetPayload(), replacements)
  1785. fsConfig.AccountKey = kms.NewPlainSecret(payload)
  1786. }
  1787. return fsConfig
  1788. }
  1789. func getSFTPFsFromTemplate(fsConfig vfs.SFTPFsConfig, replacements map[string]string) vfs.SFTPFsConfig {
  1790. fsConfig.Prefix = replacePlaceholders(fsConfig.Prefix, replacements)
  1791. fsConfig.Username = replacePlaceholders(fsConfig.Username, replacements)
  1792. if fsConfig.Password != nil && fsConfig.Password.IsPlain() {
  1793. payload := replacePlaceholders(fsConfig.Password.GetPayload(), replacements)
  1794. fsConfig.Password = kms.NewPlainSecret(payload)
  1795. }
  1796. return fsConfig
  1797. }
  1798. func getHTTPFsFromTemplate(fsConfig vfs.HTTPFsConfig, replacements map[string]string) vfs.HTTPFsConfig {
  1799. fsConfig.Username = replacePlaceholders(fsConfig.Username, replacements)
  1800. return fsConfig
  1801. }
  1802. func getUserFromTemplate(user dataprovider.User, template userTemplateFields) dataprovider.User {
  1803. user.Username = template.Username
  1804. user.Password = template.Password
  1805. user.PublicKeys = template.PublicKeys
  1806. replacements := make(map[string]string)
  1807. replacements["%username%"] = user.Username
  1808. if user.Password != "" && !user.IsPasswordHashed() {
  1809. user.Password = replacePlaceholders(user.Password, replacements)
  1810. replacements["%password%"] = user.Password
  1811. }
  1812. user.HomeDir = replacePlaceholders(user.HomeDir, replacements)
  1813. var vfolders []vfs.VirtualFolder
  1814. for _, vfolder := range user.VirtualFolders {
  1815. vfolder.Name = replacePlaceholders(vfolder.Name, replacements)
  1816. vfolder.VirtualPath = replacePlaceholders(vfolder.VirtualPath, replacements)
  1817. vfolders = append(vfolders, vfolder)
  1818. }
  1819. user.VirtualFolders = vfolders
  1820. user.Description = replacePlaceholders(user.Description, replacements)
  1821. user.AdditionalInfo = replacePlaceholders(user.AdditionalInfo, replacements)
  1822. user.Filters.StartDirectory = replacePlaceholders(user.Filters.StartDirectory, replacements)
  1823. switch user.FsConfig.Provider {
  1824. case sdk.CryptedFilesystemProvider:
  1825. user.FsConfig.CryptConfig = getCryptFsFromTemplate(user.FsConfig.CryptConfig, replacements)
  1826. case sdk.S3FilesystemProvider:
  1827. user.FsConfig.S3Config = getS3FsFromTemplate(user.FsConfig.S3Config, replacements)
  1828. case sdk.GCSFilesystemProvider:
  1829. user.FsConfig.GCSConfig = getGCSFsFromTemplate(user.FsConfig.GCSConfig, replacements)
  1830. case sdk.AzureBlobFilesystemProvider:
  1831. user.FsConfig.AzBlobConfig = getAzBlobFsFromTemplate(user.FsConfig.AzBlobConfig, replacements)
  1832. case sdk.SFTPFilesystemProvider:
  1833. user.FsConfig.SFTPConfig = getSFTPFsFromTemplate(user.FsConfig.SFTPConfig, replacements)
  1834. case sdk.HTTPFilesystemProvider:
  1835. user.FsConfig.HTTPConfig = getHTTPFsFromTemplate(user.FsConfig.HTTPConfig, replacements)
  1836. }
  1837. return user
  1838. }
  1839. func getTransferLimits(r *http.Request) (int64, int64, int64, error) {
  1840. dataTransferUL, err := strconv.ParseInt(r.Form.Get("upload_data_transfer"), 10, 64)
  1841. if err != nil {
  1842. return 0, 0, 0, fmt.Errorf("invalid upload data transfer: %w", err)
  1843. }
  1844. dataTransferDL, err := strconv.ParseInt(r.Form.Get("download_data_transfer"), 10, 64)
  1845. if err != nil {
  1846. return 0, 0, 0, fmt.Errorf("invalid download data transfer: %w", err)
  1847. }
  1848. dataTransferTotal, err := strconv.ParseInt(r.Form.Get("total_data_transfer"), 10, 64)
  1849. if err != nil {
  1850. return 0, 0, 0, fmt.Errorf("invalid total data transfer: %w", err)
  1851. }
  1852. return dataTransferUL, dataTransferDL, dataTransferTotal, nil
  1853. }
  1854. func getQuotaLimits(r *http.Request) (int64, int, error) {
  1855. quotaSize, err := util.ParseBytes(r.Form.Get("quota_size"))
  1856. if err != nil {
  1857. return 0, 0, fmt.Errorf("invalid quota size: %w", err)
  1858. }
  1859. quotaFiles, err := strconv.Atoi(r.Form.Get("quota_files"))
  1860. if err != nil {
  1861. return 0, 0, fmt.Errorf("invalid quota files: %w", err)
  1862. }
  1863. return quotaSize, quotaFiles, nil
  1864. }
  1865. func getUserFromPostFields(r *http.Request) (dataprovider.User, error) {
  1866. user := dataprovider.User{}
  1867. err := r.ParseMultipartForm(maxRequestSize)
  1868. if err != nil {
  1869. return user, err
  1870. }
  1871. defer r.MultipartForm.RemoveAll() //nolint:errcheck
  1872. uid, err := strconv.Atoi(r.Form.Get("uid"))
  1873. if err != nil {
  1874. return user, fmt.Errorf("invalid uid: %w", err)
  1875. }
  1876. gid, err := strconv.Atoi(r.Form.Get("gid"))
  1877. if err != nil {
  1878. return user, fmt.Errorf("invalid uid: %w", err)
  1879. }
  1880. maxSessions, err := strconv.Atoi(r.Form.Get("max_sessions"))
  1881. if err != nil {
  1882. return user, fmt.Errorf("invalid max sessions: %w", err)
  1883. }
  1884. quotaSize, quotaFiles, err := getQuotaLimits(r)
  1885. if err != nil {
  1886. return user, err
  1887. }
  1888. bandwidthUL, err := strconv.ParseInt(r.Form.Get("upload_bandwidth"), 10, 64)
  1889. if err != nil {
  1890. return user, fmt.Errorf("invalid upload bandwidth: %w", err)
  1891. }
  1892. bandwidthDL, err := strconv.ParseInt(r.Form.Get("download_bandwidth"), 10, 64)
  1893. if err != nil {
  1894. return user, fmt.Errorf("invalid download bandwidth: %w", err)
  1895. }
  1896. dataTransferUL, dataTransferDL, dataTransferTotal, err := getTransferLimits(r)
  1897. if err != nil {
  1898. return user, err
  1899. }
  1900. status, err := strconv.Atoi(r.Form.Get("status"))
  1901. if err != nil {
  1902. return user, fmt.Errorf("invalid status: %w", err)
  1903. }
  1904. expirationDateMillis := int64(0)
  1905. expirationDateString := r.Form.Get("expiration_date")
  1906. if strings.TrimSpace(expirationDateString) != "" {
  1907. expirationDate, err := time.Parse(webDateTimeFormat, expirationDateString)
  1908. if err != nil {
  1909. return user, err
  1910. }
  1911. expirationDateMillis = util.GetTimeAsMsSinceEpoch(expirationDate)
  1912. }
  1913. fsConfig, err := getFsConfigFromPostFields(r)
  1914. if err != nil {
  1915. return user, err
  1916. }
  1917. filters, err := getFiltersFromUserPostFields(r)
  1918. if err != nil {
  1919. return user, err
  1920. }
  1921. user = dataprovider.User{
  1922. BaseUser: sdk.BaseUser{
  1923. Username: r.Form.Get("username"),
  1924. Email: r.Form.Get("email"),
  1925. Password: r.Form.Get("password"),
  1926. PublicKeys: r.Form["public_keys"],
  1927. HomeDir: r.Form.Get("home_dir"),
  1928. UID: uid,
  1929. GID: gid,
  1930. Permissions: getUserPermissionsFromPostFields(r),
  1931. MaxSessions: maxSessions,
  1932. QuotaSize: quotaSize,
  1933. QuotaFiles: quotaFiles,
  1934. UploadBandwidth: bandwidthUL,
  1935. DownloadBandwidth: bandwidthDL,
  1936. UploadDataTransfer: dataTransferUL,
  1937. DownloadDataTransfer: dataTransferDL,
  1938. TotalDataTransfer: dataTransferTotal,
  1939. Status: status,
  1940. ExpirationDate: expirationDateMillis,
  1941. AdditionalInfo: r.Form.Get("additional_info"),
  1942. Description: r.Form.Get("description"),
  1943. Role: r.Form.Get("role"),
  1944. },
  1945. Filters: dataprovider.UserFilters{
  1946. BaseUserFilters: filters,
  1947. RequirePasswordChange: r.Form.Get("require_password_change") != "",
  1948. },
  1949. VirtualFolders: getVirtualFoldersFromPostFields(r),
  1950. FsConfig: fsConfig,
  1951. Groups: getGroupsFromUserPostFields(r),
  1952. }
  1953. return user, nil
  1954. }
  1955. func getGroupFromPostFields(r *http.Request) (dataprovider.Group, error) {
  1956. group := dataprovider.Group{}
  1957. err := r.ParseMultipartForm(maxRequestSize)
  1958. if err != nil {
  1959. return group, err
  1960. }
  1961. defer r.MultipartForm.RemoveAll() //nolint:errcheck
  1962. maxSessions, err := strconv.Atoi(r.Form.Get("max_sessions"))
  1963. if err != nil {
  1964. return group, fmt.Errorf("invalid max sessions: %w", err)
  1965. }
  1966. quotaSize, quotaFiles, err := getQuotaLimits(r)
  1967. if err != nil {
  1968. return group, err
  1969. }
  1970. bandwidthUL, err := strconv.ParseInt(r.Form.Get("upload_bandwidth"), 10, 64)
  1971. if err != nil {
  1972. return group, fmt.Errorf("invalid upload bandwidth: %w", err)
  1973. }
  1974. bandwidthDL, err := strconv.ParseInt(r.Form.Get("download_bandwidth"), 10, 64)
  1975. if err != nil {
  1976. return group, fmt.Errorf("invalid download bandwidth: %w", err)
  1977. }
  1978. dataTransferUL, dataTransferDL, dataTransferTotal, err := getTransferLimits(r)
  1979. if err != nil {
  1980. return group, err
  1981. }
  1982. expiresIn, err := strconv.ParseInt(r.Form.Get("expires_in"), 10, 64)
  1983. if err != nil {
  1984. return group, fmt.Errorf("invalid expires in: %w", err)
  1985. }
  1986. fsConfig, err := getFsConfigFromPostFields(r)
  1987. if err != nil {
  1988. return group, err
  1989. }
  1990. filters, err := getFiltersFromUserPostFields(r)
  1991. if err != nil {
  1992. return group, err
  1993. }
  1994. group = dataprovider.Group{
  1995. BaseGroup: sdk.BaseGroup{
  1996. Name: r.Form.Get("name"),
  1997. Description: r.Form.Get("description"),
  1998. },
  1999. UserSettings: dataprovider.GroupUserSettings{
  2000. BaseGroupUserSettings: sdk.BaseGroupUserSettings{
  2001. HomeDir: r.Form.Get("home_dir"),
  2002. MaxSessions: maxSessions,
  2003. QuotaSize: quotaSize,
  2004. QuotaFiles: quotaFiles,
  2005. Permissions: getSubDirPermissionsFromPostFields(r),
  2006. UploadBandwidth: bandwidthUL,
  2007. DownloadBandwidth: bandwidthDL,
  2008. UploadDataTransfer: dataTransferUL,
  2009. DownloadDataTransfer: dataTransferDL,
  2010. TotalDataTransfer: dataTransferTotal,
  2011. ExpiresIn: int(expiresIn),
  2012. Filters: filters,
  2013. },
  2014. FsConfig: fsConfig,
  2015. },
  2016. VirtualFolders: getVirtualFoldersFromPostFields(r),
  2017. }
  2018. return group, nil
  2019. }
  2020. func getKeyValsFromPostFields(r *http.Request, key, val string) []dataprovider.KeyValue {
  2021. var res []dataprovider.KeyValue
  2022. for k := range r.Form {
  2023. if strings.HasPrefix(k, key) {
  2024. formKey := r.Form.Get(k)
  2025. idx := strings.TrimPrefix(k, key)
  2026. formVal := r.Form.Get(fmt.Sprintf("%s%s", val, idx))
  2027. if formKey != "" && formVal != "" {
  2028. res = append(res, dataprovider.KeyValue{
  2029. Key: formKey,
  2030. Value: formVal,
  2031. })
  2032. }
  2033. }
  2034. }
  2035. return res
  2036. }
  2037. func getFoldersRetentionFromPostFields(r *http.Request) ([]dataprovider.FolderRetention, error) {
  2038. var res []dataprovider.FolderRetention
  2039. for k := range r.Form {
  2040. if strings.HasPrefix(k, "folder_retention_path") {
  2041. folderPath := r.Form.Get(k)
  2042. if folderPath != "" {
  2043. idx := strings.TrimPrefix(k, "folder_retention_path")
  2044. retention, err := strconv.Atoi(r.Form.Get(fmt.Sprintf("folder_retention_val%s", idx)))
  2045. if err != nil {
  2046. return nil, fmt.Errorf("invalid retention for path %q: %w", folderPath, err)
  2047. }
  2048. options := r.Form[fmt.Sprintf("folder_retention_options%s", idx)]
  2049. res = append(res, dataprovider.FolderRetention{
  2050. Path: folderPath,
  2051. Retention: retention,
  2052. DeleteEmptyDirs: util.Contains(options, "1"),
  2053. IgnoreUserPermissions: util.Contains(options, "2"),
  2054. })
  2055. }
  2056. }
  2057. }
  2058. return res, nil
  2059. }
  2060. func getHTTPPartsFromPostFields(r *http.Request) []dataprovider.HTTPPart {
  2061. var result []dataprovider.HTTPPart
  2062. for k := range r.Form {
  2063. if strings.HasPrefix(k, "http_part_name") {
  2064. partName := r.Form.Get(k)
  2065. if partName != "" {
  2066. idx := strings.TrimPrefix(k, "http_part_name")
  2067. order, err := strconv.Atoi(idx)
  2068. if err != nil {
  2069. continue
  2070. }
  2071. filePath := r.Form.Get(fmt.Sprintf("http_part_file%s", idx))
  2072. body := r.Form.Get(fmt.Sprintf("http_part_body%s", idx))
  2073. concatHeaders := getSliceFromDelimitedValues(r.Form.Get(fmt.Sprintf("http_part_headers%s", idx)), "\n")
  2074. var headers []dataprovider.KeyValue
  2075. for _, h := range concatHeaders {
  2076. values := strings.SplitN(h, ":", 2)
  2077. if len(values) > 1 {
  2078. headers = append(headers, dataprovider.KeyValue{
  2079. Key: strings.TrimSpace(values[0]),
  2080. Value: strings.TrimSpace(values[1]),
  2081. })
  2082. }
  2083. }
  2084. result = append(result, dataprovider.HTTPPart{
  2085. Name: partName,
  2086. Filepath: filePath,
  2087. Headers: headers,
  2088. Body: body,
  2089. Order: order,
  2090. })
  2091. }
  2092. }
  2093. }
  2094. sort.Slice(result, func(i, j int) bool {
  2095. return result[i].Order < result[j].Order
  2096. })
  2097. return result
  2098. }
  2099. func getEventActionOptionsFromPostFields(r *http.Request) (dataprovider.BaseEventActionOptions, error) {
  2100. httpTimeout, err := strconv.Atoi(r.Form.Get("http_timeout"))
  2101. if err != nil {
  2102. return dataprovider.BaseEventActionOptions{}, fmt.Errorf("invalid http timeout: %w", err)
  2103. }
  2104. cmdTimeout, err := strconv.Atoi(r.Form.Get("cmd_timeout"))
  2105. if err != nil {
  2106. return dataprovider.BaseEventActionOptions{}, fmt.Errorf("invalid command timeout: %w", err)
  2107. }
  2108. foldersRetention, err := getFoldersRetentionFromPostFields(r)
  2109. if err != nil {
  2110. return dataprovider.BaseEventActionOptions{}, err
  2111. }
  2112. fsActionType, err := strconv.Atoi(r.Form.Get("fs_action_type"))
  2113. if err != nil {
  2114. return dataprovider.BaseEventActionOptions{}, fmt.Errorf("invalid fs action type: %w", err)
  2115. }
  2116. pwdExpirationThreshold, err := strconv.Atoi(r.Form.Get("pwd_expiration_threshold"))
  2117. if err != nil {
  2118. return dataprovider.BaseEventActionOptions{}, fmt.Errorf("invalid password expiration threshold: %w", err)
  2119. }
  2120. var emailAttachments []string
  2121. if r.Form.Get("email_attachments") != "" {
  2122. emailAttachments = getSliceFromDelimitedValues(r.Form.Get("email_attachments"), ",")
  2123. }
  2124. var cmdArgs []string
  2125. if r.Form.Get("cmd_arguments") != "" {
  2126. cmdArgs = getSliceFromDelimitedValues(r.Form.Get("cmd_arguments"), ",")
  2127. }
  2128. options := dataprovider.BaseEventActionOptions{
  2129. HTTPConfig: dataprovider.EventActionHTTPConfig{
  2130. Endpoint: r.Form.Get("http_endpoint"),
  2131. Username: r.Form.Get("http_username"),
  2132. Password: getSecretFromFormField(r, "http_password"),
  2133. Headers: getKeyValsFromPostFields(r, "http_header_key", "http_header_val"),
  2134. Timeout: httpTimeout,
  2135. SkipTLSVerify: r.Form.Get("http_skip_tls_verify") != "",
  2136. Method: r.Form.Get("http_method"),
  2137. QueryParameters: getKeyValsFromPostFields(r, "http_query_key", "http_query_val"),
  2138. Body: r.Form.Get("http_body"),
  2139. Parts: getHTTPPartsFromPostFields(r),
  2140. },
  2141. CmdConfig: dataprovider.EventActionCommandConfig{
  2142. Cmd: r.Form.Get("cmd_path"),
  2143. Args: cmdArgs,
  2144. Timeout: cmdTimeout,
  2145. EnvVars: getKeyValsFromPostFields(r, "cmd_env_key", "cmd_env_val"),
  2146. },
  2147. EmailConfig: dataprovider.EventActionEmailConfig{
  2148. Recipients: getSliceFromDelimitedValues(r.Form.Get("email_recipients"), ","),
  2149. Subject: r.Form.Get("email_subject"),
  2150. Body: r.Form.Get("email_body"),
  2151. Attachments: emailAttachments,
  2152. },
  2153. RetentionConfig: dataprovider.EventActionDataRetentionConfig{
  2154. Folders: foldersRetention,
  2155. },
  2156. FsConfig: dataprovider.EventActionFilesystemConfig{
  2157. Type: fsActionType,
  2158. Renames: getKeyValsFromPostFields(r, "fs_rename_source", "fs_rename_target"),
  2159. Deletes: getSliceFromDelimitedValues(r.Form.Get("fs_delete_paths"), ","),
  2160. MkDirs: getSliceFromDelimitedValues(r.Form.Get("fs_mkdir_paths"), ","),
  2161. Exist: getSliceFromDelimitedValues(r.Form.Get("fs_exist_paths"), ","),
  2162. Copy: getKeyValsFromPostFields(r, "fs_copy_source", "fs_copy_target"),
  2163. Compress: dataprovider.EventActionFsCompress{
  2164. Name: r.Form.Get("fs_compress_name"),
  2165. Paths: getSliceFromDelimitedValues(r.Form.Get("fs_compress_paths"), ","),
  2166. },
  2167. },
  2168. PwdExpirationConfig: dataprovider.EventActionPasswordExpiration{
  2169. Threshold: pwdExpirationThreshold,
  2170. },
  2171. }
  2172. return options, nil
  2173. }
  2174. func getEventActionFromPostFields(r *http.Request) (dataprovider.BaseEventAction, error) {
  2175. err := r.ParseForm()
  2176. if err != nil {
  2177. return dataprovider.BaseEventAction{}, err
  2178. }
  2179. actionType, err := strconv.Atoi(r.Form.Get("type"))
  2180. if err != nil {
  2181. return dataprovider.BaseEventAction{}, fmt.Errorf("invalid action type: %w", err)
  2182. }
  2183. options, err := getEventActionOptionsFromPostFields(r)
  2184. if err != nil {
  2185. return dataprovider.BaseEventAction{}, err
  2186. }
  2187. action := dataprovider.BaseEventAction{
  2188. Name: r.Form.Get("name"),
  2189. Description: r.Form.Get("description"),
  2190. Type: actionType,
  2191. Options: options,
  2192. }
  2193. return action, nil
  2194. }
  2195. func getEventRuleConditionsFromPostFields(r *http.Request) (dataprovider.EventConditions, error) {
  2196. var schedules []dataprovider.Schedule
  2197. var names, groupNames, roleNames, fsPaths []dataprovider.ConditionPattern
  2198. for k := range r.Form {
  2199. if strings.HasPrefix(k, "schedule_hour") {
  2200. hour := r.Form.Get(k)
  2201. if hour != "" {
  2202. idx := strings.TrimPrefix(k, "schedule_hour")
  2203. dayOfWeek := r.Form.Get(fmt.Sprintf("schedule_day_of_week%s", idx))
  2204. dayOfMonth := r.Form.Get(fmt.Sprintf("schedule_day_of_month%s", idx))
  2205. month := r.Form.Get(fmt.Sprintf("schedule_month%s", idx))
  2206. schedules = append(schedules, dataprovider.Schedule{
  2207. Hours: hour,
  2208. DayOfWeek: dayOfWeek,
  2209. DayOfMonth: dayOfMonth,
  2210. Month: month,
  2211. })
  2212. }
  2213. }
  2214. if strings.HasPrefix(k, "name_pattern") {
  2215. pattern := r.Form.Get(k)
  2216. if pattern != "" {
  2217. idx := strings.TrimPrefix(k, "name_pattern")
  2218. patternType := r.Form.Get(fmt.Sprintf("type_name_pattern%s", idx))
  2219. names = append(names, dataprovider.ConditionPattern{
  2220. Pattern: pattern,
  2221. InverseMatch: patternType == inversePatternType,
  2222. })
  2223. }
  2224. }
  2225. if strings.HasPrefix(k, "group_name_pattern") {
  2226. pattern := r.Form.Get(k)
  2227. if pattern != "" {
  2228. idx := strings.TrimPrefix(k, "group_name_pattern")
  2229. patternType := r.Form.Get(fmt.Sprintf("type_group_name_pattern%s", idx))
  2230. groupNames = append(groupNames, dataprovider.ConditionPattern{
  2231. Pattern: pattern,
  2232. InverseMatch: patternType == inversePatternType,
  2233. })
  2234. }
  2235. }
  2236. if strings.HasPrefix(k, "role_name_pattern") {
  2237. pattern := r.Form.Get(k)
  2238. if pattern != "" {
  2239. idx := strings.TrimPrefix(k, "role_name_pattern")
  2240. patternType := r.Form.Get(fmt.Sprintf("type_role_name_pattern%s", idx))
  2241. roleNames = append(roleNames, dataprovider.ConditionPattern{
  2242. Pattern: pattern,
  2243. InverseMatch: patternType == inversePatternType,
  2244. })
  2245. }
  2246. }
  2247. if strings.HasPrefix(k, "fs_path_pattern") {
  2248. pattern := r.Form.Get(k)
  2249. if pattern != "" {
  2250. idx := strings.TrimPrefix(k, "fs_path_pattern")
  2251. patternType := r.Form.Get(fmt.Sprintf("type_fs_path_pattern%s", idx))
  2252. fsPaths = append(fsPaths, dataprovider.ConditionPattern{
  2253. Pattern: pattern,
  2254. InverseMatch: patternType == inversePatternType,
  2255. })
  2256. }
  2257. }
  2258. }
  2259. minFileSize, err := util.ParseBytes(r.Form.Get("fs_min_size"))
  2260. if err != nil {
  2261. return dataprovider.EventConditions{}, fmt.Errorf("invalid min file size: %w", err)
  2262. }
  2263. maxFileSize, err := util.ParseBytes(r.Form.Get("fs_max_size"))
  2264. if err != nil {
  2265. return dataprovider.EventConditions{}, fmt.Errorf("invalid max file size: %w", err)
  2266. }
  2267. conditions := dataprovider.EventConditions{
  2268. FsEvents: r.Form["fs_events"],
  2269. ProviderEvents: r.Form["provider_events"],
  2270. Schedules: schedules,
  2271. Options: dataprovider.ConditionOptions{
  2272. Names: names,
  2273. GroupNames: groupNames,
  2274. RoleNames: roleNames,
  2275. FsPaths: fsPaths,
  2276. Protocols: r.Form["fs_protocols"],
  2277. ProviderObjects: r.Form["provider_objects"],
  2278. MinFileSize: minFileSize,
  2279. MaxFileSize: maxFileSize,
  2280. ConcurrentExecution: r.Form.Get("concurrent_execution") != "",
  2281. },
  2282. }
  2283. return conditions, nil
  2284. }
  2285. func getEventRuleActionsFromPostFields(r *http.Request) ([]dataprovider.EventAction, error) {
  2286. var actions []dataprovider.EventAction
  2287. for k := range r.Form {
  2288. if strings.HasPrefix(k, "action_name") {
  2289. name := r.Form.Get(k)
  2290. if name != "" {
  2291. idx := strings.TrimPrefix(k, "action_name")
  2292. order, err := strconv.Atoi(r.Form.Get(fmt.Sprintf("action_order%s", idx)))
  2293. if err != nil {
  2294. return actions, fmt.Errorf("invalid order: %w", err)
  2295. }
  2296. options := r.Form[fmt.Sprintf("action_options%s", idx)]
  2297. actions = append(actions, dataprovider.EventAction{
  2298. BaseEventAction: dataprovider.BaseEventAction{
  2299. Name: name,
  2300. },
  2301. Order: order + 1,
  2302. Options: dataprovider.EventActionOptions{
  2303. IsFailureAction: util.Contains(options, "1"),
  2304. StopOnFailure: util.Contains(options, "2"),
  2305. ExecuteSync: util.Contains(options, "3"),
  2306. },
  2307. })
  2308. }
  2309. }
  2310. }
  2311. return actions, nil
  2312. }
  2313. func getEventRuleFromPostFields(r *http.Request) (dataprovider.EventRule, error) {
  2314. err := r.ParseForm()
  2315. if err != nil {
  2316. return dataprovider.EventRule{}, err
  2317. }
  2318. status, err := strconv.Atoi(r.Form.Get("status"))
  2319. if err != nil {
  2320. return dataprovider.EventRule{}, fmt.Errorf("invalid status: %w", err)
  2321. }
  2322. trigger, err := strconv.Atoi(r.Form.Get("trigger"))
  2323. if err != nil {
  2324. return dataprovider.EventRule{}, fmt.Errorf("invalid trigger: %w", err)
  2325. }
  2326. conditions, err := getEventRuleConditionsFromPostFields(r)
  2327. if err != nil {
  2328. return dataprovider.EventRule{}, err
  2329. }
  2330. actions, err := getEventRuleActionsFromPostFields(r)
  2331. if err != nil {
  2332. return dataprovider.EventRule{}, err
  2333. }
  2334. rule := dataprovider.EventRule{
  2335. Name: r.Form.Get("name"),
  2336. Status: status,
  2337. Description: r.Form.Get("description"),
  2338. Trigger: trigger,
  2339. Conditions: conditions,
  2340. Actions: actions,
  2341. }
  2342. return rule, nil
  2343. }
  2344. func getRoleFromPostFields(r *http.Request) (dataprovider.Role, error) {
  2345. err := r.ParseForm()
  2346. if err != nil {
  2347. return dataprovider.Role{}, err
  2348. }
  2349. return dataprovider.Role{
  2350. Name: r.Form.Get("name"),
  2351. Description: r.Form.Get("description"),
  2352. }, nil
  2353. }
  2354. func getIPListEntryFromPostFields(r *http.Request, listType dataprovider.IPListType) (dataprovider.IPListEntry, error) {
  2355. err := r.ParseForm()
  2356. if err != nil {
  2357. return dataprovider.IPListEntry{}, err
  2358. }
  2359. var mode int
  2360. if listType == dataprovider.IPListTypeDefender {
  2361. mode, err = strconv.Atoi(r.Form.Get("mode"))
  2362. if err != nil {
  2363. return dataprovider.IPListEntry{}, fmt.Errorf("invalid mode: %w", err)
  2364. }
  2365. } else {
  2366. mode = 1
  2367. }
  2368. protocols := 0
  2369. for _, proto := range r.Form["protocols"] {
  2370. p, err := strconv.Atoi(proto)
  2371. if err == nil {
  2372. protocols += p
  2373. }
  2374. }
  2375. return dataprovider.IPListEntry{
  2376. IPOrNet: r.Form.Get("ipornet"),
  2377. Mode: mode,
  2378. Protocols: protocols,
  2379. Description: r.Form.Get("description"),
  2380. }, nil
  2381. }
  2382. func getSFTPConfigsFromPostFields(r *http.Request) *dataprovider.SFTPDConfigs {
  2383. return &dataprovider.SFTPDConfigs{
  2384. HostKeyAlgos: r.Form["sftp_host_key_algos"],
  2385. Moduli: getSliceFromDelimitedValues(r.Form.Get("sftp_moduli"), ","),
  2386. KexAlgorithms: r.Form["sftp_kex_algos"],
  2387. Ciphers: r.Form["sftp_ciphers"],
  2388. MACs: r.Form["sftp_macs"],
  2389. }
  2390. }
  2391. func getSMTPConfigsFromPostFields(r *http.Request) *dataprovider.SMTPConfigs {
  2392. port, err := strconv.Atoi(r.Form.Get("smtp_port"))
  2393. if err != nil {
  2394. port = 0
  2395. }
  2396. authType, err := strconv.Atoi(r.Form.Get("smtp_auth"))
  2397. if err != nil {
  2398. authType = 0
  2399. }
  2400. encryption, err := strconv.Atoi(r.Form.Get("smtp_encryption"))
  2401. if err != nil {
  2402. encryption = 0
  2403. }
  2404. return &dataprovider.SMTPConfigs{
  2405. Host: r.Form.Get("smtp_host"),
  2406. Port: port,
  2407. From: r.Form.Get("smtp_from"),
  2408. User: r.Form.Get("smtp_username"),
  2409. Password: getSecretFromFormField(r, "smtp_password"),
  2410. AuthType: authType,
  2411. Encryption: encryption,
  2412. Domain: r.Form.Get("smtp_domain"),
  2413. }
  2414. }
  2415. func (s *httpdServer) handleWebAdminForgotPwd(w http.ResponseWriter, r *http.Request) {
  2416. r.Body = http.MaxBytesReader(w, r.Body, maxRequestSize)
  2417. if !smtp.IsEnabled() {
  2418. s.renderNotFoundPage(w, r, errors.New("this page does not exist"))
  2419. return
  2420. }
  2421. s.renderForgotPwdPage(w, "", util.GetIPFromRemoteAddress(r.RemoteAddr))
  2422. }
  2423. func (s *httpdServer) handleWebAdminForgotPwdPost(w http.ResponseWriter, r *http.Request) {
  2424. r.Body = http.MaxBytesReader(w, r.Body, maxRequestSize)
  2425. ipAddr := util.GetIPFromRemoteAddress(r.RemoteAddr)
  2426. err := r.ParseForm()
  2427. if err != nil {
  2428. s.renderForgotPwdPage(w, err.Error(), ipAddr)
  2429. return
  2430. }
  2431. if err := verifyCSRFToken(r.Form.Get(csrfFormToken), ipAddr); err != nil {
  2432. s.renderForbiddenPage(w, r, err.Error())
  2433. return
  2434. }
  2435. err = handleForgotPassword(r, r.Form.Get("username"), true)
  2436. if err != nil {
  2437. if e, ok := err.(*util.ValidationError); ok {
  2438. s.renderForgotPwdPage(w, e.GetErrorString(), ipAddr)
  2439. return
  2440. }
  2441. s.renderForgotPwdPage(w, err.Error(), ipAddr)
  2442. return
  2443. }
  2444. http.Redirect(w, r, webAdminResetPwdPath, http.StatusFound)
  2445. }
  2446. func (s *httpdServer) handleWebAdminPasswordReset(w http.ResponseWriter, r *http.Request) {
  2447. r.Body = http.MaxBytesReader(w, r.Body, maxLoginBodySize)
  2448. if !smtp.IsEnabled() {
  2449. s.renderNotFoundPage(w, r, errors.New("this page does not exist"))
  2450. return
  2451. }
  2452. s.renderResetPwdPage(w, "", util.GetIPFromRemoteAddress(r.RemoteAddr))
  2453. }
  2454. func (s *httpdServer) handleWebAdminTwoFactor(w http.ResponseWriter, r *http.Request) {
  2455. r.Body = http.MaxBytesReader(w, r.Body, maxRequestSize)
  2456. s.renderTwoFactorPage(w, "", util.GetIPFromRemoteAddress(r.RemoteAddr))
  2457. }
  2458. func (s *httpdServer) handleWebAdminTwoFactorRecovery(w http.ResponseWriter, r *http.Request) {
  2459. r.Body = http.MaxBytesReader(w, r.Body, maxRequestSize)
  2460. s.renderTwoFactorRecoveryPage(w, "", util.GetIPFromRemoteAddress(r.RemoteAddr))
  2461. }
  2462. func (s *httpdServer) handleWebAdminMFA(w http.ResponseWriter, r *http.Request) {
  2463. r.Body = http.MaxBytesReader(w, r.Body, maxRequestSize)
  2464. s.renderMFAPage(w, r)
  2465. }
  2466. func (s *httpdServer) handleWebAdminProfile(w http.ResponseWriter, r *http.Request) {
  2467. r.Body = http.MaxBytesReader(w, r.Body, maxRequestSize)
  2468. s.renderProfilePage(w, r, "")
  2469. }
  2470. func (s *httpdServer) handleWebAdminChangePwd(w http.ResponseWriter, r *http.Request) {
  2471. r.Body = http.MaxBytesReader(w, r.Body, maxRequestSize)
  2472. s.renderChangePasswordPage(w, r, "")
  2473. }
  2474. func (s *httpdServer) handleWebAdminProfilePost(w http.ResponseWriter, r *http.Request) {
  2475. r.Body = http.MaxBytesReader(w, r.Body, maxRequestSize)
  2476. err := r.ParseForm()
  2477. if err != nil {
  2478. s.renderProfilePage(w, r, err.Error())
  2479. return
  2480. }
  2481. ipAddr := util.GetIPFromRemoteAddress(r.RemoteAddr)
  2482. if err := verifyCSRFToken(r.Form.Get(csrfFormToken), ipAddr); err != nil {
  2483. s.renderForbiddenPage(w, r, err.Error())
  2484. return
  2485. }
  2486. claims, err := getTokenClaims(r)
  2487. if err != nil || claims.Username == "" {
  2488. s.renderProfilePage(w, r, "Invalid token claims")
  2489. return
  2490. }
  2491. admin, err := dataprovider.AdminExists(claims.Username)
  2492. if err != nil {
  2493. s.renderProfilePage(w, r, err.Error())
  2494. return
  2495. }
  2496. admin.Filters.AllowAPIKeyAuth = r.Form.Get("allow_api_key_auth") != ""
  2497. admin.Email = r.Form.Get("email")
  2498. admin.Description = r.Form.Get("description")
  2499. err = dataprovider.UpdateAdmin(&admin, dataprovider.ActionExecutorSelf, ipAddr, admin.Role)
  2500. if err != nil {
  2501. s.renderProfilePage(w, r, err.Error())
  2502. return
  2503. }
  2504. s.renderMessagePage(w, r, "Profile updated", "", http.StatusOK, nil,
  2505. "Your profile has been successfully updated")
  2506. }
  2507. func (s *httpdServer) handleWebMaintenance(w http.ResponseWriter, r *http.Request) {
  2508. r.Body = http.MaxBytesReader(w, r.Body, maxRequestSize)
  2509. s.renderMaintenancePage(w, r, "")
  2510. }
  2511. func (s *httpdServer) handleWebRestore(w http.ResponseWriter, r *http.Request) {
  2512. r.Body = http.MaxBytesReader(w, r.Body, MaxRestoreSize)
  2513. claims, err := getTokenClaims(r)
  2514. if err != nil || claims.Username == "" {
  2515. s.renderBadRequestPage(w, r, errors.New("invalid token claims"))
  2516. return
  2517. }
  2518. err = r.ParseMultipartForm(MaxRestoreSize)
  2519. if err != nil {
  2520. s.renderMaintenancePage(w, r, err.Error())
  2521. return
  2522. }
  2523. defer r.MultipartForm.RemoveAll() //nolint:errcheck
  2524. ipAddr := util.GetIPFromRemoteAddress(r.RemoteAddr)
  2525. if err := verifyCSRFToken(r.Form.Get(csrfFormToken), ipAddr); err != nil {
  2526. s.renderForbiddenPage(w, r, err.Error())
  2527. return
  2528. }
  2529. restoreMode, err := strconv.Atoi(r.Form.Get("mode"))
  2530. if err != nil {
  2531. s.renderMaintenancePage(w, r, err.Error())
  2532. return
  2533. }
  2534. scanQuota, err := strconv.Atoi(r.Form.Get("quota"))
  2535. if err != nil {
  2536. s.renderMaintenancePage(w, r, err.Error())
  2537. return
  2538. }
  2539. backupFile, _, err := r.FormFile("backup_file")
  2540. if err != nil {
  2541. s.renderMaintenancePage(w, r, err.Error())
  2542. return
  2543. }
  2544. defer backupFile.Close()
  2545. backupContent, err := io.ReadAll(backupFile)
  2546. if err != nil || len(backupContent) == 0 {
  2547. if len(backupContent) == 0 {
  2548. err = errors.New("backup file size must be greater than 0")
  2549. }
  2550. s.renderMaintenancePage(w, r, err.Error())
  2551. return
  2552. }
  2553. if err := restoreBackup(backupContent, "", scanQuota, restoreMode, claims.Username, ipAddr, claims.Role); err != nil {
  2554. s.renderMaintenancePage(w, r, err.Error())
  2555. return
  2556. }
  2557. s.renderMessagePage(w, r, "Data restored", "", http.StatusOK, nil, "Your backup was successfully restored")
  2558. }
  2559. func (s *httpdServer) handleGetWebAdmins(w http.ResponseWriter, r *http.Request) {
  2560. r.Body = http.MaxBytesReader(w, r.Body, maxRequestSize)
  2561. limit := defaultQueryLimit
  2562. if _, ok := r.URL.Query()["qlimit"]; ok {
  2563. var err error
  2564. limit, err = strconv.Atoi(r.URL.Query().Get("qlimit"))
  2565. if err != nil {
  2566. limit = defaultQueryLimit
  2567. }
  2568. }
  2569. admins := make([]dataprovider.Admin, 0, limit)
  2570. for {
  2571. a, err := dataprovider.GetAdmins(limit, len(admins), dataprovider.OrderASC)
  2572. if err != nil {
  2573. s.renderInternalServerErrorPage(w, r, err)
  2574. return
  2575. }
  2576. admins = append(admins, a...)
  2577. if len(a) < limit {
  2578. break
  2579. }
  2580. }
  2581. data := adminsPage{
  2582. basePage: s.getBasePageData(pageAdminsTitle, webAdminsPath, r),
  2583. Admins: admins,
  2584. }
  2585. renderAdminTemplate(w, templateAdmins, data)
  2586. }
  2587. func (s *httpdServer) handleWebAdminSetupGet(w http.ResponseWriter, r *http.Request) {
  2588. r.Body = http.MaxBytesReader(w, r.Body, maxLoginBodySize)
  2589. if dataprovider.HasAdmin() {
  2590. http.Redirect(w, r, webAdminLoginPath, http.StatusFound)
  2591. return
  2592. }
  2593. s.renderAdminSetupPage(w, r, "", "")
  2594. }
  2595. func (s *httpdServer) handleWebAddAdminGet(w http.ResponseWriter, r *http.Request) {
  2596. r.Body = http.MaxBytesReader(w, r.Body, maxRequestSize)
  2597. admin := &dataprovider.Admin{
  2598. Status: 1,
  2599. Permissions: []string{dataprovider.PermAdminAny},
  2600. }
  2601. s.renderAddUpdateAdminPage(w, r, admin, "", true)
  2602. }
  2603. func (s *httpdServer) handleWebUpdateAdminGet(w http.ResponseWriter, r *http.Request) {
  2604. r.Body = http.MaxBytesReader(w, r.Body, maxRequestSize)
  2605. username := getURLParam(r, "username")
  2606. admin, err := dataprovider.AdminExists(username)
  2607. if err == nil {
  2608. s.renderAddUpdateAdminPage(w, r, &admin, "", false)
  2609. } else if errors.Is(err, util.ErrNotFound) {
  2610. s.renderNotFoundPage(w, r, err)
  2611. } else {
  2612. s.renderInternalServerErrorPage(w, r, err)
  2613. }
  2614. }
  2615. func (s *httpdServer) handleWebAddAdminPost(w http.ResponseWriter, r *http.Request) {
  2616. r.Body = http.MaxBytesReader(w, r.Body, maxRequestSize)
  2617. claims, err := getTokenClaims(r)
  2618. if err != nil || claims.Username == "" {
  2619. s.renderBadRequestPage(w, r, errors.New("invalid token claims"))
  2620. return
  2621. }
  2622. admin, err := getAdminFromPostFields(r)
  2623. if err != nil {
  2624. s.renderAddUpdateAdminPage(w, r, &admin, err.Error(), true)
  2625. return
  2626. }
  2627. if admin.Password == "" && s.binding.isWebAdminLoginFormDisabled() {
  2628. admin.Password = util.GenerateUniqueID()
  2629. }
  2630. ipAddr := util.GetIPFromRemoteAddress(r.RemoteAddr)
  2631. if err := verifyCSRFToken(r.Form.Get(csrfFormToken), ipAddr); err != nil {
  2632. s.renderForbiddenPage(w, r, err.Error())
  2633. return
  2634. }
  2635. err = dataprovider.AddAdmin(&admin, claims.Username, ipAddr, claims.Role)
  2636. if err != nil {
  2637. s.renderAddUpdateAdminPage(w, r, &admin, err.Error(), true)
  2638. return
  2639. }
  2640. http.Redirect(w, r, webAdminsPath, http.StatusSeeOther)
  2641. }
  2642. func (s *httpdServer) handleWebUpdateAdminPost(w http.ResponseWriter, r *http.Request) {
  2643. r.Body = http.MaxBytesReader(w, r.Body, maxRequestSize)
  2644. username := getURLParam(r, "username")
  2645. admin, err := dataprovider.AdminExists(username)
  2646. if errors.Is(err, util.ErrNotFound) {
  2647. s.renderNotFoundPage(w, r, err)
  2648. return
  2649. } else if err != nil {
  2650. s.renderInternalServerErrorPage(w, r, err)
  2651. return
  2652. }
  2653. updatedAdmin, err := getAdminFromPostFields(r)
  2654. if err != nil {
  2655. s.renderAddUpdateAdminPage(w, r, &updatedAdmin, err.Error(), false)
  2656. return
  2657. }
  2658. ipAddr := util.GetIPFromRemoteAddress(r.RemoteAddr)
  2659. if err := verifyCSRFToken(r.Form.Get(csrfFormToken), ipAddr); err != nil {
  2660. s.renderForbiddenPage(w, r, err.Error())
  2661. return
  2662. }
  2663. updatedAdmin.ID = admin.ID
  2664. updatedAdmin.Username = admin.Username
  2665. if updatedAdmin.Password == "" {
  2666. updatedAdmin.Password = admin.Password
  2667. }
  2668. updatedAdmin.Filters.TOTPConfig = admin.Filters.TOTPConfig
  2669. updatedAdmin.Filters.RecoveryCodes = admin.Filters.RecoveryCodes
  2670. claims, err := getTokenClaims(r)
  2671. if err != nil || claims.Username == "" {
  2672. s.renderAddUpdateAdminPage(w, r, &updatedAdmin, "Invalid token claims", false)
  2673. return
  2674. }
  2675. if username == claims.Username {
  2676. if claims.isCriticalPermRemoved(updatedAdmin.Permissions) {
  2677. s.renderAddUpdateAdminPage(w, r, &updatedAdmin, "You cannot remove these permissions to yourself", false)
  2678. return
  2679. }
  2680. if updatedAdmin.Status == 0 {
  2681. s.renderAddUpdateAdminPage(w, r, &updatedAdmin, "You cannot disable yourself", false)
  2682. return
  2683. }
  2684. if updatedAdmin.Role != claims.Role {
  2685. s.renderAddUpdateAdminPage(w, r, &updatedAdmin, "You cannot add/change your role", false)
  2686. return
  2687. }
  2688. }
  2689. err = dataprovider.UpdateAdmin(&updatedAdmin, claims.Username, ipAddr, claims.Role)
  2690. if err != nil {
  2691. s.renderAddUpdateAdminPage(w, r, &updatedAdmin, err.Error(), false)
  2692. return
  2693. }
  2694. http.Redirect(w, r, webAdminsPath, http.StatusSeeOther)
  2695. }
  2696. func (s *httpdServer) handleWebDefenderPage(w http.ResponseWriter, r *http.Request) {
  2697. r.Body = http.MaxBytesReader(w, r.Body, maxRequestSize)
  2698. data := defenderHostsPage{
  2699. basePage: s.getBasePageData(pageDefenderTitle, webDefenderPath, r),
  2700. DefenderHostsURL: webDefenderHostsPath,
  2701. }
  2702. renderAdminTemplate(w, templateDefender, data)
  2703. }
  2704. func (s *httpdServer) handleGetWebUsers(w http.ResponseWriter, r *http.Request) {
  2705. r.Body = http.MaxBytesReader(w, r.Body, maxRequestSize)
  2706. claims, err := getTokenClaims(r)
  2707. if err != nil || claims.Username == "" {
  2708. s.renderBadRequestPage(w, r, errors.New("invalid token claims"))
  2709. return
  2710. }
  2711. var limit int
  2712. if _, ok := r.URL.Query()["qlimit"]; ok {
  2713. var err error
  2714. limit, err = strconv.Atoi(r.URL.Query().Get("qlimit"))
  2715. if err != nil {
  2716. limit = defaultQueryLimit
  2717. }
  2718. } else {
  2719. limit = defaultQueryLimit
  2720. }
  2721. users := make([]dataprovider.User, 0, limit)
  2722. for {
  2723. u, err := dataprovider.GetUsers(limit, len(users), dataprovider.OrderASC, claims.Role)
  2724. if err != nil {
  2725. s.renderInternalServerErrorPage(w, r, err)
  2726. return
  2727. }
  2728. users = append(users, u...)
  2729. if len(u) < limit {
  2730. break
  2731. }
  2732. }
  2733. data := usersPage{
  2734. basePage: s.getBasePageData(pageUsersTitle, webUsersPath, r),
  2735. Users: users,
  2736. }
  2737. renderAdminTemplate(w, templateUsers, data)
  2738. }
  2739. func (s *httpdServer) handleWebTemplateFolderGet(w http.ResponseWriter, r *http.Request) {
  2740. r.Body = http.MaxBytesReader(w, r.Body, maxRequestSize)
  2741. if r.URL.Query().Get("from") != "" {
  2742. name := r.URL.Query().Get("from")
  2743. folder, err := dataprovider.GetFolderByName(name)
  2744. if err == nil {
  2745. folder.FsConfig.SetEmptySecrets()
  2746. s.renderFolderPage(w, r, folder, folderPageModeTemplate, "")
  2747. } else if errors.Is(err, util.ErrNotFound) {
  2748. s.renderNotFoundPage(w, r, err)
  2749. } else {
  2750. s.renderInternalServerErrorPage(w, r, err)
  2751. }
  2752. } else {
  2753. folder := vfs.BaseVirtualFolder{}
  2754. s.renderFolderPage(w, r, folder, folderPageModeTemplate, "")
  2755. }
  2756. }
  2757. func (s *httpdServer) handleWebTemplateFolderPost(w http.ResponseWriter, r *http.Request) {
  2758. r.Body = http.MaxBytesReader(w, r.Body, maxRequestSize)
  2759. claims, err := getTokenClaims(r)
  2760. if err != nil || claims.Username == "" {
  2761. s.renderBadRequestPage(w, r, errors.New("invalid token claims"))
  2762. return
  2763. }
  2764. templateFolder := vfs.BaseVirtualFolder{}
  2765. err = r.ParseMultipartForm(maxRequestSize)
  2766. if err != nil {
  2767. s.renderMessagePage(w, r, "Error parsing folders fields", "", http.StatusBadRequest, err, "")
  2768. return
  2769. }
  2770. defer r.MultipartForm.RemoveAll() //nolint:errcheck
  2771. ipAddr := util.GetIPFromRemoteAddress(r.RemoteAddr)
  2772. if err := verifyCSRFToken(r.Form.Get(csrfFormToken), ipAddr); err != nil {
  2773. s.renderForbiddenPage(w, r, err.Error())
  2774. return
  2775. }
  2776. templateFolder.MappedPath = r.Form.Get("mapped_path")
  2777. templateFolder.Description = r.Form.Get("description")
  2778. fsConfig, err := getFsConfigFromPostFields(r)
  2779. if err != nil {
  2780. s.renderMessagePage(w, r, "Error parsing folders fields", "", http.StatusBadRequest, err, "")
  2781. return
  2782. }
  2783. templateFolder.FsConfig = fsConfig
  2784. var dump dataprovider.BackupData
  2785. dump.Version = dataprovider.DumpVersion
  2786. foldersFields := getFoldersForTemplate(r)
  2787. for _, tmpl := range foldersFields {
  2788. f := getFolderFromTemplate(templateFolder, tmpl)
  2789. if err := dataprovider.ValidateFolder(&f); err != nil {
  2790. s.renderMessagePage(w, r, "Folder validation error", fmt.Sprintf("Error validating folder %#v", f.Name),
  2791. http.StatusBadRequest, err, "")
  2792. return
  2793. }
  2794. dump.Folders = append(dump.Folders, f)
  2795. }
  2796. if len(dump.Folders) == 0 {
  2797. s.renderMessagePage(w, r, "No folders defined", "No valid folders defined, unable to complete the requested action",
  2798. http.StatusBadRequest, nil, "")
  2799. return
  2800. }
  2801. if r.Form.Get("form_action") == "export_from_template" {
  2802. w.Header().Set("Content-Disposition", fmt.Sprintf("attachment; filename=\"sftpgo-%v-folders-from-template.json\"",
  2803. len(dump.Folders)))
  2804. render.JSON(w, r, dump)
  2805. return
  2806. }
  2807. if err = RestoreFolders(dump.Folders, "", 1, 0, claims.Username, ipAddr, claims.Role); err != nil {
  2808. s.renderMessagePage(w, r, "Unable to save folders", "Cannot save the defined folders:",
  2809. getRespStatus(err), err, "")
  2810. return
  2811. }
  2812. http.Redirect(w, r, webFoldersPath, http.StatusSeeOther)
  2813. }
  2814. func (s *httpdServer) handleWebTemplateUserGet(w http.ResponseWriter, r *http.Request) {
  2815. r.Body = http.MaxBytesReader(w, r.Body, maxRequestSize)
  2816. tokenAdmin := getAdminFromToken(r)
  2817. admin, err := dataprovider.AdminExists(tokenAdmin.Username)
  2818. if err != nil {
  2819. s.renderInternalServerErrorPage(w, r, fmt.Errorf("unable to get the admin %q: %w", tokenAdmin.Username, err))
  2820. return
  2821. }
  2822. if r.URL.Query().Get("from") != "" {
  2823. username := r.URL.Query().Get("from")
  2824. user, err := dataprovider.UserExists(username, admin.Role)
  2825. if err == nil {
  2826. user.SetEmptySecrets()
  2827. user.PublicKeys = nil
  2828. user.Email = ""
  2829. user.Description = ""
  2830. if user.ExpirationDate == 0 && admin.Filters.Preferences.DefaultUsersExpiration > 0 {
  2831. user.ExpirationDate = util.GetTimeAsMsSinceEpoch(time.Now().Add(24 * time.Hour * time.Duration(admin.Filters.Preferences.DefaultUsersExpiration)))
  2832. }
  2833. s.renderUserPage(w, r, &user, userPageModeTemplate, "", &admin)
  2834. } else if errors.Is(err, util.ErrNotFound) {
  2835. s.renderNotFoundPage(w, r, err)
  2836. } else {
  2837. s.renderInternalServerErrorPage(w, r, err)
  2838. }
  2839. } else {
  2840. user := dataprovider.User{BaseUser: sdk.BaseUser{
  2841. Status: 1,
  2842. Permissions: map[string][]string{
  2843. "/": {dataprovider.PermAny},
  2844. },
  2845. }}
  2846. if admin.Filters.Preferences.DefaultUsersExpiration > 0 {
  2847. user.ExpirationDate = util.GetTimeAsMsSinceEpoch(time.Now().Add(24 * time.Hour * time.Duration(admin.Filters.Preferences.DefaultUsersExpiration)))
  2848. }
  2849. s.renderUserPage(w, r, &user, userPageModeTemplate, "", &admin)
  2850. }
  2851. }
  2852. func (s *httpdServer) handleWebTemplateUserPost(w http.ResponseWriter, r *http.Request) {
  2853. r.Body = http.MaxBytesReader(w, r.Body, maxRequestSize)
  2854. claims, err := getTokenClaims(r)
  2855. if err != nil || claims.Username == "" {
  2856. s.renderBadRequestPage(w, r, errors.New("invalid token claims"))
  2857. return
  2858. }
  2859. templateUser, err := getUserFromPostFields(r)
  2860. if err != nil {
  2861. s.renderMessagePage(w, r, "Error parsing user fields", "", http.StatusBadRequest, err, "")
  2862. return
  2863. }
  2864. ipAddr := util.GetIPFromRemoteAddress(r.RemoteAddr)
  2865. if err := verifyCSRFToken(r.Form.Get(csrfFormToken), ipAddr); err != nil {
  2866. s.renderForbiddenPage(w, r, err.Error())
  2867. return
  2868. }
  2869. var dump dataprovider.BackupData
  2870. dump.Version = dataprovider.DumpVersion
  2871. userTmplFields := getUsersForTemplate(r)
  2872. for _, tmpl := range userTmplFields {
  2873. u := getUserFromTemplate(templateUser, tmpl)
  2874. if err := dataprovider.ValidateUser(&u); err != nil {
  2875. s.renderMessagePage(w, r, "User validation error", fmt.Sprintf("Error validating user %#v", u.Username),
  2876. http.StatusBadRequest, err, "")
  2877. return
  2878. }
  2879. // to create a template the "manage_system" permission is required, so role admins cannot use
  2880. // this method, we don't need to force the role
  2881. dump.Users = append(dump.Users, u)
  2882. for _, folder := range u.VirtualFolders {
  2883. if !dump.HasFolder(folder.Name) {
  2884. dump.Folders = append(dump.Folders, folder.BaseVirtualFolder)
  2885. }
  2886. }
  2887. }
  2888. if len(dump.Users) == 0 {
  2889. s.renderMessagePage(w, r, "No users defined", "No valid users defined, unable to complete the requested action",
  2890. http.StatusBadRequest, nil, "")
  2891. return
  2892. }
  2893. if r.Form.Get("form_action") == "export_from_template" {
  2894. w.Header().Set("Content-Disposition", fmt.Sprintf("attachment; filename=\"sftpgo-%v-users-from-template.json\"",
  2895. len(dump.Users)))
  2896. render.JSON(w, r, dump)
  2897. return
  2898. }
  2899. if err = RestoreUsers(dump.Users, "", 1, 0, claims.Username, ipAddr, claims.Role); err != nil {
  2900. s.renderMessagePage(w, r, "Unable to save users", "Cannot save the defined users:",
  2901. getRespStatus(err), err, "")
  2902. return
  2903. }
  2904. http.Redirect(w, r, webUsersPath, http.StatusSeeOther)
  2905. }
  2906. func (s *httpdServer) handleWebAddUserGet(w http.ResponseWriter, r *http.Request) {
  2907. r.Body = http.MaxBytesReader(w, r.Body, maxRequestSize)
  2908. tokenAdmin := getAdminFromToken(r)
  2909. admin, err := dataprovider.AdminExists(tokenAdmin.Username)
  2910. if err != nil {
  2911. s.renderInternalServerErrorPage(w, r, fmt.Errorf("unable to get the admin %q: %w", tokenAdmin.Username, err))
  2912. return
  2913. }
  2914. user := dataprovider.User{BaseUser: sdk.BaseUser{
  2915. Status: 1,
  2916. Permissions: map[string][]string{
  2917. "/": {dataprovider.PermAny},
  2918. }},
  2919. }
  2920. if admin.Filters.Preferences.DefaultUsersExpiration > 0 {
  2921. user.ExpirationDate = util.GetTimeAsMsSinceEpoch(time.Now().Add(24 * time.Hour * time.Duration(admin.Filters.Preferences.DefaultUsersExpiration)))
  2922. }
  2923. s.renderUserPage(w, r, &user, userPageModeAdd, "", &admin)
  2924. }
  2925. func (s *httpdServer) handleWebUpdateUserGet(w http.ResponseWriter, r *http.Request) {
  2926. r.Body = http.MaxBytesReader(w, r.Body, maxRequestSize)
  2927. claims, err := getTokenClaims(r)
  2928. if err != nil || claims.Username == "" {
  2929. s.renderBadRequestPage(w, r, errors.New("invalid token claims"))
  2930. return
  2931. }
  2932. username := getURLParam(r, "username")
  2933. user, err := dataprovider.UserExists(username, claims.Role)
  2934. if err == nil {
  2935. s.renderUserPage(w, r, &user, userPageModeUpdate, "", nil)
  2936. } else if errors.Is(err, util.ErrNotFound) {
  2937. s.renderNotFoundPage(w, r, err)
  2938. } else {
  2939. s.renderInternalServerErrorPage(w, r, err)
  2940. }
  2941. }
  2942. func (s *httpdServer) handleWebAddUserPost(w http.ResponseWriter, r *http.Request) {
  2943. r.Body = http.MaxBytesReader(w, r.Body, maxRequestSize)
  2944. claims, err := getTokenClaims(r)
  2945. if err != nil || claims.Username == "" {
  2946. s.renderBadRequestPage(w, r, errors.New("invalid token claims"))
  2947. return
  2948. }
  2949. user, err := getUserFromPostFields(r)
  2950. if err != nil {
  2951. s.renderUserPage(w, r, &user, userPageModeAdd, err.Error(), nil)
  2952. return
  2953. }
  2954. ipAddr := util.GetIPFromRemoteAddress(r.RemoteAddr)
  2955. if err := verifyCSRFToken(r.Form.Get(csrfFormToken), ipAddr); err != nil {
  2956. s.renderForbiddenPage(w, r, err.Error())
  2957. return
  2958. }
  2959. user = getUserFromTemplate(user, userTemplateFields{
  2960. Username: user.Username,
  2961. Password: user.Password,
  2962. PublicKeys: user.PublicKeys,
  2963. })
  2964. if claims.Role != "" {
  2965. user.Role = claims.Role
  2966. }
  2967. user.Filters.RecoveryCodes = nil
  2968. user.Filters.TOTPConfig = dataprovider.UserTOTPConfig{
  2969. Enabled: false,
  2970. }
  2971. err = dataprovider.AddUser(&user, claims.Username, ipAddr, claims.Role)
  2972. if err != nil {
  2973. s.renderUserPage(w, r, &user, userPageModeAdd, err.Error(), nil)
  2974. return
  2975. }
  2976. http.Redirect(w, r, webUsersPath, http.StatusSeeOther)
  2977. }
  2978. func (s *httpdServer) handleWebUpdateUserPost(w http.ResponseWriter, r *http.Request) {
  2979. r.Body = http.MaxBytesReader(w, r.Body, maxRequestSize)
  2980. claims, err := getTokenClaims(r)
  2981. if err != nil || claims.Username == "" {
  2982. s.renderBadRequestPage(w, r, errors.New("invalid token claims"))
  2983. return
  2984. }
  2985. username := getURLParam(r, "username")
  2986. user, err := dataprovider.UserExists(username, claims.Role)
  2987. if errors.Is(err, util.ErrNotFound) {
  2988. s.renderNotFoundPage(w, r, err)
  2989. return
  2990. } else if err != nil {
  2991. s.renderInternalServerErrorPage(w, r, err)
  2992. return
  2993. }
  2994. updatedUser, err := getUserFromPostFields(r)
  2995. if err != nil {
  2996. s.renderUserPage(w, r, &user, userPageModeUpdate, err.Error(), nil)
  2997. return
  2998. }
  2999. ipAddr := util.GetIPFromRemoteAddress(r.RemoteAddr)
  3000. if err := verifyCSRFToken(r.Form.Get(csrfFormToken), ipAddr); err != nil {
  3001. s.renderForbiddenPage(w, r, err.Error())
  3002. return
  3003. }
  3004. updatedUser.ID = user.ID
  3005. updatedUser.Username = user.Username
  3006. updatedUser.Filters.RecoveryCodes = user.Filters.RecoveryCodes
  3007. updatedUser.Filters.TOTPConfig = user.Filters.TOTPConfig
  3008. updatedUser.LastPasswordChange = user.LastPasswordChange
  3009. updatedUser.SetEmptySecretsIfNil()
  3010. if updatedUser.Password == redactedSecret {
  3011. updatedUser.Password = user.Password
  3012. }
  3013. updateEncryptedSecrets(&updatedUser.FsConfig, user.FsConfig.S3Config.AccessSecret, user.FsConfig.AzBlobConfig.AccountKey,
  3014. user.FsConfig.AzBlobConfig.SASURL, user.FsConfig.GCSConfig.Credentials, user.FsConfig.CryptConfig.Passphrase,
  3015. user.FsConfig.SFTPConfig.Password, user.FsConfig.SFTPConfig.PrivateKey, user.FsConfig.SFTPConfig.KeyPassphrase,
  3016. user.FsConfig.HTTPConfig.Password, user.FsConfig.HTTPConfig.APIKey)
  3017. updatedUser = getUserFromTemplate(updatedUser, userTemplateFields{
  3018. Username: updatedUser.Username,
  3019. Password: updatedUser.Password,
  3020. PublicKeys: updatedUser.PublicKeys,
  3021. })
  3022. if claims.Role != "" {
  3023. updatedUser.Role = claims.Role
  3024. }
  3025. err = dataprovider.UpdateUser(&updatedUser, claims.Username, ipAddr, claims.Role)
  3026. if err != nil {
  3027. s.renderUserPage(w, r, &updatedUser, userPageModeUpdate, err.Error(), nil)
  3028. return
  3029. }
  3030. if r.Form.Get("disconnect") != "" {
  3031. disconnectUser(user.Username, claims.Username, claims.Role)
  3032. }
  3033. http.Redirect(w, r, webUsersPath, http.StatusSeeOther)
  3034. }
  3035. func (s *httpdServer) handleWebGetStatus(w http.ResponseWriter, r *http.Request) {
  3036. r.Body = http.MaxBytesReader(w, r.Body, maxRequestSize)
  3037. data := statusPage{
  3038. basePage: s.getBasePageData(pageStatusTitle, webStatusPath, r),
  3039. Status: getServicesStatus(),
  3040. }
  3041. renderAdminTemplate(w, templateStatus, data)
  3042. }
  3043. func (s *httpdServer) handleWebGetConnections(w http.ResponseWriter, r *http.Request) {
  3044. r.Body = http.MaxBytesReader(w, r.Body, maxRequestSize)
  3045. claims, err := getTokenClaims(r)
  3046. if err != nil || claims.Username == "" {
  3047. s.renderBadRequestPage(w, r, errors.New("invalid token claims"))
  3048. return
  3049. }
  3050. connectionStats := common.Connections.GetStats(claims.Role)
  3051. connectionStats = append(connectionStats, getNodesConnections(claims.Username, claims.Role)...)
  3052. data := connectionsPage{
  3053. basePage: s.getBasePageData(pageConnectionsTitle, webConnectionsPath, r),
  3054. Connections: connectionStats,
  3055. }
  3056. renderAdminTemplate(w, templateConnections, data)
  3057. }
  3058. func (s *httpdServer) handleWebAddFolderGet(w http.ResponseWriter, r *http.Request) {
  3059. r.Body = http.MaxBytesReader(w, r.Body, maxRequestSize)
  3060. s.renderFolderPage(w, r, vfs.BaseVirtualFolder{}, folderPageModeAdd, "")
  3061. }
  3062. func (s *httpdServer) handleWebAddFolderPost(w http.ResponseWriter, r *http.Request) {
  3063. r.Body = http.MaxBytesReader(w, r.Body, maxRequestSize)
  3064. claims, err := getTokenClaims(r)
  3065. if err != nil || claims.Username == "" {
  3066. s.renderBadRequestPage(w, r, errors.New("invalid token claims"))
  3067. return
  3068. }
  3069. folder := vfs.BaseVirtualFolder{}
  3070. err = r.ParseMultipartForm(maxRequestSize)
  3071. if err != nil {
  3072. s.renderFolderPage(w, r, folder, folderPageModeAdd, err.Error())
  3073. return
  3074. }
  3075. defer r.MultipartForm.RemoveAll() //nolint:errcheck
  3076. ipAddr := util.GetIPFromRemoteAddress(r.RemoteAddr)
  3077. if err := verifyCSRFToken(r.Form.Get(csrfFormToken), ipAddr); err != nil {
  3078. s.renderForbiddenPage(w, r, err.Error())
  3079. return
  3080. }
  3081. folder.MappedPath = r.Form.Get("mapped_path")
  3082. folder.Name = r.Form.Get("name")
  3083. folder.Description = r.Form.Get("description")
  3084. fsConfig, err := getFsConfigFromPostFields(r)
  3085. if err != nil {
  3086. s.renderFolderPage(w, r, folder, folderPageModeAdd, err.Error())
  3087. return
  3088. }
  3089. folder.FsConfig = fsConfig
  3090. folder = getFolderFromTemplate(folder, folder.Name)
  3091. err = dataprovider.AddFolder(&folder, claims.Username, ipAddr, claims.Role)
  3092. if err == nil {
  3093. http.Redirect(w, r, webFoldersPath, http.StatusSeeOther)
  3094. } else {
  3095. s.renderFolderPage(w, r, folder, folderPageModeAdd, err.Error())
  3096. }
  3097. }
  3098. func (s *httpdServer) handleWebUpdateFolderGet(w http.ResponseWriter, r *http.Request) {
  3099. r.Body = http.MaxBytesReader(w, r.Body, maxRequestSize)
  3100. name := getURLParam(r, "name")
  3101. folder, err := dataprovider.GetFolderByName(name)
  3102. if err == nil {
  3103. s.renderFolderPage(w, r, folder, folderPageModeUpdate, "")
  3104. } else if errors.Is(err, util.ErrNotFound) {
  3105. s.renderNotFoundPage(w, r, err)
  3106. } else {
  3107. s.renderInternalServerErrorPage(w, r, err)
  3108. }
  3109. }
  3110. func (s *httpdServer) handleWebUpdateFolderPost(w http.ResponseWriter, r *http.Request) {
  3111. r.Body = http.MaxBytesReader(w, r.Body, maxRequestSize)
  3112. claims, err := getTokenClaims(r)
  3113. if err != nil || claims.Username == "" {
  3114. s.renderBadRequestPage(w, r, errors.New("invalid token claims"))
  3115. return
  3116. }
  3117. name := getURLParam(r, "name")
  3118. folder, err := dataprovider.GetFolderByName(name)
  3119. if errors.Is(err, util.ErrNotFound) {
  3120. s.renderNotFoundPage(w, r, err)
  3121. return
  3122. } else if err != nil {
  3123. s.renderInternalServerErrorPage(w, r, err)
  3124. return
  3125. }
  3126. err = r.ParseMultipartForm(maxRequestSize)
  3127. if err != nil {
  3128. s.renderFolderPage(w, r, folder, folderPageModeUpdate, err.Error())
  3129. return
  3130. }
  3131. defer r.MultipartForm.RemoveAll() //nolint:errcheck
  3132. ipAddr := util.GetIPFromRemoteAddress(r.RemoteAddr)
  3133. if err := verifyCSRFToken(r.Form.Get(csrfFormToken), ipAddr); err != nil {
  3134. s.renderForbiddenPage(w, r, err.Error())
  3135. return
  3136. }
  3137. fsConfig, err := getFsConfigFromPostFields(r)
  3138. if err != nil {
  3139. s.renderFolderPage(w, r, folder, folderPageModeUpdate, err.Error())
  3140. return
  3141. }
  3142. updatedFolder := vfs.BaseVirtualFolder{
  3143. MappedPath: r.Form.Get("mapped_path"),
  3144. Description: r.Form.Get("description"),
  3145. }
  3146. updatedFolder.ID = folder.ID
  3147. updatedFolder.Name = folder.Name
  3148. updatedFolder.FsConfig = fsConfig
  3149. updatedFolder.FsConfig.SetEmptySecretsIfNil()
  3150. updateEncryptedSecrets(&updatedFolder.FsConfig, folder.FsConfig.S3Config.AccessSecret, folder.FsConfig.AzBlobConfig.AccountKey,
  3151. folder.FsConfig.AzBlobConfig.SASURL, folder.FsConfig.GCSConfig.Credentials, folder.FsConfig.CryptConfig.Passphrase,
  3152. folder.FsConfig.SFTPConfig.Password, folder.FsConfig.SFTPConfig.PrivateKey, folder.FsConfig.SFTPConfig.KeyPassphrase,
  3153. folder.FsConfig.HTTPConfig.Password, folder.FsConfig.HTTPConfig.APIKey)
  3154. updatedFolder = getFolderFromTemplate(updatedFolder, updatedFolder.Name)
  3155. err = dataprovider.UpdateFolder(&updatedFolder, folder.Users, folder.Groups, claims.Username, ipAddr, claims.Role)
  3156. if err != nil {
  3157. s.renderFolderPage(w, r, updatedFolder, folderPageModeUpdate, err.Error())
  3158. return
  3159. }
  3160. http.Redirect(w, r, webFoldersPath, http.StatusSeeOther)
  3161. }
  3162. func (s *httpdServer) getWebVirtualFolders(w http.ResponseWriter, r *http.Request, limit int, minimal bool) ([]vfs.BaseVirtualFolder, error) {
  3163. folders := make([]vfs.BaseVirtualFolder, 0, limit)
  3164. for {
  3165. f, err := dataprovider.GetFolders(limit, len(folders), dataprovider.OrderASC, minimal)
  3166. if err != nil {
  3167. s.renderInternalServerErrorPage(w, r, err)
  3168. return folders, err
  3169. }
  3170. folders = append(folders, f...)
  3171. if len(f) < limit {
  3172. break
  3173. }
  3174. }
  3175. return folders, nil
  3176. }
  3177. func (s *httpdServer) handleWebGetFolders(w http.ResponseWriter, r *http.Request) {
  3178. r.Body = http.MaxBytesReader(w, r.Body, maxRequestSize)
  3179. limit := defaultQueryLimit
  3180. if _, ok := r.URL.Query()["qlimit"]; ok {
  3181. var err error
  3182. limit, err = strconv.Atoi(r.URL.Query().Get("qlimit"))
  3183. if err != nil {
  3184. limit = defaultQueryLimit
  3185. }
  3186. }
  3187. folders, err := s.getWebVirtualFolders(w, r, limit, false)
  3188. if err != nil {
  3189. return
  3190. }
  3191. data := foldersPage{
  3192. basePage: s.getBasePageData(pageFoldersTitle, webFoldersPath, r),
  3193. Folders: folders,
  3194. }
  3195. renderAdminTemplate(w, templateFolders, data)
  3196. }
  3197. func (s *httpdServer) getWebGroups(w http.ResponseWriter, r *http.Request, limit int, minimal bool) ([]dataprovider.Group, error) {
  3198. groups := make([]dataprovider.Group, 0, limit)
  3199. for {
  3200. f, err := dataprovider.GetGroups(limit, len(groups), dataprovider.OrderASC, minimal)
  3201. if err != nil {
  3202. s.renderInternalServerErrorPage(w, r, err)
  3203. return groups, err
  3204. }
  3205. groups = append(groups, f...)
  3206. if len(f) < limit {
  3207. break
  3208. }
  3209. }
  3210. return groups, nil
  3211. }
  3212. func (s *httpdServer) handleWebGetGroups(w http.ResponseWriter, r *http.Request) {
  3213. r.Body = http.MaxBytesReader(w, r.Body, maxRequestSize)
  3214. limit := defaultQueryLimit
  3215. if _, ok := r.URL.Query()["qlimit"]; ok {
  3216. var err error
  3217. limit, err = strconv.Atoi(r.URL.Query().Get("qlimit"))
  3218. if err != nil {
  3219. limit = defaultQueryLimit
  3220. }
  3221. }
  3222. groups, err := s.getWebGroups(w, r, limit, false)
  3223. if err != nil {
  3224. return
  3225. }
  3226. data := groupsPage{
  3227. basePage: s.getBasePageData(pageGroupsTitle, webGroupsPath, r),
  3228. Groups: groups,
  3229. }
  3230. renderAdminTemplate(w, templateGroups, data)
  3231. }
  3232. func (s *httpdServer) handleWebAddGroupGet(w http.ResponseWriter, r *http.Request) {
  3233. r.Body = http.MaxBytesReader(w, r.Body, maxRequestSize)
  3234. s.renderGroupPage(w, r, dataprovider.Group{}, genericPageModeAdd, "")
  3235. }
  3236. func (s *httpdServer) handleWebAddGroupPost(w http.ResponseWriter, r *http.Request) {
  3237. r.Body = http.MaxBytesReader(w, r.Body, maxRequestSize)
  3238. claims, err := getTokenClaims(r)
  3239. if err != nil || claims.Username == "" {
  3240. s.renderBadRequestPage(w, r, errors.New("invalid token claims"))
  3241. return
  3242. }
  3243. group, err := getGroupFromPostFields(r)
  3244. if err != nil {
  3245. s.renderGroupPage(w, r, group, genericPageModeAdd, err.Error())
  3246. return
  3247. }
  3248. ipAddr := util.GetIPFromRemoteAddress(r.RemoteAddr)
  3249. if err := verifyCSRFToken(r.Form.Get(csrfFormToken), ipAddr); err != nil {
  3250. s.renderForbiddenPage(w, r, err.Error())
  3251. return
  3252. }
  3253. err = dataprovider.AddGroup(&group, claims.Username, ipAddr, claims.Role)
  3254. if err != nil {
  3255. s.renderGroupPage(w, r, group, genericPageModeAdd, err.Error())
  3256. return
  3257. }
  3258. http.Redirect(w, r, webGroupsPath, http.StatusSeeOther)
  3259. }
  3260. func (s *httpdServer) handleWebUpdateGroupGet(w http.ResponseWriter, r *http.Request) {
  3261. r.Body = http.MaxBytesReader(w, r.Body, maxRequestSize)
  3262. name := getURLParam(r, "name")
  3263. group, err := dataprovider.GroupExists(name)
  3264. if err == nil {
  3265. s.renderGroupPage(w, r, group, genericPageModeUpdate, "")
  3266. } else if errors.Is(err, util.ErrNotFound) {
  3267. s.renderNotFoundPage(w, r, err)
  3268. } else {
  3269. s.renderInternalServerErrorPage(w, r, err)
  3270. }
  3271. }
  3272. func (s *httpdServer) handleWebUpdateGroupPost(w http.ResponseWriter, r *http.Request) {
  3273. r.Body = http.MaxBytesReader(w, r.Body, maxRequestSize)
  3274. claims, err := getTokenClaims(r)
  3275. if err != nil || claims.Username == "" {
  3276. s.renderBadRequestPage(w, r, errors.New("invalid token claims"))
  3277. return
  3278. }
  3279. name := getURLParam(r, "name")
  3280. group, err := dataprovider.GroupExists(name)
  3281. if errors.Is(err, util.ErrNotFound) {
  3282. s.renderNotFoundPage(w, r, err)
  3283. return
  3284. } else if err != nil {
  3285. s.renderInternalServerErrorPage(w, r, err)
  3286. return
  3287. }
  3288. updatedGroup, err := getGroupFromPostFields(r)
  3289. if err != nil {
  3290. s.renderGroupPage(w, r, group, genericPageModeUpdate, err.Error())
  3291. return
  3292. }
  3293. ipAddr := util.GetIPFromRemoteAddress(r.RemoteAddr)
  3294. if err := verifyCSRFToken(r.Form.Get(csrfFormToken), ipAddr); err != nil {
  3295. s.renderForbiddenPage(w, r, err.Error())
  3296. return
  3297. }
  3298. updatedGroup.ID = group.ID
  3299. updatedGroup.Name = group.Name
  3300. updatedGroup.SetEmptySecretsIfNil()
  3301. updateEncryptedSecrets(&updatedGroup.UserSettings.FsConfig, group.UserSettings.FsConfig.S3Config.AccessSecret,
  3302. group.UserSettings.FsConfig.AzBlobConfig.AccountKey, group.UserSettings.FsConfig.AzBlobConfig.SASURL,
  3303. group.UserSettings.FsConfig.GCSConfig.Credentials, group.UserSettings.FsConfig.CryptConfig.Passphrase,
  3304. group.UserSettings.FsConfig.SFTPConfig.Password, group.UserSettings.FsConfig.SFTPConfig.PrivateKey,
  3305. group.UserSettings.FsConfig.SFTPConfig.KeyPassphrase, group.UserSettings.FsConfig.HTTPConfig.Password,
  3306. group.UserSettings.FsConfig.HTTPConfig.APIKey)
  3307. err = dataprovider.UpdateGroup(&updatedGroup, group.Users, claims.Username, ipAddr, claims.Role)
  3308. if err != nil {
  3309. s.renderGroupPage(w, r, updatedGroup, genericPageModeUpdate, err.Error())
  3310. return
  3311. }
  3312. http.Redirect(w, r, webGroupsPath, http.StatusSeeOther)
  3313. }
  3314. func (s *httpdServer) getWebEventActions(w http.ResponseWriter, r *http.Request, limit int, minimal bool,
  3315. ) ([]dataprovider.BaseEventAction, error) {
  3316. actions := make([]dataprovider.BaseEventAction, 0, limit)
  3317. for {
  3318. res, err := dataprovider.GetEventActions(limit, len(actions), dataprovider.OrderASC, minimal)
  3319. if err != nil {
  3320. s.renderInternalServerErrorPage(w, r, err)
  3321. return actions, err
  3322. }
  3323. actions = append(actions, res...)
  3324. if len(res) < limit {
  3325. break
  3326. }
  3327. }
  3328. return actions, nil
  3329. }
  3330. func (s *httpdServer) handleWebGetEventActions(w http.ResponseWriter, r *http.Request) {
  3331. r.Body = http.MaxBytesReader(w, r.Body, maxRequestSize)
  3332. limit := defaultQueryLimit
  3333. if _, ok := r.URL.Query()["qlimit"]; ok {
  3334. var err error
  3335. limit, err = strconv.Atoi(r.URL.Query().Get("qlimit"))
  3336. if err != nil {
  3337. limit = defaultQueryLimit
  3338. }
  3339. }
  3340. actions, err := s.getWebEventActions(w, r, limit, false)
  3341. if err != nil {
  3342. return
  3343. }
  3344. data := eventActionsPage{
  3345. basePage: s.getBasePageData(pageEventActionsTitle, webAdminEventActionsPath, r),
  3346. Actions: actions,
  3347. }
  3348. renderAdminTemplate(w, templateEventActions, data)
  3349. }
  3350. func (s *httpdServer) handleWebAddEventActionGet(w http.ResponseWriter, r *http.Request) {
  3351. r.Body = http.MaxBytesReader(w, r.Body, maxRequestSize)
  3352. action := dataprovider.BaseEventAction{
  3353. Type: dataprovider.ActionTypeHTTP,
  3354. }
  3355. s.renderEventActionPage(w, r, action, genericPageModeAdd, "")
  3356. }
  3357. func (s *httpdServer) handleWebAddEventActionPost(w http.ResponseWriter, r *http.Request) {
  3358. r.Body = http.MaxBytesReader(w, r.Body, maxRequestSize)
  3359. claims, err := getTokenClaims(r)
  3360. if err != nil || claims.Username == "" {
  3361. s.renderBadRequestPage(w, r, errors.New("invalid token claims"))
  3362. return
  3363. }
  3364. action, err := getEventActionFromPostFields(r)
  3365. if err != nil {
  3366. s.renderEventActionPage(w, r, action, genericPageModeAdd, err.Error())
  3367. return
  3368. }
  3369. ipAddr := util.GetIPFromRemoteAddress(r.RemoteAddr)
  3370. if err := verifyCSRFToken(r.Form.Get(csrfFormToken), ipAddr); err != nil {
  3371. s.renderForbiddenPage(w, r, err.Error())
  3372. return
  3373. }
  3374. if err = dataprovider.AddEventAction(&action, claims.Username, ipAddr, claims.Role); err != nil {
  3375. s.renderEventActionPage(w, r, action, genericPageModeAdd, err.Error())
  3376. return
  3377. }
  3378. http.Redirect(w, r, webAdminEventActionsPath, http.StatusSeeOther)
  3379. }
  3380. func (s *httpdServer) handleWebUpdateEventActionGet(w http.ResponseWriter, r *http.Request) {
  3381. r.Body = http.MaxBytesReader(w, r.Body, maxRequestSize)
  3382. name := getURLParam(r, "name")
  3383. action, err := dataprovider.EventActionExists(name)
  3384. if err == nil {
  3385. s.renderEventActionPage(w, r, action, genericPageModeUpdate, "")
  3386. } else if errors.Is(err, util.ErrNotFound) {
  3387. s.renderNotFoundPage(w, r, err)
  3388. } else {
  3389. s.renderInternalServerErrorPage(w, r, err)
  3390. }
  3391. }
  3392. func (s *httpdServer) handleWebUpdateEventActionPost(w http.ResponseWriter, r *http.Request) {
  3393. r.Body = http.MaxBytesReader(w, r.Body, maxRequestSize)
  3394. claims, err := getTokenClaims(r)
  3395. if err != nil || claims.Username == "" {
  3396. s.renderBadRequestPage(w, r, errors.New("invalid token claims"))
  3397. return
  3398. }
  3399. name := getURLParam(r, "name")
  3400. action, err := dataprovider.EventActionExists(name)
  3401. if errors.Is(err, util.ErrNotFound) {
  3402. s.renderNotFoundPage(w, r, err)
  3403. return
  3404. } else if err != nil {
  3405. s.renderInternalServerErrorPage(w, r, err)
  3406. return
  3407. }
  3408. updatedAction, err := getEventActionFromPostFields(r)
  3409. if err != nil {
  3410. s.renderEventActionPage(w, r, updatedAction, genericPageModeUpdate, err.Error())
  3411. return
  3412. }
  3413. ipAddr := util.GetIPFromRemoteAddress(r.RemoteAddr)
  3414. if err := verifyCSRFToken(r.Form.Get(csrfFormToken), ipAddr); err != nil {
  3415. s.renderForbiddenPage(w, r, err.Error())
  3416. return
  3417. }
  3418. updatedAction.ID = action.ID
  3419. updatedAction.Name = action.Name
  3420. updatedAction.Options.SetEmptySecretsIfNil()
  3421. switch updatedAction.Type {
  3422. case dataprovider.ActionTypeHTTP:
  3423. if updatedAction.Options.HTTPConfig.Password.IsNotPlainAndNotEmpty() {
  3424. updatedAction.Options.HTTPConfig.Password = action.Options.HTTPConfig.Password
  3425. }
  3426. }
  3427. err = dataprovider.UpdateEventAction(&updatedAction, claims.Username, ipAddr, claims.Role)
  3428. if err != nil {
  3429. s.renderEventActionPage(w, r, updatedAction, genericPageModeUpdate, err.Error())
  3430. return
  3431. }
  3432. http.Redirect(w, r, webAdminEventActionsPath, http.StatusSeeOther)
  3433. }
  3434. func (s *httpdServer) handleWebGetEventRules(w http.ResponseWriter, r *http.Request) {
  3435. r.Body = http.MaxBytesReader(w, r.Body, maxRequestSize)
  3436. limit := defaultQueryLimit
  3437. if _, ok := r.URL.Query()["qlimit"]; ok {
  3438. if lim, err := strconv.Atoi(r.URL.Query().Get("qlimit")); err == nil {
  3439. limit = lim
  3440. }
  3441. }
  3442. rules := make([]dataprovider.EventRule, 0, limit)
  3443. for {
  3444. res, err := dataprovider.GetEventRules(limit, len(rules), dataprovider.OrderASC)
  3445. if err != nil {
  3446. s.renderInternalServerErrorPage(w, r, err)
  3447. return
  3448. }
  3449. rules = append(rules, res...)
  3450. if len(res) < limit {
  3451. break
  3452. }
  3453. }
  3454. data := eventRulesPage{
  3455. basePage: s.getBasePageData(pageEventRulesTitle, webAdminEventRulesPath, r),
  3456. Rules: rules,
  3457. }
  3458. renderAdminTemplate(w, templateEventRules, data)
  3459. }
  3460. func (s *httpdServer) handleWebAddEventRuleGet(w http.ResponseWriter, r *http.Request) {
  3461. r.Body = http.MaxBytesReader(w, r.Body, maxRequestSize)
  3462. rule := dataprovider.EventRule{
  3463. Status: 1,
  3464. Trigger: dataprovider.EventTriggerFsEvent,
  3465. }
  3466. s.renderEventRulePage(w, r, rule, genericPageModeAdd, "")
  3467. }
  3468. func (s *httpdServer) handleWebAddEventRulePost(w http.ResponseWriter, r *http.Request) {
  3469. r.Body = http.MaxBytesReader(w, r.Body, maxRequestSize)
  3470. claims, err := getTokenClaims(r)
  3471. if err != nil || claims.Username == "" {
  3472. s.renderBadRequestPage(w, r, errors.New("invalid token claims"))
  3473. return
  3474. }
  3475. rule, err := getEventRuleFromPostFields(r)
  3476. if err != nil {
  3477. s.renderEventRulePage(w, r, rule, genericPageModeAdd, err.Error())
  3478. return
  3479. }
  3480. ipAddr := util.GetIPFromRemoteAddress(r.RemoteAddr)
  3481. err = verifyCSRFToken(r.Form.Get(csrfFormToken), ipAddr)
  3482. if err != nil {
  3483. s.renderForbiddenPage(w, r, err.Error())
  3484. return
  3485. }
  3486. if err = dataprovider.AddEventRule(&rule, claims.Username, ipAddr, claims.Role); err != nil {
  3487. s.renderEventRulePage(w, r, rule, genericPageModeAdd, err.Error())
  3488. return
  3489. }
  3490. http.Redirect(w, r, webAdminEventRulesPath, http.StatusSeeOther)
  3491. }
  3492. func (s *httpdServer) handleWebUpdateEventRuleGet(w http.ResponseWriter, r *http.Request) {
  3493. r.Body = http.MaxBytesReader(w, r.Body, maxRequestSize)
  3494. name := getURLParam(r, "name")
  3495. rule, err := dataprovider.EventRuleExists(name)
  3496. if err == nil {
  3497. s.renderEventRulePage(w, r, rule, genericPageModeUpdate, "")
  3498. } else if errors.Is(err, util.ErrNotFound) {
  3499. s.renderNotFoundPage(w, r, err)
  3500. } else {
  3501. s.renderInternalServerErrorPage(w, r, err)
  3502. }
  3503. }
  3504. func (s *httpdServer) handleWebUpdateEventRulePost(w http.ResponseWriter, r *http.Request) {
  3505. r.Body = http.MaxBytesReader(w, r.Body, maxRequestSize)
  3506. claims, err := getTokenClaims(r)
  3507. if err != nil || claims.Username == "" {
  3508. s.renderBadRequestPage(w, r, errors.New("invalid token claims"))
  3509. return
  3510. }
  3511. name := getURLParam(r, "name")
  3512. rule, err := dataprovider.EventRuleExists(name)
  3513. if errors.Is(err, util.ErrNotFound) {
  3514. s.renderNotFoundPage(w, r, err)
  3515. return
  3516. } else if err != nil {
  3517. s.renderInternalServerErrorPage(w, r, err)
  3518. return
  3519. }
  3520. updatedRule, err := getEventRuleFromPostFields(r)
  3521. if err != nil {
  3522. s.renderEventRulePage(w, r, updatedRule, genericPageModeUpdate, err.Error())
  3523. return
  3524. }
  3525. ipAddr := util.GetIPFromRemoteAddress(r.RemoteAddr)
  3526. if err := verifyCSRFToken(r.Form.Get(csrfFormToken), ipAddr); err != nil {
  3527. s.renderForbiddenPage(w, r, err.Error())
  3528. return
  3529. }
  3530. updatedRule.ID = rule.ID
  3531. updatedRule.Name = rule.Name
  3532. err = dataprovider.UpdateEventRule(&updatedRule, claims.Username, ipAddr, claims.Role)
  3533. if err != nil {
  3534. s.renderEventRulePage(w, r, updatedRule, genericPageModeUpdate, err.Error())
  3535. return
  3536. }
  3537. http.Redirect(w, r, webAdminEventRulesPath, http.StatusSeeOther)
  3538. }
  3539. func (s *httpdServer) getWebRoles(w http.ResponseWriter, r *http.Request, limit int, minimal bool) ([]dataprovider.Role, error) {
  3540. roles := make([]dataprovider.Role, 0, limit)
  3541. for {
  3542. res, err := dataprovider.GetRoles(limit, len(roles), dataprovider.OrderASC, minimal)
  3543. if err != nil {
  3544. s.renderInternalServerErrorPage(w, r, err)
  3545. return roles, err
  3546. }
  3547. roles = append(roles, res...)
  3548. if len(res) < limit {
  3549. break
  3550. }
  3551. }
  3552. return roles, nil
  3553. }
  3554. func (s *httpdServer) handleWebGetRoles(w http.ResponseWriter, r *http.Request) {
  3555. r.Body = http.MaxBytesReader(w, r.Body, maxRequestSize)
  3556. roles, err := s.getWebRoles(w, r, 10, false)
  3557. if err != nil {
  3558. return
  3559. }
  3560. data := rolesPage{
  3561. basePage: s.getBasePageData(pageRolesTitle, webAdminRolesPath, r),
  3562. Roles: roles,
  3563. }
  3564. renderAdminTemplate(w, templateRoles, data)
  3565. }
  3566. func (s *httpdServer) handleWebAddRoleGet(w http.ResponseWriter, r *http.Request) {
  3567. r.Body = http.MaxBytesReader(w, r.Body, maxRequestSize)
  3568. s.renderRolePage(w, r, dataprovider.Role{}, genericPageModeAdd, "")
  3569. }
  3570. func (s *httpdServer) handleWebAddRolePost(w http.ResponseWriter, r *http.Request) {
  3571. r.Body = http.MaxBytesReader(w, r.Body, maxRequestSize)
  3572. role, err := getRoleFromPostFields(r)
  3573. if err != nil {
  3574. s.renderRolePage(w, r, role, genericPageModeAdd, err.Error())
  3575. return
  3576. }
  3577. claims, err := getTokenClaims(r)
  3578. if err != nil || claims.Username == "" {
  3579. s.renderBadRequestPage(w, r, errors.New("invalid token claims"))
  3580. return
  3581. }
  3582. ipAddr := util.GetIPFromRemoteAddress(r.RemoteAddr)
  3583. if err := verifyCSRFToken(r.Form.Get(csrfFormToken), ipAddr); err != nil {
  3584. s.renderForbiddenPage(w, r, err.Error())
  3585. return
  3586. }
  3587. err = dataprovider.AddRole(&role, claims.Username, ipAddr, claims.Role)
  3588. if err != nil {
  3589. s.renderRolePage(w, r, role, genericPageModeAdd, err.Error())
  3590. return
  3591. }
  3592. http.Redirect(w, r, webAdminRolesPath, http.StatusSeeOther)
  3593. }
  3594. func (s *httpdServer) handleWebUpdateRoleGet(w http.ResponseWriter, r *http.Request) {
  3595. r.Body = http.MaxBytesReader(w, r.Body, maxRequestSize)
  3596. role, err := dataprovider.RoleExists(getURLParam(r, "name"))
  3597. if err == nil {
  3598. s.renderRolePage(w, r, role, genericPageModeUpdate, "")
  3599. } else if errors.Is(err, util.ErrNotFound) {
  3600. s.renderNotFoundPage(w, r, err)
  3601. } else {
  3602. s.renderInternalServerErrorPage(w, r, err)
  3603. }
  3604. }
  3605. func (s *httpdServer) handleWebUpdateRolePost(w http.ResponseWriter, r *http.Request) {
  3606. r.Body = http.MaxBytesReader(w, r.Body, maxRequestSize)
  3607. claims, err := getTokenClaims(r)
  3608. if err != nil || claims.Username == "" {
  3609. s.renderBadRequestPage(w, r, errors.New("invalid token claims"))
  3610. return
  3611. }
  3612. role, err := dataprovider.RoleExists(getURLParam(r, "name"))
  3613. if errors.Is(err, util.ErrNotFound) {
  3614. s.renderNotFoundPage(w, r, err)
  3615. return
  3616. } else if err != nil {
  3617. s.renderInternalServerErrorPage(w, r, err)
  3618. return
  3619. }
  3620. updatedRole, err := getRoleFromPostFields(r)
  3621. if err != nil {
  3622. s.renderRolePage(w, r, role, genericPageModeUpdate, err.Error())
  3623. return
  3624. }
  3625. ipAddr := util.GetIPFromRemoteAddress(r.RemoteAddr)
  3626. if err := verifyCSRFToken(r.Form.Get(csrfFormToken), ipAddr); err != nil {
  3627. s.renderForbiddenPage(w, r, err.Error())
  3628. return
  3629. }
  3630. updatedRole.ID = role.ID
  3631. updatedRole.Name = role.Name
  3632. err = dataprovider.UpdateRole(&updatedRole, claims.Username, ipAddr, claims.Role)
  3633. if err != nil {
  3634. s.renderRolePage(w, r, updatedRole, genericPageModeUpdate, err.Error())
  3635. return
  3636. }
  3637. http.Redirect(w, r, webAdminRolesPath, http.StatusSeeOther)
  3638. }
  3639. func (s *httpdServer) handleWebGetEvents(w http.ResponseWriter, r *http.Request) {
  3640. r.Body = http.MaxBytesReader(w, r.Body, maxRequestSize)
  3641. data := eventsPage{
  3642. basePage: s.getBasePageData(pageEventsTitle, webEventsPath, r),
  3643. FsEventsSearchURL: webEventsFsSearchPath,
  3644. ProviderEventsSearchURL: webEventsProviderSearchPath,
  3645. }
  3646. renderAdminTemplate(w, templateEvents, data)
  3647. }
  3648. func (s *httpdServer) handleWebIPListsPage(w http.ResponseWriter, r *http.Request) {
  3649. r.Body = http.MaxBytesReader(w, r.Body, maxRequestSize)
  3650. rtlStatus, rtlProtocols := common.Config.GetRateLimitersStatus()
  3651. data := ipListsPage{
  3652. basePage: s.getBasePageData(pageIPListsTitle, webIPListsPath, r),
  3653. RateLimitersStatus: rtlStatus,
  3654. RateLimitersProtocols: strings.Join(rtlProtocols, ", "),
  3655. IsAllowListEnabled: common.Config.IsAllowListEnabled(),
  3656. }
  3657. renderAdminTemplate(w, templateIPLists, data)
  3658. }
  3659. func (s *httpdServer) handleWebAddIPListEntryGet(w http.ResponseWriter, r *http.Request) {
  3660. r.Body = http.MaxBytesReader(w, r.Body, maxRequestSize)
  3661. listType, _, err := getIPListPathParams(r)
  3662. if err != nil {
  3663. s.renderBadRequestPage(w, r, err)
  3664. return
  3665. }
  3666. s.renderIPListPage(w, r, dataprovider.IPListEntry{Type: listType}, genericPageModeAdd, "")
  3667. }
  3668. func (s *httpdServer) handleWebAddIPListEntryPost(w http.ResponseWriter, r *http.Request) {
  3669. r.Body = http.MaxBytesReader(w, r.Body, maxRequestSize)
  3670. listType, _, err := getIPListPathParams(r)
  3671. if err != nil {
  3672. s.renderBadRequestPage(w, r, err)
  3673. return
  3674. }
  3675. entry, err := getIPListEntryFromPostFields(r, listType)
  3676. if err != nil {
  3677. s.renderIPListPage(w, r, entry, genericPageModeAdd, err.Error())
  3678. return
  3679. }
  3680. entry.Type = listType
  3681. claims, err := getTokenClaims(r)
  3682. if err != nil || claims.Username == "" {
  3683. s.renderBadRequestPage(w, r, errors.New("invalid token claims"))
  3684. return
  3685. }
  3686. ipAddr := util.GetIPFromRemoteAddress(r.RemoteAddr)
  3687. if err := verifyCSRFToken(r.Form.Get(csrfFormToken), ipAddr); err != nil {
  3688. s.renderForbiddenPage(w, r, err.Error())
  3689. return
  3690. }
  3691. err = dataprovider.AddIPListEntry(&entry, claims.Username, ipAddr, claims.Role)
  3692. if err != nil {
  3693. s.renderIPListPage(w, r, entry, genericPageModeAdd, err.Error())
  3694. return
  3695. }
  3696. http.Redirect(w, r, webIPListsPath, http.StatusSeeOther)
  3697. }
  3698. func (s *httpdServer) handleWebUpdateIPListEntryGet(w http.ResponseWriter, r *http.Request) {
  3699. r.Body = http.MaxBytesReader(w, r.Body, maxRequestSize)
  3700. listType, ipOrNet, err := getIPListPathParams(r)
  3701. if err != nil {
  3702. s.renderBadRequestPage(w, r, err)
  3703. return
  3704. }
  3705. entry, err := dataprovider.IPListEntryExists(ipOrNet, listType)
  3706. if err == nil {
  3707. s.renderIPListPage(w, r, entry, genericPageModeUpdate, "")
  3708. } else if errors.Is(err, util.ErrNotFound) {
  3709. s.renderNotFoundPage(w, r, err)
  3710. } else {
  3711. s.renderInternalServerErrorPage(w, r, err)
  3712. }
  3713. }
  3714. func (s *httpdServer) handleWebUpdateIPListEntryPost(w http.ResponseWriter, r *http.Request) {
  3715. r.Body = http.MaxBytesReader(w, r.Body, maxRequestSize)
  3716. claims, err := getTokenClaims(r)
  3717. if err != nil || claims.Username == "" {
  3718. s.renderBadRequestPage(w, r, errors.New("invalid token claims"))
  3719. return
  3720. }
  3721. listType, ipOrNet, err := getIPListPathParams(r)
  3722. if err != nil {
  3723. s.renderBadRequestPage(w, r, err)
  3724. return
  3725. }
  3726. entry, err := dataprovider.IPListEntryExists(ipOrNet, listType)
  3727. if errors.Is(err, util.ErrNotFound) {
  3728. s.renderNotFoundPage(w, r, err)
  3729. return
  3730. } else if err != nil {
  3731. s.renderInternalServerErrorPage(w, r, err)
  3732. return
  3733. }
  3734. updatedEntry, err := getIPListEntryFromPostFields(r, listType)
  3735. if err != nil {
  3736. s.renderIPListPage(w, r, entry, genericPageModeUpdate, err.Error())
  3737. return
  3738. }
  3739. ipAddr := util.GetIPFromRemoteAddress(r.RemoteAddr)
  3740. if err := verifyCSRFToken(r.Form.Get(csrfFormToken), ipAddr); err != nil {
  3741. s.renderForbiddenPage(w, r, err.Error())
  3742. return
  3743. }
  3744. updatedEntry.Type = listType
  3745. updatedEntry.IPOrNet = ipOrNet
  3746. err = dataprovider.UpdateIPListEntry(&updatedEntry, claims.Username, ipAddr, claims.Role)
  3747. if err != nil {
  3748. s.renderIPListPage(w, r, entry, genericPageModeUpdate, err.Error())
  3749. return
  3750. }
  3751. http.Redirect(w, r, webIPListsPath, http.StatusSeeOther)
  3752. }
  3753. func (s *httpdServer) handleWebConfigs(w http.ResponseWriter, r *http.Request) {
  3754. r.Body = http.MaxBytesReader(w, r.Body, maxRequestSize)
  3755. configs, err := dataprovider.GetConfigs()
  3756. if err != nil {
  3757. s.renderInternalServerErrorPage(w, r, err)
  3758. return
  3759. }
  3760. s.renderConfigsPage(w, r, configs, "", 0)
  3761. }
  3762. func (s *httpdServer) handleWebConfigsPost(w http.ResponseWriter, r *http.Request) {
  3763. r.Body = http.MaxBytesReader(w, r.Body, maxRequestSize)
  3764. claims, err := getTokenClaims(r)
  3765. if err != nil || claims.Username == "" {
  3766. s.renderBadRequestPage(w, r, errors.New("invalid token claims"))
  3767. return
  3768. }
  3769. configs, err := dataprovider.GetConfigs()
  3770. if err != nil {
  3771. s.renderInternalServerErrorPage(w, r, err)
  3772. return
  3773. }
  3774. err = r.ParseForm()
  3775. if err != nil {
  3776. s.renderBadRequestPage(w, r, err)
  3777. return
  3778. }
  3779. ipAddr := util.GetIPFromRemoteAddress(r.RemoteAddr)
  3780. if err := verifyCSRFToken(r.Form.Get(csrfFormToken), ipAddr); err != nil {
  3781. s.renderForbiddenPage(w, r, err.Error())
  3782. return
  3783. }
  3784. var configSection int
  3785. switch r.Form.Get("form_action") {
  3786. case "sftp_submit":
  3787. configSection = 1
  3788. sftpConfigs := getSFTPConfigsFromPostFields(r)
  3789. configs.SFTPD = sftpConfigs
  3790. case "smtp_submit":
  3791. configSection = 2
  3792. smtpConfigs := getSMTPConfigsFromPostFields(r)
  3793. if smtpConfigs.Password.IsNotPlainAndNotEmpty() {
  3794. smtpConfigs.Password = configs.SMTP.Password
  3795. }
  3796. configs.SMTP = smtpConfigs
  3797. default:
  3798. s.renderBadRequestPage(w, r, errors.New("unsupported form action"))
  3799. return
  3800. }
  3801. err = dataprovider.UpdateConfigs(&configs, claims.Username, ipAddr, claims.Role)
  3802. if err != nil {
  3803. s.renderConfigsPage(w, r, configs, err.Error(), configSection)
  3804. return
  3805. }
  3806. if configSection == 2 {
  3807. err := configs.SMTP.Password.TryDecrypt()
  3808. if err == nil {
  3809. smtp.Activate(configs.SMTP)
  3810. } else {
  3811. logger.Error(logSender, "", "unable to decrypt SMTP password, cannot activate configuration")
  3812. }
  3813. }
  3814. s.renderMessagePage(w, r, "Configurations updated", "", http.StatusOK, nil,
  3815. "Configurations has been successfully updated")
  3816. }