webadmin.go 147 KB

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