webadmin.go 147 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072307330743075307630773078307930803081308230833084308530863087308830893090309130923093309430953096309730983099310031013102310331043105310631073108310931103111311231133114311531163117311831193120312131223123312431253126312731283129313031313132313331343135313631373138313931403141314231433144314531463147314831493150315131523153315431553156315731583159316031613162316331643165316631673168316931703171317231733174317531763177317831793180318131823183318431853186318731883189319031913192319331943195319631973198319932003201320232033204320532063207320832093210321132123213321432153216321732183219322032213222322332243225322632273228322932303231323232333234323532363237323832393240324132423243324432453246324732483249325032513252325332543255325632573258325932603261326232633264326532663267326832693270327132723273327432753276327732783279328032813282328332843285328632873288328932903291329232933294329532963297329832993300330133023303330433053306330733083309331033113312331333143315331633173318331933203321332233233324332533263327332833293330333133323333333433353336333733383339334033413342334333443345334633473348334933503351335233533354335533563357335833593360336133623363336433653366336733683369337033713372337333743375337633773378337933803381338233833384338533863387338833893390339133923393339433953396339733983399340034013402340334043405340634073408340934103411341234133414341534163417341834193420342134223423342434253426342734283429343034313432343334343435343634373438343934403441344234433444344534463447344834493450345134523453345434553456345734583459346034613462346334643465346634673468346934703471347234733474347534763477347834793480348134823483348434853486348734883489349034913492349334943495349634973498349935003501350235033504350535063507350835093510351135123513351435153516351735183519352035213522352335243525352635273528352935303531353235333534353535363537353835393540354135423543354435453546354735483549355035513552355335543555355635573558355935603561356235633564356535663567356835693570357135723573357435753576357735783579358035813582358335843585358635873588358935903591359235933594359535963597359835993600360136023603360436053606360736083609361036113612361336143615361636173618361936203621362236233624362536263627362836293630363136323633363436353636363736383639364036413642364336443645364636473648364936503651365236533654365536563657365836593660366136623663366436653666366736683669367036713672367336743675367636773678367936803681368236833684368536863687368836893690369136923693369436953696369736983699370037013702370337043705370637073708370937103711371237133714371537163717371837193720372137223723372437253726372737283729373037313732373337343735373637373738373937403741374237433744374537463747374837493750375137523753375437553756375737583759376037613762376337643765376637673768376937703771377237733774377537763777377837793780378137823783378437853786378737883789379037913792379337943795379637973798379938003801380238033804380538063807380838093810381138123813381438153816381738183819382038213822382338243825382638273828382938303831383238333834383538363837383838393840384138423843384438453846384738483849385038513852385338543855385638573858385938603861386238633864386538663867386838693870387138723873387438753876387738783879388038813882388338843885388638873888388938903891389238933894389538963897389838993900390139023903390439053906390739083909391039113912391339143915391639173918391939203921392239233924392539263927392839293930393139323933393439353936393739383939394039413942394339443945394639473948394939503951395239533954395539563957395839593960396139623963396439653966396739683969397039713972397339743975397639773978397939803981398239833984398539863987398839893990399139923993399439953996399739983999400040014002400340044005400640074008400940104011401240134014401540164017401840194020402140224023402440254026402740284029403040314032403340344035403640374038403940404041404240434044404540464047404840494050405140524053405440554056405740584059406040614062406340644065406640674068406940704071407240734074407540764077407840794080408140824083408440854086408740884089409040914092409340944095409640974098409941004101410241034104410541064107410841094110411141124113411441154116411741184119412041214122412341244125412641274128412941304131413241334134413541364137413841394140414141424143414441454146414741484149415041514152415341544155415641574158415941604161416241634164416541664167416841694170417141724173417441754176417741784179418041814182418341844185418641874188418941904191419241934194419541964197419841994200420142024203420442054206420742084209421042114212421342144215421642174218421942204221422242234224422542264227422842294230423142324233423442354236423742384239424042414242424342444245424642474248424942504251425242534254425542564257425842594260426142624263426442654266426742684269427042714272427342744275427642774278427942804281428242834284428542864287428842894290429142924293429442954296429742984299430043014302430343044305430643074308430943104311431243134314431543164317431843194320432143224323432443254326432743284329
  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. }
  236. type folderPage struct {
  237. basePage
  238. Folder vfs.BaseVirtualFolder
  239. Error *util.I18nError
  240. Mode folderPageMode
  241. FsWrapper fsWrapper
  242. }
  243. type groupPage struct {
  244. basePage
  245. Group *dataprovider.Group
  246. Error *util.I18nError
  247. Mode genericPageMode
  248. ValidPerms []string
  249. ValidLoginMethods []string
  250. ValidProtocols []string
  251. TwoFactorProtocols []string
  252. WebClientOptions []string
  253. VirtualFolders []vfs.BaseVirtualFolder
  254. FsWrapper fsWrapper
  255. }
  256. type rolePage struct {
  257. basePage
  258. Role *dataprovider.Role
  259. Error *util.I18nError
  260. Mode genericPageMode
  261. }
  262. type eventActionPage struct {
  263. basePage
  264. Action dataprovider.BaseEventAction
  265. ActionTypes []dataprovider.EnumMapping
  266. FsActions []dataprovider.EnumMapping
  267. HTTPMethods []string
  268. RedactedSecret string
  269. Error *util.I18nError
  270. Mode genericPageMode
  271. }
  272. type eventRulePage struct {
  273. basePage
  274. Rule dataprovider.EventRule
  275. TriggerTypes []dataprovider.EnumMapping
  276. Actions []dataprovider.BaseEventAction
  277. FsEvents []string
  278. Protocols []string
  279. ProviderEvents []string
  280. ProviderObjects []string
  281. Error *util.I18nError
  282. Mode genericPageMode
  283. IsShared bool
  284. }
  285. type eventsPage struct {
  286. basePage
  287. FsEventsSearchURL string
  288. ProviderEventsSearchURL string
  289. LogEventsSearchURL string
  290. }
  291. type configsPage struct {
  292. basePage
  293. Configs dataprovider.Configs
  294. ConfigSection int
  295. RedactedSecret string
  296. OAuth2TokenURL string
  297. OAuth2RedirectURL string
  298. Error *util.I18nError
  299. }
  300. type messagePage struct {
  301. basePage
  302. Error *util.I18nError
  303. Success string
  304. Text string
  305. }
  306. type userTemplateFields struct {
  307. Username string
  308. Password string
  309. PublicKeys []string
  310. }
  311. func loadAdminTemplates(templatesPath string) {
  312. usersPaths := []string{
  313. filepath.Join(templatesPath, templateCommonDir, templateCommonBase),
  314. filepath.Join(templatesPath, templateAdminDir, templateBase),
  315. filepath.Join(templatesPath, templateAdminDir, templateUsers),
  316. }
  317. userPaths := []string{
  318. filepath.Join(templatesPath, templateCommonDir, templateCommonBase),
  319. filepath.Join(templatesPath, templateAdminDir, templateBase),
  320. filepath.Join(templatesPath, templateAdminDir, templateFsConfig),
  321. filepath.Join(templatesPath, templateAdminDir, templateUser),
  322. }
  323. adminsPaths := []string{
  324. filepath.Join(templatesPath, templateCommonDir, templateCommonBase),
  325. filepath.Join(templatesPath, templateAdminDir, templateBase),
  326. filepath.Join(templatesPath, templateAdminDir, templateAdmins),
  327. }
  328. adminPaths := []string{
  329. filepath.Join(templatesPath, templateCommonDir, templateCommonBase),
  330. filepath.Join(templatesPath, templateAdminDir, templateBase),
  331. filepath.Join(templatesPath, templateAdminDir, templateAdmin),
  332. }
  333. profilePaths := []string{
  334. filepath.Join(templatesPath, templateCommonDir, templateCommonBase),
  335. filepath.Join(templatesPath, templateAdminDir, templateBase),
  336. filepath.Join(templatesPath, templateAdminDir, templateProfile),
  337. }
  338. changePwdPaths := []string{
  339. filepath.Join(templatesPath, templateCommonDir, templateCommonBase),
  340. filepath.Join(templatesPath, templateAdminDir, templateBase),
  341. filepath.Join(templatesPath, templateCommonDir, templateChangePwd),
  342. }
  343. connectionsPaths := []string{
  344. filepath.Join(templatesPath, templateCommonDir, templateCommonBase),
  345. filepath.Join(templatesPath, templateAdminDir, templateBase),
  346. filepath.Join(templatesPath, templateAdminDir, templateConnections),
  347. }
  348. messagePaths := []string{
  349. filepath.Join(templatesPath, templateCommonDir, templateCommonBase),
  350. filepath.Join(templatesPath, templateAdminDir, templateBase),
  351. filepath.Join(templatesPath, templateCommonDir, templateMessage),
  352. }
  353. foldersPaths := []string{
  354. filepath.Join(templatesPath, templateCommonDir, templateCommonBase),
  355. filepath.Join(templatesPath, templateAdminDir, templateBase),
  356. filepath.Join(templatesPath, templateAdminDir, templateFolders),
  357. }
  358. folderPaths := []string{
  359. filepath.Join(templatesPath, templateCommonDir, templateCommonBase),
  360. filepath.Join(templatesPath, templateAdminDir, templateBase),
  361. filepath.Join(templatesPath, templateAdminDir, templateFsConfig),
  362. filepath.Join(templatesPath, templateAdminDir, templateFolder),
  363. }
  364. groupsPaths := []string{
  365. filepath.Join(templatesPath, templateCommonDir, templateCommonBase),
  366. filepath.Join(templatesPath, templateAdminDir, templateBase),
  367. filepath.Join(templatesPath, templateAdminDir, templateGroups),
  368. }
  369. groupPaths := []string{
  370. filepath.Join(templatesPath, templateCommonDir, templateCommonBase),
  371. filepath.Join(templatesPath, templateAdminDir, templateBase),
  372. filepath.Join(templatesPath, templateAdminDir, templateFsConfig),
  373. filepath.Join(templatesPath, templateAdminDir, templateGroup),
  374. }
  375. eventRulesPaths := []string{
  376. filepath.Join(templatesPath, templateCommonDir, templateCommonBase),
  377. filepath.Join(templatesPath, templateAdminDir, templateBase),
  378. filepath.Join(templatesPath, templateAdminDir, templateEventRules),
  379. }
  380. eventRulePaths := []string{
  381. filepath.Join(templatesPath, templateCommonDir, templateCommonBase),
  382. filepath.Join(templatesPath, templateAdminDir, templateBase),
  383. filepath.Join(templatesPath, templateAdminDir, templateEventRule),
  384. }
  385. eventActionsPaths := []string{
  386. filepath.Join(templatesPath, templateCommonDir, templateCommonBase),
  387. filepath.Join(templatesPath, templateAdminDir, templateBase),
  388. filepath.Join(templatesPath, templateAdminDir, templateEventActions),
  389. }
  390. eventActionPaths := []string{
  391. filepath.Join(templatesPath, templateCommonDir, templateCommonBase),
  392. filepath.Join(templatesPath, templateAdminDir, templateBase),
  393. filepath.Join(templatesPath, templateAdminDir, templateEventAction),
  394. }
  395. statusPaths := []string{
  396. filepath.Join(templatesPath, templateCommonDir, templateCommonBase),
  397. filepath.Join(templatesPath, templateAdminDir, templateBase),
  398. filepath.Join(templatesPath, templateAdminDir, templateStatus),
  399. }
  400. loginPaths := []string{
  401. filepath.Join(templatesPath, templateCommonDir, templateCommonBase),
  402. filepath.Join(templatesPath, templateCommonDir, templateCommonBaseLogin),
  403. filepath.Join(templatesPath, templateCommonDir, templateCommonLogin),
  404. }
  405. maintenancePaths := []string{
  406. filepath.Join(templatesPath, templateCommonDir, templateCommonBase),
  407. filepath.Join(templatesPath, templateAdminDir, templateBase),
  408. filepath.Join(templatesPath, templateAdminDir, templateMaintenance),
  409. }
  410. defenderPaths := []string{
  411. filepath.Join(templatesPath, templateCommonDir, templateCommonBase),
  412. filepath.Join(templatesPath, templateAdminDir, templateBase),
  413. filepath.Join(templatesPath, templateAdminDir, templateDefender),
  414. }
  415. ipListsPaths := []string{
  416. filepath.Join(templatesPath, templateCommonDir, templateCommonBase),
  417. filepath.Join(templatesPath, templateAdminDir, templateBase),
  418. filepath.Join(templatesPath, templateAdminDir, templateIPLists),
  419. }
  420. ipListPaths := []string{
  421. filepath.Join(templatesPath, templateCommonDir, templateCommonBase),
  422. filepath.Join(templatesPath, templateAdminDir, templateBase),
  423. filepath.Join(templatesPath, templateAdminDir, templateIPList),
  424. }
  425. mfaPaths := []string{
  426. filepath.Join(templatesPath, templateCommonDir, templateCommonBase),
  427. filepath.Join(templatesPath, templateAdminDir, templateBase),
  428. filepath.Join(templatesPath, templateAdminDir, templateMFA),
  429. }
  430. twoFactorPaths := []string{
  431. filepath.Join(templatesPath, templateCommonDir, templateCommonBase),
  432. filepath.Join(templatesPath, templateCommonDir, templateCommonBaseLogin),
  433. filepath.Join(templatesPath, templateCommonDir, templateTwoFactor),
  434. }
  435. twoFactorRecoveryPaths := []string{
  436. filepath.Join(templatesPath, templateCommonDir, templateCommonBase),
  437. filepath.Join(templatesPath, templateCommonDir, templateCommonBaseLogin),
  438. filepath.Join(templatesPath, templateCommonDir, templateTwoFactorRecovery),
  439. }
  440. setupPaths := []string{
  441. filepath.Join(templatesPath, templateCommonDir, templateCommonBase),
  442. filepath.Join(templatesPath, templateCommonDir, templateCommonBaseLogin),
  443. filepath.Join(templatesPath, templateAdminDir, templateSetup),
  444. }
  445. forgotPwdPaths := []string{
  446. filepath.Join(templatesPath, templateCommonDir, templateCommonBase),
  447. filepath.Join(templatesPath, templateCommonDir, templateCommonBaseLogin),
  448. filepath.Join(templatesPath, templateCommonDir, templateForgotPassword),
  449. }
  450. resetPwdPaths := []string{
  451. filepath.Join(templatesPath, templateCommonDir, templateCommonBase),
  452. filepath.Join(templatesPath, templateCommonDir, templateCommonBaseLogin),
  453. filepath.Join(templatesPath, templateCommonDir, templateResetPassword),
  454. }
  455. rolesPaths := []string{
  456. filepath.Join(templatesPath, templateCommonDir, templateCommonBase),
  457. filepath.Join(templatesPath, templateAdminDir, templateBase),
  458. filepath.Join(templatesPath, templateAdminDir, templateRoles),
  459. }
  460. rolePaths := []string{
  461. filepath.Join(templatesPath, templateCommonDir, templateCommonBase),
  462. filepath.Join(templatesPath, templateAdminDir, templateBase),
  463. filepath.Join(templatesPath, templateAdminDir, templateRole),
  464. }
  465. eventsPaths := []string{
  466. filepath.Join(templatesPath, templateCommonDir, templateCommonBase),
  467. filepath.Join(templatesPath, templateAdminDir, templateBase),
  468. filepath.Join(templatesPath, templateAdminDir, templateEvents),
  469. }
  470. configsPaths := []string{
  471. filepath.Join(templatesPath, templateCommonDir, templateCommonBase),
  472. filepath.Join(templatesPath, templateAdminDir, templateBase),
  473. filepath.Join(templatesPath, templateAdminDir, templateConfigs),
  474. }
  475. fsBaseTpl := template.New("fsBaseTemplate").Funcs(template.FuncMap{
  476. "ListFSProviders": func() []dataprovider.FilesystemProvider {
  477. return []dataprovider.FilesystemProvider{
  478. {FilesystemProvider: sdk.LocalFilesystemProvider},
  479. {FilesystemProvider: sdk.CryptedFilesystemProvider},
  480. {FilesystemProvider: sdk.S3FilesystemProvider},
  481. {FilesystemProvider: sdk.GCSFilesystemProvider},
  482. {FilesystemProvider: sdk.AzureBlobFilesystemProvider},
  483. {FilesystemProvider: sdk.SFTPFilesystemProvider},
  484. {FilesystemProvider: sdk.HTTPFilesystemProvider},
  485. }
  486. },
  487. "HumanizeBytes": util.ByteCountSI,
  488. })
  489. usersTmpl := util.LoadTemplate(nil, usersPaths...)
  490. userTmpl := util.LoadTemplate(fsBaseTpl, userPaths...)
  491. adminsTmpl := util.LoadTemplate(nil, adminsPaths...)
  492. adminTmpl := util.LoadTemplate(nil, adminPaths...)
  493. connectionsTmpl := util.LoadTemplate(nil, connectionsPaths...)
  494. messageTmpl := util.LoadTemplate(nil, messagePaths...)
  495. groupsTmpl := util.LoadTemplate(nil, groupsPaths...)
  496. groupTmpl := util.LoadTemplate(fsBaseTpl, groupPaths...)
  497. foldersTmpl := util.LoadTemplate(nil, foldersPaths...)
  498. folderTmpl := util.LoadTemplate(fsBaseTpl, folderPaths...)
  499. eventRulesTmpl := util.LoadTemplate(nil, eventRulesPaths...)
  500. eventRuleTmpl := util.LoadTemplate(fsBaseTpl, eventRulePaths...)
  501. eventActionsTmpl := util.LoadTemplate(nil, eventActionsPaths...)
  502. eventActionTmpl := util.LoadTemplate(nil, eventActionPaths...)
  503. statusTmpl := util.LoadTemplate(nil, statusPaths...)
  504. loginTmpl := util.LoadTemplate(nil, loginPaths...)
  505. profileTmpl := util.LoadTemplate(nil, profilePaths...)
  506. changePwdTmpl := util.LoadTemplate(nil, changePwdPaths...)
  507. maintenanceTmpl := util.LoadTemplate(nil, maintenancePaths...)
  508. defenderTmpl := util.LoadTemplate(nil, defenderPaths...)
  509. ipListsTmpl := util.LoadTemplate(nil, ipListsPaths...)
  510. ipListTmpl := util.LoadTemplate(nil, ipListPaths...)
  511. mfaTmpl := util.LoadTemplate(nil, mfaPaths...)
  512. twoFactorTmpl := util.LoadTemplate(nil, twoFactorPaths...)
  513. twoFactorRecoveryTmpl := util.LoadTemplate(nil, twoFactorRecoveryPaths...)
  514. setupTmpl := util.LoadTemplate(nil, setupPaths...)
  515. forgotPwdTmpl := util.LoadTemplate(nil, forgotPwdPaths...)
  516. resetPwdTmpl := util.LoadTemplate(nil, resetPwdPaths...)
  517. rolesTmpl := util.LoadTemplate(nil, rolesPaths...)
  518. roleTmpl := util.LoadTemplate(nil, rolePaths...)
  519. eventsTmpl := util.LoadTemplate(nil, eventsPaths...)
  520. configsTmpl := util.LoadTemplate(nil, configsPaths...)
  521. adminTemplates[templateUsers] = usersTmpl
  522. adminTemplates[templateUser] = userTmpl
  523. adminTemplates[templateAdmins] = adminsTmpl
  524. adminTemplates[templateAdmin] = adminTmpl
  525. adminTemplates[templateConnections] = connectionsTmpl
  526. adminTemplates[templateMessage] = messageTmpl
  527. adminTemplates[templateGroups] = groupsTmpl
  528. adminTemplates[templateGroup] = groupTmpl
  529. adminTemplates[templateFolders] = foldersTmpl
  530. adminTemplates[templateFolder] = folderTmpl
  531. adminTemplates[templateEventRules] = eventRulesTmpl
  532. adminTemplates[templateEventRule] = eventRuleTmpl
  533. adminTemplates[templateEventActions] = eventActionsTmpl
  534. adminTemplates[templateEventAction] = eventActionTmpl
  535. adminTemplates[templateStatus] = statusTmpl
  536. adminTemplates[templateCommonLogin] = loginTmpl
  537. adminTemplates[templateProfile] = profileTmpl
  538. adminTemplates[templateChangePwd] = changePwdTmpl
  539. adminTemplates[templateMaintenance] = maintenanceTmpl
  540. adminTemplates[templateDefender] = defenderTmpl
  541. adminTemplates[templateIPLists] = ipListsTmpl
  542. adminTemplates[templateIPList] = ipListTmpl
  543. adminTemplates[templateMFA] = mfaTmpl
  544. adminTemplates[templateTwoFactor] = twoFactorTmpl
  545. adminTemplates[templateTwoFactorRecovery] = twoFactorRecoveryTmpl
  546. adminTemplates[templateSetup] = setupTmpl
  547. adminTemplates[templateForgotPassword] = forgotPwdTmpl
  548. adminTemplates[templateResetPassword] = resetPwdTmpl
  549. adminTemplates[templateRoles] = rolesTmpl
  550. adminTemplates[templateRole] = roleTmpl
  551. adminTemplates[templateEvents] = eventsTmpl
  552. adminTemplates[templateConfigs] = configsTmpl
  553. }
  554. func isEventManagerResource(currentURL string) bool {
  555. if currentURL == webAdminEventRulesPath {
  556. return true
  557. }
  558. if currentURL == webAdminEventActionsPath {
  559. return true
  560. }
  561. if currentURL == webAdminEventRulePath || strings.HasPrefix(currentURL, webAdminEventRulePath+"/") {
  562. return true
  563. }
  564. if currentURL == webAdminEventActionPath || strings.HasPrefix(currentURL, webAdminEventActionPath+"/") {
  565. return true
  566. }
  567. return false
  568. }
  569. func isIPListsResource(currentURL string) bool {
  570. if currentURL == webDefenderPath {
  571. return true
  572. }
  573. if currentURL == webIPListsPath {
  574. return true
  575. }
  576. if strings.HasPrefix(currentURL, webIPListPath+"/") {
  577. return true
  578. }
  579. return false
  580. }
  581. func isServerManagerResource(currentURL string) bool {
  582. return currentURL == webEventsPath || currentURL == webStatusPath || currentURL == webMaintenancePath ||
  583. currentURL == webConfigsPath
  584. }
  585. func (s *httpdServer) getBasePageData(title, currentURL string, r *http.Request) basePage {
  586. var csrfToken string
  587. if currentURL != "" {
  588. csrfToken = createCSRFToken(util.GetIPFromRemoteAddress(r.RemoteAddr))
  589. }
  590. return basePage{
  591. commonBasePage: getCommonBasePage(r),
  592. Title: title,
  593. CurrentURL: currentURL,
  594. UsersURL: webUsersPath,
  595. UserURL: webUserPath,
  596. UserTemplateURL: webTemplateUser,
  597. AdminsURL: webAdminsPath,
  598. AdminURL: webAdminPath,
  599. GroupsURL: webGroupsPath,
  600. GroupURL: webGroupPath,
  601. FoldersURL: webFoldersPath,
  602. FolderURL: webFolderPath,
  603. FolderTemplateURL: webTemplateFolder,
  604. DefenderURL: webDefenderPath,
  605. IPListsURL: webIPListsPath,
  606. IPListURL: webIPListPath,
  607. EventsURL: webEventsPath,
  608. ConfigsURL: webConfigsPath,
  609. LogoutURL: webLogoutPath,
  610. LoginURL: webAdminLoginPath,
  611. ProfileURL: webAdminProfilePath,
  612. ChangePwdURL: webChangeAdminPwdPath,
  613. MFAURL: webAdminMFAPath,
  614. EventRulesURL: webAdminEventRulesPath,
  615. EventRuleURL: webAdminEventRulePath,
  616. EventActionsURL: webAdminEventActionsPath,
  617. EventActionURL: webAdminEventActionPath,
  618. RolesURL: webAdminRolesPath,
  619. RoleURL: webAdminRolePath,
  620. QuotaScanURL: webQuotaScanPath,
  621. ConnectionsURL: webConnectionsPath,
  622. StatusURL: webStatusPath,
  623. FolderQuotaScanURL: webScanVFolderPath,
  624. MaintenanceURL: webMaintenancePath,
  625. LoggedUser: getAdminFromToken(r),
  626. IsEventManagerPage: isEventManagerResource(currentURL),
  627. IsIPManagerPage: isIPListsResource(currentURL),
  628. IsServerManagerPage: isServerManagerResource(currentURL),
  629. HasDefender: common.Config.DefenderConfig.Enabled,
  630. HasSearcher: plugin.Handler.HasSearcher(),
  631. HasExternalLogin: isLoggedInWithOIDC(r),
  632. CSRFToken: csrfToken,
  633. Branding: s.binding.Branding.WebAdmin,
  634. }
  635. }
  636. func renderAdminTemplate(w http.ResponseWriter, tmplName string, data any) {
  637. err := adminTemplates[tmplName].ExecuteTemplate(w, tmplName, data)
  638. if err != nil {
  639. http.Error(w, err.Error(), http.StatusInternalServerError)
  640. }
  641. }
  642. func (s *httpdServer) renderMessagePageWithString(w http.ResponseWriter, r *http.Request, title string, statusCode int,
  643. err error, message, text string,
  644. ) {
  645. data := messagePage{
  646. basePage: s.getBasePageData(title, "", r),
  647. Error: getI18nError(err),
  648. Success: message,
  649. Text: text,
  650. }
  651. w.WriteHeader(statusCode)
  652. renderAdminTemplate(w, templateMessage, data)
  653. }
  654. func (s *httpdServer) renderMessagePage(w http.ResponseWriter, r *http.Request, title string, statusCode int,
  655. err error, message string,
  656. ) {
  657. s.renderMessagePageWithString(w, r, title, statusCode, err, message, "")
  658. }
  659. func (s *httpdServer) renderInternalServerErrorPage(w http.ResponseWriter, r *http.Request, err error) {
  660. s.renderMessagePage(w, r, util.I18nError500Title, http.StatusInternalServerError,
  661. util.NewI18nError(err, util.I18nError500Message), "")
  662. }
  663. func (s *httpdServer) renderBadRequestPage(w http.ResponseWriter, r *http.Request, err error) {
  664. s.renderMessagePage(w, r, util.I18nError400Title, http.StatusBadRequest,
  665. util.NewI18nError(err, util.I18nError400Message), "")
  666. }
  667. func (s *httpdServer) renderForbiddenPage(w http.ResponseWriter, r *http.Request, err error) {
  668. s.renderMessagePage(w, r, util.I18nError403Title, http.StatusForbidden,
  669. util.NewI18nError(err, util.I18nError403Message), "")
  670. }
  671. func (s *httpdServer) renderNotFoundPage(w http.ResponseWriter, r *http.Request, err error) {
  672. s.renderMessagePage(w, r, util.I18nError404Title, http.StatusNotFound,
  673. util.NewI18nError(err, util.I18nError404Message), "")
  674. }
  675. func (s *httpdServer) renderForgotPwdPage(w http.ResponseWriter, r *http.Request, err *util.I18nError, ip string) {
  676. data := forgotPwdPage{
  677. commonBasePage: getCommonBasePage(r),
  678. CurrentURL: webAdminForgotPwdPath,
  679. Error: err,
  680. CSRFToken: createCSRFToken(ip),
  681. LoginURL: webAdminLoginPath,
  682. Title: util.I18nForgotPwdTitle,
  683. Branding: s.binding.Branding.WebAdmin,
  684. }
  685. renderAdminTemplate(w, templateForgotPassword, data)
  686. }
  687. func (s *httpdServer) renderResetPwdPage(w http.ResponseWriter, r *http.Request, err *util.I18nError, ip string) {
  688. data := resetPwdPage{
  689. commonBasePage: getCommonBasePage(r),
  690. CurrentURL: webAdminResetPwdPath,
  691. Error: err,
  692. CSRFToken: createCSRFToken(ip),
  693. LoginURL: webAdminLoginPath,
  694. Title: util.I18nResetPwdTitle,
  695. Branding: s.binding.Branding.WebAdmin,
  696. }
  697. renderAdminTemplate(w, templateResetPassword, data)
  698. }
  699. func (s *httpdServer) renderTwoFactorPage(w http.ResponseWriter, r *http.Request, err *util.I18nError, ip string) {
  700. data := twoFactorPage{
  701. commonBasePage: getCommonBasePage(r),
  702. Title: pageTwoFactorTitle,
  703. CurrentURL: webAdminTwoFactorPath,
  704. Error: err,
  705. CSRFToken: createCSRFToken(ip),
  706. RecoveryURL: webAdminTwoFactorRecoveryPath,
  707. Branding: s.binding.Branding.WebAdmin,
  708. }
  709. renderAdminTemplate(w, templateTwoFactor, data)
  710. }
  711. func (s *httpdServer) renderTwoFactorRecoveryPage(w http.ResponseWriter, r *http.Request, err *util.I18nError, ip string) {
  712. data := twoFactorPage{
  713. commonBasePage: getCommonBasePage(r),
  714. Title: pageTwoFactorRecoveryTitle,
  715. CurrentURL: webAdminTwoFactorRecoveryPath,
  716. Error: err,
  717. CSRFToken: createCSRFToken(ip),
  718. Branding: s.binding.Branding.WebAdmin,
  719. }
  720. renderAdminTemplate(w, templateTwoFactorRecovery, data)
  721. }
  722. func (s *httpdServer) renderMFAPage(w http.ResponseWriter, r *http.Request) {
  723. data := mfaPage{
  724. basePage: s.getBasePageData(pageMFATitle, webAdminMFAPath, r),
  725. TOTPConfigs: mfa.GetAvailableTOTPConfigNames(),
  726. GenerateTOTPURL: webAdminTOTPGeneratePath,
  727. ValidateTOTPURL: webAdminTOTPValidatePath,
  728. SaveTOTPURL: webAdminTOTPSavePath,
  729. RecCodesURL: webAdminRecoveryCodesPath,
  730. }
  731. admin, err := dataprovider.AdminExists(data.LoggedUser.Username)
  732. if err != nil {
  733. s.renderInternalServerErrorPage(w, r, err)
  734. return
  735. }
  736. data.TOTPConfig = admin.Filters.TOTPConfig
  737. data.RequireTwoFactor = admin.Filters.RequireTwoFactor
  738. renderAdminTemplate(w, templateMFA, data)
  739. }
  740. func (s *httpdServer) renderProfilePage(w http.ResponseWriter, r *http.Request, err error) {
  741. data := profilePage{
  742. basePage: s.getBasePageData(util.I18nProfileTitle, webAdminProfilePath, r),
  743. Error: getI18nError(err),
  744. }
  745. admin, err := dataprovider.AdminExists(data.LoggedUser.Username)
  746. if err != nil {
  747. s.renderInternalServerErrorPage(w, r, err)
  748. return
  749. }
  750. data.AllowAPIKeyAuth = admin.Filters.AllowAPIKeyAuth
  751. data.Email = admin.Email
  752. data.Description = admin.Description
  753. renderAdminTemplate(w, templateProfile, data)
  754. }
  755. func (s *httpdServer) renderChangePasswordPage(w http.ResponseWriter, r *http.Request, err *util.I18nError) {
  756. data := changePasswordPage{
  757. basePage: s.getBasePageData(util.I18nChangePwdTitle, webChangeAdminPwdPath, r),
  758. Error: err,
  759. }
  760. renderAdminTemplate(w, templateChangePwd, data)
  761. }
  762. func (s *httpdServer) renderMaintenancePage(w http.ResponseWriter, r *http.Request, err error) {
  763. data := maintenancePage{
  764. basePage: s.getBasePageData(util.I18nMaintenanceTitle, webMaintenancePath, r),
  765. BackupPath: webBackupPath,
  766. RestorePath: webRestorePath,
  767. Error: getI18nError(err),
  768. }
  769. renderAdminTemplate(w, templateMaintenance, data)
  770. }
  771. func (s *httpdServer) renderConfigsPage(w http.ResponseWriter, r *http.Request, configs dataprovider.Configs,
  772. err error, section int,
  773. ) {
  774. configs.SetNilsToEmpty()
  775. if configs.SMTP.Port == 0 {
  776. configs.SMTP.Port = 587
  777. configs.SMTP.AuthType = 1
  778. configs.SMTP.Encryption = 2
  779. }
  780. if configs.ACME.HTTP01Challenge.Port == 0 {
  781. configs.ACME.HTTP01Challenge.Port = 80
  782. }
  783. data := configsPage{
  784. basePage: s.getBasePageData(util.I18nConfigsTitle, webConfigsPath, r),
  785. Configs: configs,
  786. ConfigSection: section,
  787. RedactedSecret: redactedSecret,
  788. OAuth2TokenURL: webOAuth2TokenPath,
  789. OAuth2RedirectURL: webOAuth2RedirectPath,
  790. Error: getI18nError(err),
  791. }
  792. renderAdminTemplate(w, templateConfigs, data)
  793. }
  794. func (s *httpdServer) renderAdminSetupPage(w http.ResponseWriter, r *http.Request, username, ip string, err *util.I18nError) {
  795. data := setupPage{
  796. commonBasePage: getCommonBasePage(r),
  797. Title: util.I18nSetupTitle,
  798. CurrentURL: webAdminSetupPath,
  799. CSRFToken: createCSRFToken(ip),
  800. Username: username,
  801. HasInstallationCode: installationCode != "",
  802. InstallationCodeHint: installationCodeHint,
  803. HideSupportLink: hideSupportLink,
  804. Error: err,
  805. Branding: s.binding.Branding.WebAdmin,
  806. }
  807. renderAdminTemplate(w, templateSetup, data)
  808. }
  809. func (s *httpdServer) renderAddUpdateAdminPage(w http.ResponseWriter, r *http.Request, admin *dataprovider.Admin,
  810. err error, isAdd bool) {
  811. groups, errGroups := s.getWebGroups(w, r, defaultQueryLimit, true)
  812. if errGroups != nil {
  813. return
  814. }
  815. roles, errRoles := s.getWebRoles(w, r, 10, true)
  816. if errRoles != nil {
  817. return
  818. }
  819. currentURL := webAdminPath
  820. title := util.I18nAddAdminTitle
  821. if !isAdd {
  822. currentURL = fmt.Sprintf("%v/%v", webAdminPath, url.PathEscape(admin.Username))
  823. title = util.I18nUpdateAdminTitle
  824. }
  825. data := adminPage{
  826. basePage: s.getBasePageData(title, currentURL, r),
  827. Admin: admin,
  828. Groups: groups,
  829. Roles: roles,
  830. Error: getI18nError(err),
  831. IsAdd: isAdd,
  832. }
  833. renderAdminTemplate(w, templateAdmin, data)
  834. }
  835. func (s *httpdServer) getUserPageTitleAndURL(mode userPageMode, username string) (string, string) {
  836. var title, currentURL string
  837. switch mode {
  838. case userPageModeAdd:
  839. title = util.I18nAddUserTitle
  840. currentURL = webUserPath
  841. case userPageModeUpdate:
  842. title = util.I18nUpdateUserTitle
  843. currentURL = fmt.Sprintf("%v/%v", webUserPath, url.PathEscape(username))
  844. case userPageModeTemplate:
  845. title = util.I18nTemplateUserTitle
  846. currentURL = webTemplateUser
  847. }
  848. return title, currentURL
  849. }
  850. func (s *httpdServer) renderUserPage(w http.ResponseWriter, r *http.Request, user *dataprovider.User,
  851. mode userPageMode, err error, admin *dataprovider.Admin,
  852. ) {
  853. user.SetEmptySecretsIfNil()
  854. title, currentURL := s.getUserPageTitleAndURL(mode, user.Username)
  855. if user.Password != "" && user.IsPasswordHashed() {
  856. switch mode {
  857. case userPageModeUpdate:
  858. user.Password = redactedSecret
  859. default:
  860. user.Password = ""
  861. }
  862. }
  863. user.FsConfig.RedactedSecret = redactedSecret
  864. basePage := s.getBasePageData(title, currentURL, r)
  865. if (mode == userPageModeAdd || mode == userPageModeTemplate) && len(user.Groups) == 0 && admin != nil {
  866. for _, group := range admin.Groups {
  867. user.Groups = append(user.Groups, sdk.GroupMapping{
  868. Name: group.Name,
  869. Type: group.Options.GetUserGroupType(),
  870. })
  871. }
  872. }
  873. var roles []dataprovider.Role
  874. if basePage.LoggedUser.Role == "" {
  875. var errRoles error
  876. roles, errRoles = s.getWebRoles(w, r, 10, true)
  877. if errRoles != nil {
  878. return
  879. }
  880. }
  881. folders, errFolders := s.getWebVirtualFolders(w, r, defaultQueryLimit, true)
  882. if errFolders != nil {
  883. return
  884. }
  885. groups, errGroups := s.getWebGroups(w, r, defaultQueryLimit, true)
  886. if errGroups != nil {
  887. return
  888. }
  889. data := userPage{
  890. basePage: basePage,
  891. Mode: mode,
  892. Error: getI18nError(err),
  893. User: user,
  894. ValidPerms: dataprovider.ValidPerms,
  895. ValidLoginMethods: dataprovider.ValidLoginMethods,
  896. ValidProtocols: dataprovider.ValidProtocols,
  897. TwoFactorProtocols: dataprovider.MFAProtocols,
  898. WebClientOptions: sdk.WebClientOptions,
  899. RootDirPerms: user.GetPermissionsForPath("/"),
  900. VirtualFolders: folders,
  901. Groups: groups,
  902. Roles: roles,
  903. CanImpersonate: os.Getuid() == 0,
  904. FsWrapper: fsWrapper{
  905. Filesystem: user.FsConfig,
  906. IsUserPage: true,
  907. IsGroupPage: false,
  908. IsHidden: basePage.LoggedUser.Filters.Preferences.HideFilesystem(),
  909. HasUsersBaseDir: dataprovider.HasUsersBaseDir(),
  910. DirPath: user.HomeDir,
  911. },
  912. }
  913. renderAdminTemplate(w, templateUser, data)
  914. }
  915. func (s *httpdServer) renderIPListPage(w http.ResponseWriter, r *http.Request, entry dataprovider.IPListEntry,
  916. mode genericPageMode, err error,
  917. ) {
  918. var title, currentURL string
  919. switch mode {
  920. case genericPageModeAdd:
  921. title = util.I18nAddIPListTitle
  922. currentURL = fmt.Sprintf("%s/%d", webIPListPath, entry.Type)
  923. case genericPageModeUpdate:
  924. title = util.I18nUpdateIPListTitle
  925. currentURL = fmt.Sprintf("%s/%d/%s", webIPListPath, entry.Type, url.PathEscape(entry.IPOrNet))
  926. }
  927. data := ipListPage{
  928. basePage: s.getBasePageData(title, currentURL, r),
  929. Error: getI18nError(err),
  930. Entry: &entry,
  931. Mode: mode,
  932. }
  933. renderAdminTemplate(w, templateIPList, data)
  934. }
  935. func (s *httpdServer) renderRolePage(w http.ResponseWriter, r *http.Request, role dataprovider.Role,
  936. mode genericPageMode, err error,
  937. ) {
  938. var title, currentURL string
  939. switch mode {
  940. case genericPageModeAdd:
  941. title = util.I18nRoleAddTitle
  942. currentURL = webAdminRolePath
  943. case genericPageModeUpdate:
  944. title = util.I18nRoleUpdateTitle
  945. currentURL = fmt.Sprintf("%s/%s", webAdminRolePath, url.PathEscape(role.Name))
  946. }
  947. data := rolePage{
  948. basePage: s.getBasePageData(title, currentURL, r),
  949. Error: getI18nError(err),
  950. Role: &role,
  951. Mode: mode,
  952. }
  953. renderAdminTemplate(w, templateRole, data)
  954. }
  955. func (s *httpdServer) renderGroupPage(w http.ResponseWriter, r *http.Request, group dataprovider.Group,
  956. mode genericPageMode, err error,
  957. ) {
  958. folders, errFolders := s.getWebVirtualFolders(w, r, defaultQueryLimit, true)
  959. if errFolders != nil {
  960. return
  961. }
  962. group.SetEmptySecretsIfNil()
  963. group.UserSettings.FsConfig.RedactedSecret = redactedSecret
  964. var title, currentURL string
  965. switch mode {
  966. case genericPageModeAdd:
  967. title = util.I18nAddGroupTitle
  968. currentURL = webGroupPath
  969. case genericPageModeUpdate:
  970. title = util.I18nUpdateGroupTitle
  971. currentURL = fmt.Sprintf("%v/%v", webGroupPath, url.PathEscape(group.Name))
  972. }
  973. group.UserSettings.FsConfig.RedactedSecret = redactedSecret
  974. group.UserSettings.FsConfig.SetEmptySecretsIfNil()
  975. data := groupPage{
  976. basePage: s.getBasePageData(title, currentURL, r),
  977. Error: getI18nError(err),
  978. Group: &group,
  979. Mode: mode,
  980. ValidPerms: dataprovider.ValidPerms,
  981. ValidLoginMethods: dataprovider.ValidLoginMethods,
  982. ValidProtocols: dataprovider.ValidProtocols,
  983. TwoFactorProtocols: dataprovider.MFAProtocols,
  984. WebClientOptions: sdk.WebClientOptions,
  985. VirtualFolders: folders,
  986. FsWrapper: fsWrapper{
  987. Filesystem: group.UserSettings.FsConfig,
  988. IsUserPage: false,
  989. IsGroupPage: true,
  990. HasUsersBaseDir: false,
  991. DirPath: group.UserSettings.HomeDir,
  992. },
  993. }
  994. renderAdminTemplate(w, templateGroup, data)
  995. }
  996. func (s *httpdServer) renderEventActionPage(w http.ResponseWriter, r *http.Request, action dataprovider.BaseEventAction,
  997. mode genericPageMode, err error,
  998. ) {
  999. action.Options.SetEmptySecretsIfNil()
  1000. var title, currentURL string
  1001. switch mode {
  1002. case genericPageModeAdd:
  1003. title = util.I18nAddActionTitle
  1004. currentURL = webAdminEventActionPath
  1005. case genericPageModeUpdate:
  1006. title = util.I18nUpdateActionTitle
  1007. currentURL = fmt.Sprintf("%s/%s", webAdminEventActionPath, url.PathEscape(action.Name))
  1008. }
  1009. if action.Options.HTTPConfig.Timeout == 0 {
  1010. action.Options.HTTPConfig.Timeout = 20
  1011. }
  1012. if action.Options.CmdConfig.Timeout == 0 {
  1013. action.Options.CmdConfig.Timeout = 20
  1014. }
  1015. if action.Options.PwdExpirationConfig.Threshold == 0 {
  1016. action.Options.PwdExpirationConfig.Threshold = 10
  1017. }
  1018. data := eventActionPage{
  1019. basePage: s.getBasePageData(title, currentURL, r),
  1020. Action: action,
  1021. ActionTypes: dataprovider.EventActionTypes,
  1022. FsActions: dataprovider.FsActionTypes,
  1023. HTTPMethods: dataprovider.SupportedHTTPActionMethods,
  1024. RedactedSecret: redactedSecret,
  1025. Error: getI18nError(err),
  1026. Mode: mode,
  1027. }
  1028. renderAdminTemplate(w, templateEventAction, data)
  1029. }
  1030. func (s *httpdServer) renderEventRulePage(w http.ResponseWriter, r *http.Request, rule dataprovider.EventRule,
  1031. mode genericPageMode, err error,
  1032. ) {
  1033. actions, errActions := s.getWebEventActions(w, r, defaultQueryLimit, true)
  1034. if errActions != nil {
  1035. return
  1036. }
  1037. var title, currentURL string
  1038. switch mode {
  1039. case genericPageModeAdd:
  1040. title = util.I18nAddRuleTitle
  1041. currentURL = webAdminEventRulePath
  1042. case genericPageModeUpdate:
  1043. title = util.I18nUpdateRuleTitle
  1044. currentURL = fmt.Sprintf("%v/%v", webAdminEventRulePath, url.PathEscape(rule.Name))
  1045. }
  1046. data := eventRulePage{
  1047. basePage: s.getBasePageData(title, currentURL, r),
  1048. Rule: rule,
  1049. TriggerTypes: dataprovider.EventTriggerTypes,
  1050. Actions: actions,
  1051. FsEvents: dataprovider.SupportedFsEvents,
  1052. Protocols: dataprovider.SupportedRuleConditionProtocols,
  1053. ProviderEvents: dataprovider.SupportedProviderEvents,
  1054. ProviderObjects: dataprovider.SupporteRuleConditionProviderObjects,
  1055. Error: getI18nError(err),
  1056. Mode: mode,
  1057. IsShared: s.isShared > 0,
  1058. }
  1059. renderAdminTemplate(w, templateEventRule, data)
  1060. }
  1061. func (s *httpdServer) renderFolderPage(w http.ResponseWriter, r *http.Request, folder vfs.BaseVirtualFolder,
  1062. mode folderPageMode, err error,
  1063. ) {
  1064. var title, currentURL string
  1065. switch mode {
  1066. case folderPageModeAdd:
  1067. title = util.I18nAddFolderTitle
  1068. currentURL = webFolderPath
  1069. case folderPageModeUpdate:
  1070. title = util.I18nUpdateFolderTitle
  1071. currentURL = fmt.Sprintf("%v/%v", webFolderPath, url.PathEscape(folder.Name))
  1072. case folderPageModeTemplate:
  1073. title = util.I18nTemplateFolderTitle
  1074. currentURL = webTemplateFolder
  1075. }
  1076. folder.FsConfig.RedactedSecret = redactedSecret
  1077. folder.FsConfig.SetEmptySecretsIfNil()
  1078. data := folderPage{
  1079. basePage: s.getBasePageData(title, currentURL, r),
  1080. Error: getI18nError(err),
  1081. Folder: folder,
  1082. Mode: mode,
  1083. FsWrapper: fsWrapper{
  1084. Filesystem: folder.FsConfig,
  1085. IsUserPage: false,
  1086. IsGroupPage: false,
  1087. HasUsersBaseDir: false,
  1088. DirPath: folder.MappedPath,
  1089. },
  1090. }
  1091. renderAdminTemplate(w, templateFolder, data)
  1092. }
  1093. func getFoldersForTemplate(r *http.Request) []string {
  1094. var res []string
  1095. for k := range r.Form {
  1096. if hasPrefixAndSuffix(k, "template_folders[", "][tpl_foldername]") {
  1097. r.Form.Add("tpl_foldername", r.Form.Get(k))
  1098. }
  1099. }
  1100. folderNames := r.Form["tpl_foldername"]
  1101. folders := make(map[string]bool)
  1102. for _, name := range folderNames {
  1103. name = strings.TrimSpace(name)
  1104. if name == "" {
  1105. continue
  1106. }
  1107. if _, ok := folders[name]; ok {
  1108. continue
  1109. }
  1110. folders[name] = true
  1111. res = append(res, name)
  1112. }
  1113. return res
  1114. }
  1115. func getUsersForTemplate(r *http.Request) []userTemplateFields {
  1116. var res []userTemplateFields
  1117. tplUsernames := r.Form["tpl_username"]
  1118. tplPasswords := r.Form["tpl_password"]
  1119. tplPublicKeys := r.Form["tpl_public_keys"]
  1120. users := make(map[string]bool)
  1121. for idx := range tplUsernames {
  1122. username := tplUsernames[idx]
  1123. password := ""
  1124. publicKey := ""
  1125. if len(tplPasswords) > idx {
  1126. password = strings.TrimSpace(tplPasswords[idx])
  1127. }
  1128. if len(tplPublicKeys) > idx {
  1129. publicKey = strings.TrimSpace(tplPublicKeys[idx])
  1130. }
  1131. if username == "" {
  1132. continue
  1133. }
  1134. if _, ok := users[username]; ok {
  1135. continue
  1136. }
  1137. users[username] = true
  1138. res = append(res, userTemplateFields{
  1139. Username: username,
  1140. Password: password,
  1141. PublicKeys: []string{publicKey},
  1142. })
  1143. }
  1144. return res
  1145. }
  1146. func getVirtualFoldersFromPostFields(r *http.Request) []vfs.VirtualFolder {
  1147. var virtualFolders []vfs.VirtualFolder
  1148. folderPaths := r.Form["vfolder_path"]
  1149. folderNames := r.Form["vfolder_name"]
  1150. folderQuotaSizes := r.Form["vfolder_quota_size"]
  1151. folderQuotaFiles := r.Form["vfolder_quota_files"]
  1152. for idx, p := range folderPaths {
  1153. name := ""
  1154. if len(folderNames) > idx {
  1155. name = folderNames[idx]
  1156. }
  1157. if p != "" && name != "" {
  1158. vfolder := vfs.VirtualFolder{
  1159. BaseVirtualFolder: vfs.BaseVirtualFolder{
  1160. Name: name,
  1161. },
  1162. VirtualPath: p,
  1163. QuotaFiles: -1,
  1164. QuotaSize: -1,
  1165. }
  1166. if len(folderQuotaSizes) > idx {
  1167. quotaSize, err := util.ParseBytes(folderQuotaSizes[idx])
  1168. if err == nil {
  1169. vfolder.QuotaSize = quotaSize
  1170. }
  1171. }
  1172. if len(folderQuotaFiles) > idx {
  1173. quotaFiles, err := strconv.Atoi(folderQuotaFiles[idx])
  1174. if err == nil {
  1175. vfolder.QuotaFiles = quotaFiles
  1176. }
  1177. }
  1178. virtualFolders = append(virtualFolders, vfolder)
  1179. }
  1180. }
  1181. return virtualFolders
  1182. }
  1183. func getSubDirPermissionsFromPostFields(r *http.Request) map[string][]string {
  1184. permissions := make(map[string][]string)
  1185. for idx, p := range r.Form["sub_perm_path"] {
  1186. if p != "" {
  1187. permissions[p] = r.Form["sub_perm_permissions"+strconv.Itoa(idx)]
  1188. }
  1189. }
  1190. return permissions
  1191. }
  1192. func getUserPermissionsFromPostFields(r *http.Request) map[string][]string {
  1193. permissions := getSubDirPermissionsFromPostFields(r)
  1194. permissions["/"] = r.Form["permissions"]
  1195. return permissions
  1196. }
  1197. func getAccessTimeRestrictionsFromPostFields(r *http.Request) []sdk.TimePeriod {
  1198. var result []sdk.TimePeriod
  1199. dayOfWeeks := r.Form["access_time_day_of_week"]
  1200. starts := r.Form["access_time_start"]
  1201. ends := r.Form["access_time_end"]
  1202. for idx, dayOfWeek := range dayOfWeeks {
  1203. dayOfWeek = strings.TrimSpace(dayOfWeek)
  1204. start := ""
  1205. if len(starts) > idx {
  1206. start = strings.TrimSpace(starts[idx])
  1207. }
  1208. end := ""
  1209. if len(ends) > idx {
  1210. end = strings.TrimSpace(ends[idx])
  1211. }
  1212. dayNumber, err := strconv.Atoi(dayOfWeek)
  1213. if err == nil && start != "" && end != "" {
  1214. result = append(result, sdk.TimePeriod{
  1215. DayOfWeek: dayNumber,
  1216. From: start,
  1217. To: end,
  1218. })
  1219. }
  1220. }
  1221. return result
  1222. }
  1223. func getBandwidthLimitsFromPostFields(r *http.Request) ([]sdk.BandwidthLimit, error) {
  1224. var result []sdk.BandwidthLimit
  1225. bwSources := r.Form["bandwidth_limit_sources"]
  1226. uploadSources := r.Form["upload_bandwidth_source"]
  1227. downloadSources := r.Form["download_bandwidth_source"]
  1228. for idx, bwSource := range bwSources {
  1229. sources := getSliceFromDelimitedValues(bwSource, ",")
  1230. if len(sources) > 0 {
  1231. bwLimit := sdk.BandwidthLimit{
  1232. Sources: sources,
  1233. }
  1234. ul := ""
  1235. dl := ""
  1236. if len(uploadSources) > idx {
  1237. ul = uploadSources[idx]
  1238. }
  1239. if len(downloadSources) > idx {
  1240. dl = downloadSources[idx]
  1241. }
  1242. if ul != "" {
  1243. bandwidthUL, err := strconv.ParseInt(ul, 10, 64)
  1244. if err != nil {
  1245. return result, fmt.Errorf("invalid upload_bandwidth_source%v %q: %w", idx, ul, err)
  1246. }
  1247. bwLimit.UploadBandwidth = bandwidthUL
  1248. }
  1249. if dl != "" {
  1250. bandwidthDL, err := strconv.ParseInt(dl, 10, 64)
  1251. if err != nil {
  1252. return result, fmt.Errorf("invalid download_bandwidth_source%v %q: %w", idx, ul, err)
  1253. }
  1254. bwLimit.DownloadBandwidth = bandwidthDL
  1255. }
  1256. result = append(result, bwLimit)
  1257. }
  1258. }
  1259. return result, nil
  1260. }
  1261. func getPatterDenyPolicyFromString(policy string) int {
  1262. denyPolicy := sdk.DenyPolicyDefault
  1263. if policy == "1" {
  1264. denyPolicy = sdk.DenyPolicyHide
  1265. }
  1266. return denyPolicy
  1267. }
  1268. func getFilePatternsFromPostField(r *http.Request) []sdk.PatternsFilter {
  1269. var result []sdk.PatternsFilter
  1270. patternPaths := r.Form["pattern_path"]
  1271. patterns := r.Form["patterns"]
  1272. patternTypes := r.Form["pattern_type"]
  1273. policies := r.Form["pattern_policy"]
  1274. allowedPatterns := make(map[string][]string)
  1275. deniedPatterns := make(map[string][]string)
  1276. patternPolicies := make(map[string]string)
  1277. for idx := range patternPaths {
  1278. p := patternPaths[idx]
  1279. filters := strings.ReplaceAll(patterns[idx], " ", "")
  1280. patternType := patternTypes[idx]
  1281. patternPolicy := policies[idx]
  1282. if p != "" && filters != "" {
  1283. if patternType == "allowed" {
  1284. allowedPatterns[p] = append(allowedPatterns[p], strings.Split(filters, ",")...)
  1285. } else {
  1286. deniedPatterns[p] = append(deniedPatterns[p], strings.Split(filters, ",")...)
  1287. }
  1288. if patternPolicy != "" && patternPolicy != "0" {
  1289. patternPolicies[p] = patternPolicy
  1290. }
  1291. }
  1292. }
  1293. for dirAllowed, allowPatterns := range allowedPatterns {
  1294. filter := sdk.PatternsFilter{
  1295. Path: dirAllowed,
  1296. AllowedPatterns: allowPatterns,
  1297. DenyPolicy: getPatterDenyPolicyFromString(patternPolicies[dirAllowed]),
  1298. }
  1299. for dirDenied, denPatterns := range deniedPatterns {
  1300. if dirAllowed == dirDenied {
  1301. filter.DeniedPatterns = denPatterns
  1302. break
  1303. }
  1304. }
  1305. result = append(result, filter)
  1306. }
  1307. for dirDenied, denPatterns := range deniedPatterns {
  1308. found := false
  1309. for _, res := range result {
  1310. if res.Path == dirDenied {
  1311. found = true
  1312. break
  1313. }
  1314. }
  1315. if !found {
  1316. result = append(result, sdk.PatternsFilter{
  1317. Path: dirDenied,
  1318. DeniedPatterns: denPatterns,
  1319. DenyPolicy: getPatterDenyPolicyFromString(patternPolicies[dirDenied]),
  1320. })
  1321. }
  1322. }
  1323. return result
  1324. }
  1325. func getGroupsFromUserPostFields(r *http.Request) []sdk.GroupMapping {
  1326. var groups []sdk.GroupMapping
  1327. primaryGroup := strings.TrimSpace(r.Form.Get("primary_group"))
  1328. if primaryGroup != "" {
  1329. groups = append(groups, sdk.GroupMapping{
  1330. Name: primaryGroup,
  1331. Type: sdk.GroupTypePrimary,
  1332. })
  1333. }
  1334. secondaryGroups := r.Form["secondary_groups"]
  1335. for _, name := range secondaryGroups {
  1336. groups = append(groups, sdk.GroupMapping{
  1337. Name: strings.TrimSpace(name),
  1338. Type: sdk.GroupTypeSecondary,
  1339. })
  1340. }
  1341. membershipGroups := r.Form["membership_groups"]
  1342. for _, name := range membershipGroups {
  1343. groups = append(groups, sdk.GroupMapping{
  1344. Name: strings.TrimSpace(name),
  1345. Type: sdk.GroupTypeMembership,
  1346. })
  1347. }
  1348. return groups
  1349. }
  1350. func getFiltersFromUserPostFields(r *http.Request) (sdk.BaseUserFilters, error) {
  1351. var filters sdk.BaseUserFilters
  1352. bwLimits, err := getBandwidthLimitsFromPostFields(r)
  1353. if err != nil {
  1354. return filters, err
  1355. }
  1356. maxFileSize, err := util.ParseBytes(r.Form.Get("max_upload_file_size"))
  1357. if err != nil {
  1358. return filters, util.NewI18nError(fmt.Errorf("invalid max upload file size: %w", err), util.I18nErrorInvalidMaxFilesize)
  1359. }
  1360. defaultSharesExpiration, err := strconv.Atoi(r.Form.Get("default_shares_expiration"))
  1361. if err != nil {
  1362. return filters, fmt.Errorf("invalid default shares expiration: %w", err)
  1363. }
  1364. maxSharesExpiration, err := strconv.Atoi(r.Form.Get("max_shares_expiration"))
  1365. if err != nil {
  1366. return filters, fmt.Errorf("invalid max shares expiration: %w", err)
  1367. }
  1368. passwordExpiration, err := strconv.Atoi(r.Form.Get("password_expiration"))
  1369. if err != nil {
  1370. return filters, fmt.Errorf("invalid password expiration: %w", err)
  1371. }
  1372. passwordStrength, err := strconv.Atoi(r.Form.Get("password_strength"))
  1373. if err != nil {
  1374. return filters, fmt.Errorf("invalid password strength: %w", err)
  1375. }
  1376. if r.Form.Get("ftp_security") == "1" {
  1377. filters.FTPSecurity = 1
  1378. }
  1379. filters.BandwidthLimits = bwLimits
  1380. filters.AllowedIP = getSliceFromDelimitedValues(r.Form.Get("allowed_ip"), ",")
  1381. filters.DeniedIP = getSliceFromDelimitedValues(r.Form.Get("denied_ip"), ",")
  1382. filters.DeniedLoginMethods = r.Form["denied_login_methods"]
  1383. filters.DeniedProtocols = r.Form["denied_protocols"]
  1384. filters.TwoFactorAuthProtocols = r.Form["required_two_factor_protocols"]
  1385. filters.FilePatterns = getFilePatternsFromPostField(r)
  1386. filters.TLSUsername = sdk.TLSUsername(strings.TrimSpace(r.Form.Get("tls_username")))
  1387. filters.WebClient = r.Form["web_client_options"]
  1388. filters.DefaultSharesExpiration = defaultSharesExpiration
  1389. filters.MaxSharesExpiration = maxSharesExpiration
  1390. filters.PasswordExpiration = passwordExpiration
  1391. filters.PasswordStrength = passwordStrength
  1392. filters.AccessTime = getAccessTimeRestrictionsFromPostFields(r)
  1393. hooks := r.Form["hooks"]
  1394. if util.Contains(hooks, "external_auth_disabled") {
  1395. filters.Hooks.ExternalAuthDisabled = true
  1396. }
  1397. if util.Contains(hooks, "pre_login_disabled") {
  1398. filters.Hooks.PreLoginDisabled = true
  1399. }
  1400. if util.Contains(hooks, "check_password_disabled") {
  1401. filters.Hooks.CheckPasswordDisabled = true
  1402. }
  1403. filters.IsAnonymous = r.Form.Get("is_anonymous") != ""
  1404. filters.DisableFsChecks = r.Form.Get("disable_fs_checks") != ""
  1405. filters.AllowAPIKeyAuth = r.Form.Get("allow_api_key_auth") != ""
  1406. filters.StartDirectory = strings.TrimSpace(r.Form.Get("start_directory"))
  1407. filters.MaxUploadFileSize = maxFileSize
  1408. filters.ExternalAuthCacheTime, err = strconv.ParseInt(r.Form.Get("external_auth_cache_time"), 10, 64)
  1409. if err != nil {
  1410. return filters, fmt.Errorf("invalid external auth cache time: %w", err)
  1411. }
  1412. return filters, nil
  1413. }
  1414. func getSecretFromFormField(r *http.Request, field string) *kms.Secret {
  1415. secret := kms.NewPlainSecret(r.Form.Get(field))
  1416. if strings.TrimSpace(secret.GetPayload()) == redactedSecret {
  1417. secret.SetStatus(sdkkms.SecretStatusRedacted)
  1418. }
  1419. if strings.TrimSpace(secret.GetPayload()) == "" {
  1420. secret.SetStatus("")
  1421. }
  1422. return secret
  1423. }
  1424. func getS3Config(r *http.Request) (vfs.S3FsConfig, error) {
  1425. var err error
  1426. config := vfs.S3FsConfig{}
  1427. config.Bucket = strings.TrimSpace(r.Form.Get("s3_bucket"))
  1428. config.Region = strings.TrimSpace(r.Form.Get("s3_region"))
  1429. config.AccessKey = strings.TrimSpace(r.Form.Get("s3_access_key"))
  1430. config.RoleARN = strings.TrimSpace(r.Form.Get("s3_role_arn"))
  1431. config.AccessSecret = getSecretFromFormField(r, "s3_access_secret")
  1432. config.Endpoint = strings.TrimSpace(r.Form.Get("s3_endpoint"))
  1433. config.StorageClass = strings.TrimSpace(r.Form.Get("s3_storage_class"))
  1434. config.ACL = strings.TrimSpace(r.Form.Get("s3_acl"))
  1435. config.KeyPrefix = strings.TrimSpace(strings.TrimPrefix(r.Form.Get("s3_key_prefix"), "/"))
  1436. config.UploadPartSize, err = strconv.ParseInt(r.Form.Get("s3_upload_part_size"), 10, 64)
  1437. if err != nil {
  1438. return config, fmt.Errorf("invalid s3 upload part size: %w", err)
  1439. }
  1440. config.UploadConcurrency, err = strconv.Atoi(r.Form.Get("s3_upload_concurrency"))
  1441. if err != nil {
  1442. return config, fmt.Errorf("invalid s3 upload concurrency: %w", err)
  1443. }
  1444. config.DownloadPartSize, err = strconv.ParseInt(r.Form.Get("s3_download_part_size"), 10, 64)
  1445. if err != nil {
  1446. return config, fmt.Errorf("invalid s3 download part size: %w", err)
  1447. }
  1448. config.DownloadConcurrency, err = strconv.Atoi(r.Form.Get("s3_download_concurrency"))
  1449. if err != nil {
  1450. return config, fmt.Errorf("invalid s3 download concurrency: %w", err)
  1451. }
  1452. config.ForcePathStyle = r.Form.Get("s3_force_path_style") != ""
  1453. config.SkipTLSVerify = r.Form.Get("s3_skip_tls_verify") != ""
  1454. config.DownloadPartMaxTime, err = strconv.Atoi(r.Form.Get("s3_download_part_max_time"))
  1455. if err != nil {
  1456. return config, fmt.Errorf("invalid s3 download part max time: %w", err)
  1457. }
  1458. config.UploadPartMaxTime, err = strconv.Atoi(r.Form.Get("s3_upload_part_max_time"))
  1459. if err != nil {
  1460. return config, fmt.Errorf("invalid s3 upload part max time: %w", err)
  1461. }
  1462. return config, nil
  1463. }
  1464. func getGCSConfig(r *http.Request) (vfs.GCSFsConfig, error) {
  1465. var err error
  1466. config := vfs.GCSFsConfig{}
  1467. config.Bucket = strings.TrimSpace(r.Form.Get("gcs_bucket"))
  1468. config.StorageClass = strings.TrimSpace(r.Form.Get("gcs_storage_class"))
  1469. config.ACL = strings.TrimSpace(r.Form.Get("gcs_acl"))
  1470. config.KeyPrefix = strings.TrimSpace(strings.TrimPrefix(r.Form.Get("gcs_key_prefix"), "/"))
  1471. uploadPartSize, err := strconv.ParseInt(r.Form.Get("gcs_upload_part_size"), 10, 64)
  1472. if err == nil {
  1473. config.UploadPartSize = uploadPartSize
  1474. }
  1475. uploadPartMaxTime, err := strconv.Atoi(r.Form.Get("gcs_upload_part_max_time"))
  1476. if err == nil {
  1477. config.UploadPartMaxTime = uploadPartMaxTime
  1478. }
  1479. autoCredentials := r.Form.Get("gcs_auto_credentials")
  1480. if autoCredentials != "" {
  1481. config.AutomaticCredentials = 1
  1482. } else {
  1483. config.AutomaticCredentials = 0
  1484. }
  1485. credentials, _, err := r.FormFile("gcs_credential_file")
  1486. if err == http.ErrMissingFile {
  1487. return config, nil
  1488. }
  1489. if err != nil {
  1490. return config, err
  1491. }
  1492. defer credentials.Close()
  1493. fileBytes, err := io.ReadAll(credentials)
  1494. if err != nil || len(fileBytes) == 0 {
  1495. if len(fileBytes) == 0 {
  1496. err = errors.New("credentials file size must be greater than 0")
  1497. }
  1498. return config, err
  1499. }
  1500. config.Credentials = kms.NewPlainSecret(string(fileBytes))
  1501. config.AutomaticCredentials = 0
  1502. return config, err
  1503. }
  1504. func getSFTPConfig(r *http.Request) (vfs.SFTPFsConfig, error) {
  1505. var err error
  1506. config := vfs.SFTPFsConfig{}
  1507. config.Endpoint = strings.TrimSpace(r.Form.Get("sftp_endpoint"))
  1508. config.Username = strings.TrimSpace(r.Form.Get("sftp_username"))
  1509. config.Password = getSecretFromFormField(r, "sftp_password")
  1510. config.PrivateKey = getSecretFromFormField(r, "sftp_private_key")
  1511. config.KeyPassphrase = getSecretFromFormField(r, "sftp_key_passphrase")
  1512. fingerprintsFormValue := r.Form.Get("sftp_fingerprints")
  1513. config.Fingerprints = getSliceFromDelimitedValues(fingerprintsFormValue, "\n")
  1514. config.Prefix = strings.TrimSpace(r.Form.Get("sftp_prefix"))
  1515. config.DisableCouncurrentReads = r.Form.Get("sftp_disable_concurrent_reads") != ""
  1516. config.BufferSize, err = strconv.ParseInt(r.Form.Get("sftp_buffer_size"), 10, 64)
  1517. if r.Form.Get("sftp_equality_check_mode") != "" {
  1518. config.EqualityCheckMode = 1
  1519. } else {
  1520. config.EqualityCheckMode = 0
  1521. }
  1522. if err != nil {
  1523. return config, fmt.Errorf("invalid SFTP buffer size: %w", err)
  1524. }
  1525. return config, nil
  1526. }
  1527. func getHTTPFsConfig(r *http.Request) vfs.HTTPFsConfig {
  1528. config := vfs.HTTPFsConfig{}
  1529. config.Endpoint = strings.TrimSpace(r.Form.Get("http_endpoint"))
  1530. config.Username = strings.TrimSpace(r.Form.Get("http_username"))
  1531. config.SkipTLSVerify = r.Form.Get("http_skip_tls_verify") != ""
  1532. config.Password = getSecretFromFormField(r, "http_password")
  1533. config.APIKey = getSecretFromFormField(r, "http_api_key")
  1534. if r.Form.Get("http_equality_check_mode") != "" {
  1535. config.EqualityCheckMode = 1
  1536. } else {
  1537. config.EqualityCheckMode = 0
  1538. }
  1539. return config
  1540. }
  1541. func getAzureConfig(r *http.Request) (vfs.AzBlobFsConfig, error) {
  1542. var err error
  1543. config := vfs.AzBlobFsConfig{}
  1544. config.Container = strings.TrimSpace(r.Form.Get("az_container"))
  1545. config.AccountName = strings.TrimSpace(r.Form.Get("az_account_name"))
  1546. config.AccountKey = getSecretFromFormField(r, "az_account_key")
  1547. config.SASURL = getSecretFromFormField(r, "az_sas_url")
  1548. config.Endpoint = strings.TrimSpace(r.Form.Get("az_endpoint"))
  1549. config.KeyPrefix = strings.TrimSpace(strings.TrimPrefix(r.Form.Get("az_key_prefix"), "/"))
  1550. config.AccessTier = strings.TrimSpace(r.Form.Get("az_access_tier"))
  1551. config.UseEmulator = r.Form.Get("az_use_emulator") != ""
  1552. config.UploadPartSize, err = strconv.ParseInt(r.Form.Get("az_upload_part_size"), 10, 64)
  1553. if err != nil {
  1554. return config, fmt.Errorf("invalid azure upload part size: %w", err)
  1555. }
  1556. config.UploadConcurrency, err = strconv.Atoi(r.Form.Get("az_upload_concurrency"))
  1557. if err != nil {
  1558. return config, fmt.Errorf("invalid azure upload concurrency: %w", err)
  1559. }
  1560. config.DownloadPartSize, err = strconv.ParseInt(r.Form.Get("az_download_part_size"), 10, 64)
  1561. if err != nil {
  1562. return config, fmt.Errorf("invalid azure download part size: %w", err)
  1563. }
  1564. config.DownloadConcurrency, err = strconv.Atoi(r.Form.Get("az_download_concurrency"))
  1565. if err != nil {
  1566. return config, fmt.Errorf("invalid azure download concurrency: %w", err)
  1567. }
  1568. return config, nil
  1569. }
  1570. func getOsConfigFromPostFields(r *http.Request, readBufferField, writeBufferField string) sdk.OSFsConfig {
  1571. config := sdk.OSFsConfig{}
  1572. readBuffer, err := strconv.Atoi(r.Form.Get(readBufferField))
  1573. if err == nil {
  1574. config.ReadBufferSize = readBuffer
  1575. }
  1576. writeBuffer, err := strconv.Atoi(r.Form.Get(writeBufferField))
  1577. if err == nil {
  1578. config.WriteBufferSize = writeBuffer
  1579. }
  1580. return config
  1581. }
  1582. func getFsConfigFromPostFields(r *http.Request) (vfs.Filesystem, error) {
  1583. var fs vfs.Filesystem
  1584. fs.Provider = sdk.GetProviderByName(r.Form.Get("fs_provider"))
  1585. switch fs.Provider {
  1586. case sdk.LocalFilesystemProvider:
  1587. fs.OSConfig = getOsConfigFromPostFields(r, "osfs_read_buffer_size", "osfs_write_buffer_size")
  1588. case sdk.S3FilesystemProvider:
  1589. config, err := getS3Config(r)
  1590. if err != nil {
  1591. return fs, err
  1592. }
  1593. fs.S3Config = config
  1594. case sdk.AzureBlobFilesystemProvider:
  1595. config, err := getAzureConfig(r)
  1596. if err != nil {
  1597. return fs, err
  1598. }
  1599. fs.AzBlobConfig = config
  1600. case sdk.GCSFilesystemProvider:
  1601. config, err := getGCSConfig(r)
  1602. if err != nil {
  1603. return fs, err
  1604. }
  1605. fs.GCSConfig = config
  1606. case sdk.CryptedFilesystemProvider:
  1607. fs.CryptConfig.Passphrase = getSecretFromFormField(r, "crypt_passphrase")
  1608. fs.CryptConfig.OSFsConfig = getOsConfigFromPostFields(r, "cryptfs_read_buffer_size", "cryptfs_write_buffer_size")
  1609. case sdk.SFTPFilesystemProvider:
  1610. config, err := getSFTPConfig(r)
  1611. if err != nil {
  1612. return fs, err
  1613. }
  1614. fs.SFTPConfig = config
  1615. case sdk.HTTPFilesystemProvider:
  1616. fs.HTTPConfig = getHTTPFsConfig(r)
  1617. }
  1618. return fs, nil
  1619. }
  1620. func getAdminHiddenUserPageSections(r *http.Request) int {
  1621. var result int
  1622. for _, val := range r.Form["user_page_hidden_sections"] {
  1623. switch val {
  1624. case "1":
  1625. result++
  1626. case "2":
  1627. result += 2
  1628. case "3":
  1629. result += 4
  1630. case "4":
  1631. result += 8
  1632. case "5":
  1633. result += 16
  1634. case "6":
  1635. result += 32
  1636. case "7":
  1637. result += 64
  1638. }
  1639. }
  1640. return result
  1641. }
  1642. func getAdminFromPostFields(r *http.Request) (dataprovider.Admin, error) {
  1643. var admin dataprovider.Admin
  1644. err := r.ParseForm()
  1645. if err != nil {
  1646. return admin, util.NewI18nError(err, util.I18nErrorInvalidForm)
  1647. }
  1648. status, err := strconv.Atoi(r.Form.Get("status"))
  1649. if err != nil {
  1650. return admin, fmt.Errorf("invalid status: %w", err)
  1651. }
  1652. admin.Username = strings.TrimSpace(r.Form.Get("username"))
  1653. admin.Password = strings.TrimSpace(r.Form.Get("password"))
  1654. admin.Permissions = r.Form["permissions"]
  1655. admin.Email = strings.TrimSpace(r.Form.Get("email"))
  1656. admin.Status = status
  1657. admin.Role = strings.TrimSpace(r.Form.Get("role"))
  1658. admin.Filters.AllowList = getSliceFromDelimitedValues(r.Form.Get("allowed_ip"), ",")
  1659. admin.Filters.AllowAPIKeyAuth = r.Form.Get("allow_api_key_auth") != ""
  1660. admin.Filters.RequireTwoFactor = r.Form.Get("require_two_factor") != ""
  1661. admin.Filters.RequirePasswordChange = r.Form.Get("require_password_change") != ""
  1662. admin.AdditionalInfo = r.Form.Get("additional_info")
  1663. admin.Description = r.Form.Get("description")
  1664. admin.Filters.Preferences.HideUserPageSections = getAdminHiddenUserPageSections(r)
  1665. admin.Filters.Preferences.DefaultUsersExpiration = 0
  1666. if val := r.Form.Get("default_users_expiration"); val != "" {
  1667. defaultUsersExpiration, err := strconv.Atoi(r.Form.Get("default_users_expiration"))
  1668. if err != nil {
  1669. return admin, fmt.Errorf("invalid default users expiration: %w", err)
  1670. }
  1671. admin.Filters.Preferences.DefaultUsersExpiration = defaultUsersExpiration
  1672. }
  1673. for k := range r.Form {
  1674. if hasPrefixAndSuffix(k, "groups[", "][group]") {
  1675. groupName := strings.TrimSpace(r.Form.Get(k))
  1676. if groupName != "" {
  1677. group := dataprovider.AdminGroupMapping{
  1678. Name: groupName,
  1679. }
  1680. base, _ := strings.CutSuffix(k, "[group]")
  1681. addAsGroupType := strings.TrimSpace(r.Form.Get(base + "[group_type]"))
  1682. switch addAsGroupType {
  1683. case "1":
  1684. group.Options.AddToUsersAs = dataprovider.GroupAddToUsersAsPrimary
  1685. case "2":
  1686. group.Options.AddToUsersAs = dataprovider.GroupAddToUsersAsSecondary
  1687. default:
  1688. group.Options.AddToUsersAs = dataprovider.GroupAddToUsersAsMembership
  1689. }
  1690. admin.Groups = append(admin.Groups, group)
  1691. }
  1692. }
  1693. }
  1694. return admin, nil
  1695. }
  1696. func replacePlaceholders(field string, replacements map[string]string) string {
  1697. for k, v := range replacements {
  1698. field = strings.ReplaceAll(field, k, v)
  1699. }
  1700. return field
  1701. }
  1702. func getFolderFromTemplate(folder vfs.BaseVirtualFolder, name string) vfs.BaseVirtualFolder {
  1703. folder.Name = name
  1704. replacements := make(map[string]string)
  1705. replacements["%name%"] = folder.Name
  1706. folder.MappedPath = replacePlaceholders(folder.MappedPath, replacements)
  1707. folder.Description = replacePlaceholders(folder.Description, replacements)
  1708. switch folder.FsConfig.Provider {
  1709. case sdk.CryptedFilesystemProvider:
  1710. folder.FsConfig.CryptConfig = getCryptFsFromTemplate(folder.FsConfig.CryptConfig, replacements)
  1711. case sdk.S3FilesystemProvider:
  1712. folder.FsConfig.S3Config = getS3FsFromTemplate(folder.FsConfig.S3Config, replacements)
  1713. case sdk.GCSFilesystemProvider:
  1714. folder.FsConfig.GCSConfig = getGCSFsFromTemplate(folder.FsConfig.GCSConfig, replacements)
  1715. case sdk.AzureBlobFilesystemProvider:
  1716. folder.FsConfig.AzBlobConfig = getAzBlobFsFromTemplate(folder.FsConfig.AzBlobConfig, replacements)
  1717. case sdk.SFTPFilesystemProvider:
  1718. folder.FsConfig.SFTPConfig = getSFTPFsFromTemplate(folder.FsConfig.SFTPConfig, replacements)
  1719. case sdk.HTTPFilesystemProvider:
  1720. folder.FsConfig.HTTPConfig = getHTTPFsFromTemplate(folder.FsConfig.HTTPConfig, replacements)
  1721. }
  1722. return folder
  1723. }
  1724. func getCryptFsFromTemplate(fsConfig vfs.CryptFsConfig, replacements map[string]string) vfs.CryptFsConfig {
  1725. if fsConfig.Passphrase != nil {
  1726. if fsConfig.Passphrase.IsPlain() {
  1727. payload := replacePlaceholders(fsConfig.Passphrase.GetPayload(), replacements)
  1728. fsConfig.Passphrase = kms.NewPlainSecret(payload)
  1729. }
  1730. }
  1731. return fsConfig
  1732. }
  1733. func getS3FsFromTemplate(fsConfig vfs.S3FsConfig, replacements map[string]string) vfs.S3FsConfig {
  1734. fsConfig.KeyPrefix = replacePlaceholders(fsConfig.KeyPrefix, replacements)
  1735. fsConfig.AccessKey = replacePlaceholders(fsConfig.AccessKey, replacements)
  1736. if fsConfig.AccessSecret != nil && fsConfig.AccessSecret.IsPlain() {
  1737. payload := replacePlaceholders(fsConfig.AccessSecret.GetPayload(), replacements)
  1738. fsConfig.AccessSecret = kms.NewPlainSecret(payload)
  1739. }
  1740. return fsConfig
  1741. }
  1742. func getGCSFsFromTemplate(fsConfig vfs.GCSFsConfig, replacements map[string]string) vfs.GCSFsConfig {
  1743. fsConfig.KeyPrefix = replacePlaceholders(fsConfig.KeyPrefix, replacements)
  1744. return fsConfig
  1745. }
  1746. func getAzBlobFsFromTemplate(fsConfig vfs.AzBlobFsConfig, replacements map[string]string) vfs.AzBlobFsConfig {
  1747. fsConfig.KeyPrefix = replacePlaceholders(fsConfig.KeyPrefix, replacements)
  1748. fsConfig.AccountName = replacePlaceholders(fsConfig.AccountName, replacements)
  1749. if fsConfig.AccountKey != nil && fsConfig.AccountKey.IsPlain() {
  1750. payload := replacePlaceholders(fsConfig.AccountKey.GetPayload(), replacements)
  1751. fsConfig.AccountKey = kms.NewPlainSecret(payload)
  1752. }
  1753. return fsConfig
  1754. }
  1755. func getSFTPFsFromTemplate(fsConfig vfs.SFTPFsConfig, replacements map[string]string) vfs.SFTPFsConfig {
  1756. fsConfig.Prefix = replacePlaceholders(fsConfig.Prefix, replacements)
  1757. fsConfig.Username = replacePlaceholders(fsConfig.Username, replacements)
  1758. if fsConfig.Password != nil && fsConfig.Password.IsPlain() {
  1759. payload := replacePlaceholders(fsConfig.Password.GetPayload(), replacements)
  1760. fsConfig.Password = kms.NewPlainSecret(payload)
  1761. }
  1762. return fsConfig
  1763. }
  1764. func getHTTPFsFromTemplate(fsConfig vfs.HTTPFsConfig, replacements map[string]string) vfs.HTTPFsConfig {
  1765. fsConfig.Username = replacePlaceholders(fsConfig.Username, replacements)
  1766. return fsConfig
  1767. }
  1768. func getUserFromTemplate(user dataprovider.User, template userTemplateFields) dataprovider.User {
  1769. user.Username = template.Username
  1770. user.Password = template.Password
  1771. user.PublicKeys = template.PublicKeys
  1772. replacements := make(map[string]string)
  1773. replacements["%username%"] = user.Username
  1774. if user.Password != "" && !user.IsPasswordHashed() {
  1775. user.Password = replacePlaceholders(user.Password, replacements)
  1776. replacements["%password%"] = user.Password
  1777. }
  1778. user.HomeDir = replacePlaceholders(user.HomeDir, replacements)
  1779. var vfolders []vfs.VirtualFolder
  1780. for _, vfolder := range user.VirtualFolders {
  1781. vfolder.Name = replacePlaceholders(vfolder.Name, replacements)
  1782. vfolder.VirtualPath = replacePlaceholders(vfolder.VirtualPath, replacements)
  1783. vfolders = append(vfolders, vfolder)
  1784. }
  1785. user.VirtualFolders = vfolders
  1786. user.Description = replacePlaceholders(user.Description, replacements)
  1787. user.AdditionalInfo = replacePlaceholders(user.AdditionalInfo, replacements)
  1788. user.Filters.StartDirectory = replacePlaceholders(user.Filters.StartDirectory, replacements)
  1789. switch user.FsConfig.Provider {
  1790. case sdk.CryptedFilesystemProvider:
  1791. user.FsConfig.CryptConfig = getCryptFsFromTemplate(user.FsConfig.CryptConfig, replacements)
  1792. case sdk.S3FilesystemProvider:
  1793. user.FsConfig.S3Config = getS3FsFromTemplate(user.FsConfig.S3Config, replacements)
  1794. case sdk.GCSFilesystemProvider:
  1795. user.FsConfig.GCSConfig = getGCSFsFromTemplate(user.FsConfig.GCSConfig, replacements)
  1796. case sdk.AzureBlobFilesystemProvider:
  1797. user.FsConfig.AzBlobConfig = getAzBlobFsFromTemplate(user.FsConfig.AzBlobConfig, replacements)
  1798. case sdk.SFTPFilesystemProvider:
  1799. user.FsConfig.SFTPConfig = getSFTPFsFromTemplate(user.FsConfig.SFTPConfig, replacements)
  1800. case sdk.HTTPFilesystemProvider:
  1801. user.FsConfig.HTTPConfig = getHTTPFsFromTemplate(user.FsConfig.HTTPConfig, replacements)
  1802. }
  1803. return user
  1804. }
  1805. func getTransferLimits(r *http.Request) (int64, int64, int64, error) {
  1806. dataTransferUL, err := strconv.ParseInt(r.Form.Get("upload_data_transfer"), 10, 64)
  1807. if err != nil {
  1808. return 0, 0, 0, fmt.Errorf("invalid upload data transfer: %w", err)
  1809. }
  1810. dataTransferDL, err := strconv.ParseInt(r.Form.Get("download_data_transfer"), 10, 64)
  1811. if err != nil {
  1812. return 0, 0, 0, fmt.Errorf("invalid download data transfer: %w", err)
  1813. }
  1814. dataTransferTotal, err := strconv.ParseInt(r.Form.Get("total_data_transfer"), 10, 64)
  1815. if err != nil {
  1816. return 0, 0, 0, fmt.Errorf("invalid total data transfer: %w", err)
  1817. }
  1818. return dataTransferUL, dataTransferDL, dataTransferTotal, nil
  1819. }
  1820. func getQuotaLimits(r *http.Request) (int64, int, error) {
  1821. quotaSize, err := util.ParseBytes(r.Form.Get("quota_size"))
  1822. if err != nil {
  1823. return 0, 0, util.NewI18nError(fmt.Errorf("invalid quota size: %w", err), util.I18nErrorInvalidQuotaSize)
  1824. }
  1825. quotaFiles, err := strconv.Atoi(r.Form.Get("quota_files"))
  1826. if err != nil {
  1827. return 0, 0, fmt.Errorf("invalid quota files: %w", err)
  1828. }
  1829. return quotaSize, quotaFiles, nil
  1830. }
  1831. func updateRepeaterFormFields(r *http.Request) {
  1832. for k := range r.Form {
  1833. if hasPrefixAndSuffix(k, "public_keys[", "][public_key]") {
  1834. key := r.Form.Get(k)
  1835. if strings.TrimSpace(key) != "" {
  1836. r.Form.Add("public_keys", key)
  1837. }
  1838. continue
  1839. }
  1840. if hasPrefixAndSuffix(k, "tls_certs[", "][tls_cert]") {
  1841. cert := strings.TrimSpace(r.Form.Get(k))
  1842. if cert != "" {
  1843. r.Form.Add("tls_certs", cert)
  1844. }
  1845. continue
  1846. }
  1847. if hasPrefixAndSuffix(k, "virtual_folders[", "][vfolder_path]") {
  1848. base, _ := strings.CutSuffix(k, "[vfolder_path]")
  1849. r.Form.Add("vfolder_path", strings.TrimSpace(r.Form.Get(k)))
  1850. r.Form.Add("vfolder_name", strings.TrimSpace(r.Form.Get(base+"[vfolder_name]")))
  1851. r.Form.Add("vfolder_quota_files", strings.TrimSpace(r.Form.Get(base+"[vfolder_quota_files]")))
  1852. r.Form.Add("vfolder_quota_size", strings.TrimSpace(r.Form.Get(base+"[vfolder_quota_size]")))
  1853. continue
  1854. }
  1855. if hasPrefixAndSuffix(k, "directory_permissions[", "][sub_perm_path]") {
  1856. base, _ := strings.CutSuffix(k, "[sub_perm_path]")
  1857. r.Form.Add("sub_perm_path", strings.TrimSpace(r.Form.Get(k)))
  1858. r.Form["sub_perm_permissions"+strconv.Itoa(len(r.Form["sub_perm_path"])-1)] = r.Form[base+"[sub_perm_permissions][]"]
  1859. continue
  1860. }
  1861. if hasPrefixAndSuffix(k, "directory_patterns[", "][pattern_path]") {
  1862. base, _ := strings.CutSuffix(k, "[pattern_path]")
  1863. r.Form.Add("pattern_path", strings.TrimSpace(r.Form.Get(k)))
  1864. r.Form.Add("patterns", strings.TrimSpace(r.Form.Get(base+"[patterns]")))
  1865. r.Form.Add("pattern_type", strings.TrimSpace(r.Form.Get(base+"[pattern_type]")))
  1866. r.Form.Add("pattern_policy", strings.TrimSpace(r.Form.Get(base+"[pattern_policy]")))
  1867. continue
  1868. }
  1869. if hasPrefixAndSuffix(k, "access_time_restrictions[", "][access_time_day_of_week]") {
  1870. base, _ := strings.CutSuffix(k, "[access_time_day_of_week]")
  1871. r.Form.Add("access_time_day_of_week", strings.TrimSpace(r.Form.Get(k)))
  1872. r.Form.Add("access_time_start", strings.TrimSpace(r.Form.Get(base+"[access_time_start]")))
  1873. r.Form.Add("access_time_end", strings.TrimSpace(r.Form.Get(base+"[access_time_end]")))
  1874. continue
  1875. }
  1876. if hasPrefixAndSuffix(k, "src_bandwidth_limits[", "][bandwidth_limit_sources]") {
  1877. base, _ := strings.CutSuffix(k, "[bandwidth_limit_sources]")
  1878. r.Form.Add("bandwidth_limit_sources", r.Form.Get(k))
  1879. r.Form.Add("upload_bandwidth_source", strings.TrimSpace(r.Form.Get(base+"[upload_bandwidth_source]")))
  1880. r.Form.Add("download_bandwidth_source", strings.TrimSpace(r.Form.Get(base+"[download_bandwidth_source]")))
  1881. continue
  1882. }
  1883. if hasPrefixAndSuffix(k, "template_users[", "][tpl_username]") {
  1884. base, _ := strings.CutSuffix(k, "[tpl_username]")
  1885. r.Form.Add("tpl_username", strings.TrimSpace(r.Form.Get(k)))
  1886. r.Form.Add("tpl_password", strings.TrimSpace(r.Form.Get(base+"[tpl_password]")))
  1887. r.Form.Add("tpl_public_keys", strings.TrimSpace(r.Form.Get(base+"[tpl_public_keys]")))
  1888. continue
  1889. }
  1890. }
  1891. }
  1892. func getUserFromPostFields(r *http.Request) (dataprovider.User, error) {
  1893. user := dataprovider.User{}
  1894. err := r.ParseMultipartForm(maxRequestSize)
  1895. if err != nil {
  1896. return user, util.NewI18nError(err, util.I18nErrorInvalidForm)
  1897. }
  1898. defer r.MultipartForm.RemoveAll() //nolint:errcheck
  1899. updateRepeaterFormFields(r)
  1900. uid, err := strconv.Atoi(r.Form.Get("uid"))
  1901. if err != nil {
  1902. return user, fmt.Errorf("invalid uid: %w", err)
  1903. }
  1904. gid, err := strconv.Atoi(r.Form.Get("gid"))
  1905. if err != nil {
  1906. return user, fmt.Errorf("invalid uid: %w", err)
  1907. }
  1908. maxSessions, err := strconv.Atoi(r.Form.Get("max_sessions"))
  1909. if err != nil {
  1910. return user, fmt.Errorf("invalid max sessions: %w", err)
  1911. }
  1912. quotaSize, quotaFiles, err := getQuotaLimits(r)
  1913. if err != nil {
  1914. return user, err
  1915. }
  1916. bandwidthUL, err := strconv.ParseInt(r.Form.Get("upload_bandwidth"), 10, 64)
  1917. if err != nil {
  1918. return user, fmt.Errorf("invalid upload bandwidth: %w", err)
  1919. }
  1920. bandwidthDL, err := strconv.ParseInt(r.Form.Get("download_bandwidth"), 10, 64)
  1921. if err != nil {
  1922. return user, fmt.Errorf("invalid download bandwidth: %w", err)
  1923. }
  1924. dataTransferUL, dataTransferDL, dataTransferTotal, err := getTransferLimits(r)
  1925. if err != nil {
  1926. return user, err
  1927. }
  1928. status, err := strconv.Atoi(r.Form.Get("status"))
  1929. if err != nil {
  1930. return user, fmt.Errorf("invalid status: %w", err)
  1931. }
  1932. expirationDateMillis := int64(0)
  1933. expirationDateString := r.Form.Get("expiration_date")
  1934. if strings.TrimSpace(expirationDateString) != "" {
  1935. expirationDate, err := time.Parse(webDateTimeFormat, expirationDateString)
  1936. if err != nil {
  1937. return user, err
  1938. }
  1939. expirationDateMillis = util.GetTimeAsMsSinceEpoch(expirationDate)
  1940. }
  1941. fsConfig, err := getFsConfigFromPostFields(r)
  1942. if err != nil {
  1943. return user, err
  1944. }
  1945. filters, err := getFiltersFromUserPostFields(r)
  1946. if err != nil {
  1947. return user, err
  1948. }
  1949. filters.TLSCerts = r.Form["tls_certs"]
  1950. user = dataprovider.User{
  1951. BaseUser: sdk.BaseUser{
  1952. Username: strings.TrimSpace(r.Form.Get("username")),
  1953. Email: strings.TrimSpace(r.Form.Get("email")),
  1954. Password: strings.TrimSpace(r.Form.Get("password")),
  1955. PublicKeys: r.Form["public_keys"],
  1956. HomeDir: strings.TrimSpace(r.Form.Get("home_dir")),
  1957. UID: uid,
  1958. GID: gid,
  1959. Permissions: getUserPermissionsFromPostFields(r),
  1960. MaxSessions: maxSessions,
  1961. QuotaSize: quotaSize,
  1962. QuotaFiles: quotaFiles,
  1963. UploadBandwidth: bandwidthUL,
  1964. DownloadBandwidth: bandwidthDL,
  1965. UploadDataTransfer: dataTransferUL,
  1966. DownloadDataTransfer: dataTransferDL,
  1967. TotalDataTransfer: dataTransferTotal,
  1968. Status: status,
  1969. ExpirationDate: expirationDateMillis,
  1970. AdditionalInfo: r.Form.Get("additional_info"),
  1971. Description: r.Form.Get("description"),
  1972. Role: strings.TrimSpace(r.Form.Get("role")),
  1973. },
  1974. Filters: dataprovider.UserFilters{
  1975. BaseUserFilters: filters,
  1976. RequirePasswordChange: r.Form.Get("require_password_change") != "",
  1977. },
  1978. VirtualFolders: getVirtualFoldersFromPostFields(r),
  1979. FsConfig: fsConfig,
  1980. Groups: getGroupsFromUserPostFields(r),
  1981. }
  1982. return user, nil
  1983. }
  1984. func getGroupFromPostFields(r *http.Request) (dataprovider.Group, error) {
  1985. group := dataprovider.Group{}
  1986. err := r.ParseMultipartForm(maxRequestSize)
  1987. if err != nil {
  1988. return group, util.NewI18nError(err, util.I18nErrorInvalidForm)
  1989. }
  1990. defer r.MultipartForm.RemoveAll() //nolint:errcheck
  1991. updateRepeaterFormFields(r)
  1992. maxSessions, err := strconv.Atoi(r.Form.Get("max_sessions"))
  1993. if err != nil {
  1994. return group, fmt.Errorf("invalid max sessions: %w", err)
  1995. }
  1996. quotaSize, quotaFiles, err := getQuotaLimits(r)
  1997. if err != nil {
  1998. return group, err
  1999. }
  2000. bandwidthUL, err := strconv.ParseInt(r.Form.Get("upload_bandwidth"), 10, 64)
  2001. if err != nil {
  2002. return group, fmt.Errorf("invalid upload bandwidth: %w", err)
  2003. }
  2004. bandwidthDL, err := strconv.ParseInt(r.Form.Get("download_bandwidth"), 10, 64)
  2005. if err != nil {
  2006. return group, fmt.Errorf("invalid download bandwidth: %w", err)
  2007. }
  2008. dataTransferUL, dataTransferDL, dataTransferTotal, err := getTransferLimits(r)
  2009. if err != nil {
  2010. return group, err
  2011. }
  2012. expiresIn, err := strconv.Atoi(r.Form.Get("expires_in"))
  2013. if err != nil {
  2014. return group, fmt.Errorf("invalid expires in: %w", err)
  2015. }
  2016. fsConfig, err := getFsConfigFromPostFields(r)
  2017. if err != nil {
  2018. return group, err
  2019. }
  2020. filters, err := getFiltersFromUserPostFields(r)
  2021. if err != nil {
  2022. return group, err
  2023. }
  2024. group = dataprovider.Group{
  2025. BaseGroup: sdk.BaseGroup{
  2026. Name: strings.TrimSpace(r.Form.Get("name")),
  2027. Description: r.Form.Get("description"),
  2028. },
  2029. UserSettings: dataprovider.GroupUserSettings{
  2030. BaseGroupUserSettings: sdk.BaseGroupUserSettings{
  2031. HomeDir: strings.TrimSpace(r.Form.Get("home_dir")),
  2032. MaxSessions: maxSessions,
  2033. QuotaSize: quotaSize,
  2034. QuotaFiles: quotaFiles,
  2035. Permissions: getSubDirPermissionsFromPostFields(r),
  2036. UploadBandwidth: bandwidthUL,
  2037. DownloadBandwidth: bandwidthDL,
  2038. UploadDataTransfer: dataTransferUL,
  2039. DownloadDataTransfer: dataTransferDL,
  2040. TotalDataTransfer: dataTransferTotal,
  2041. ExpiresIn: expiresIn,
  2042. Filters: filters,
  2043. },
  2044. FsConfig: fsConfig,
  2045. },
  2046. VirtualFolders: getVirtualFoldersFromPostFields(r),
  2047. }
  2048. return group, nil
  2049. }
  2050. func getKeyValsFromPostFields(r *http.Request, key, val string) []dataprovider.KeyValue {
  2051. var res []dataprovider.KeyValue
  2052. keys := r.Form[key]
  2053. values := r.Form[val]
  2054. for idx, k := range keys {
  2055. v := values[idx]
  2056. if k != "" && v != "" {
  2057. res = append(res, dataprovider.KeyValue{
  2058. Key: k,
  2059. Value: v,
  2060. })
  2061. }
  2062. }
  2063. return res
  2064. }
  2065. func getFoldersRetentionFromPostFields(r *http.Request) ([]dataprovider.FolderRetention, error) {
  2066. var res []dataprovider.FolderRetention
  2067. paths := r.Form["folder_retention_path"]
  2068. values := r.Form["folder_retention_val"]
  2069. for idx, p := range paths {
  2070. if p != "" {
  2071. retention, err := strconv.Atoi(values[idx])
  2072. if err != nil {
  2073. return nil, fmt.Errorf("invalid retention for path %q: %w", p, err)
  2074. }
  2075. opts := r.Form["folder_retention_options"+strconv.Itoa(idx)]
  2076. res = append(res, dataprovider.FolderRetention{
  2077. Path: p,
  2078. Retention: retention,
  2079. DeleteEmptyDirs: util.Contains(opts, "1"),
  2080. })
  2081. }
  2082. }
  2083. return res, nil
  2084. }
  2085. func getHTTPPartsFromPostFields(r *http.Request) []dataprovider.HTTPPart {
  2086. var result []dataprovider.HTTPPart
  2087. names := r.Form["http_part_name"]
  2088. files := r.Form["http_part_file"]
  2089. headers := r.Form["http_part_headers"]
  2090. bodies := r.Form["http_part_body"]
  2091. orders := r.Form["http_part_order"]
  2092. for idx, partName := range names {
  2093. if partName != "" {
  2094. order, err := strconv.Atoi(orders[idx])
  2095. if err == nil {
  2096. filePath := files[idx]
  2097. body := bodies[idx]
  2098. concatHeaders := getSliceFromDelimitedValues(headers[idx], "\n")
  2099. var headers []dataprovider.KeyValue
  2100. for _, h := range concatHeaders {
  2101. values := strings.SplitN(h, ":", 2)
  2102. if len(values) > 1 {
  2103. headers = append(headers, dataprovider.KeyValue{
  2104. Key: strings.TrimSpace(values[0]),
  2105. Value: strings.TrimSpace(values[1]),
  2106. })
  2107. }
  2108. }
  2109. result = append(result, dataprovider.HTTPPart{
  2110. Name: partName,
  2111. Filepath: filePath,
  2112. Headers: headers,
  2113. Body: body,
  2114. Order: order,
  2115. })
  2116. }
  2117. }
  2118. }
  2119. sort.Slice(result, func(i, j int) bool {
  2120. return result[i].Order < result[j].Order
  2121. })
  2122. return result
  2123. }
  2124. func updateRepeaterFormActionFields(r *http.Request) {
  2125. for k := range r.Form {
  2126. if hasPrefixAndSuffix(k, "http_headers[", "][http_header_key]") {
  2127. base, _ := strings.CutSuffix(k, "[http_header_key]")
  2128. r.Form.Add("http_header_key", strings.TrimSpace(r.Form.Get(k)))
  2129. r.Form.Add("http_header_value", strings.TrimSpace(r.Form.Get(base+"[http_header_value]")))
  2130. continue
  2131. }
  2132. if hasPrefixAndSuffix(k, "query_parameters[", "][http_query_key]") {
  2133. base, _ := strings.CutSuffix(k, "[http_query_key]")
  2134. r.Form.Add("http_query_key", strings.TrimSpace(r.Form.Get(k)))
  2135. r.Form.Add("http_query_value", strings.TrimSpace(r.Form.Get(base+"[http_query_value]")))
  2136. continue
  2137. }
  2138. if hasPrefixAndSuffix(k, "multipart_body[", "][http_part_name]") {
  2139. base, _ := strings.CutSuffix(k, "[http_part_name]")
  2140. order, _ := strings.CutPrefix(k, "multipart_body[")
  2141. order, _ = strings.CutSuffix(order, "][http_part_name]")
  2142. r.Form.Add("http_part_name", strings.TrimSpace(r.Form.Get(k)))
  2143. r.Form.Add("http_part_file", strings.TrimSpace(r.Form.Get(base+"[http_part_file]")))
  2144. r.Form.Add("http_part_headers", strings.TrimSpace(r.Form.Get(base+"[http_part_headers]")))
  2145. r.Form.Add("http_part_body", strings.TrimSpace(r.Form.Get(base+"[http_part_body]")))
  2146. r.Form.Add("http_part_order", order)
  2147. continue
  2148. }
  2149. if hasPrefixAndSuffix(k, "env_vars[", "][cmd_env_key]") {
  2150. base, _ := strings.CutSuffix(k, "[cmd_env_key]")
  2151. r.Form.Add("cmd_env_key", strings.TrimSpace(r.Form.Get(k)))
  2152. r.Form.Add("cmd_env_value", strings.TrimSpace(r.Form.Get(base+"[cmd_env_value]")))
  2153. continue
  2154. }
  2155. if hasPrefixAndSuffix(k, "data_retention[", "][folder_retention_path]") {
  2156. base, _ := strings.CutSuffix(k, "[folder_retention_path]")
  2157. r.Form.Add("folder_retention_path", strings.TrimSpace(r.Form.Get(k)))
  2158. r.Form.Add("folder_retention_val", strings.TrimSpace(r.Form.Get(base+"[folder_retention_val]")))
  2159. r.Form["folder_retention_options"+strconv.Itoa(len(r.Form["folder_retention_path"])-1)] =
  2160. r.Form[base+"[folder_retention_options][]"]
  2161. continue
  2162. }
  2163. if hasPrefixAndSuffix(k, "fs_rename[", "][fs_rename_source]") {
  2164. base, _ := strings.CutSuffix(k, "[fs_rename_source]")
  2165. r.Form.Add("fs_rename_source", strings.TrimSpace(r.Form.Get(k)))
  2166. r.Form.Add("fs_rename_target", strings.TrimSpace(r.Form.Get(base+"[fs_rename_target]")))
  2167. continue
  2168. }
  2169. if hasPrefixAndSuffix(k, "fs_copy[", "][fs_copy_source]") {
  2170. base, _ := strings.CutSuffix(k, "[fs_copy_source]")
  2171. r.Form.Add("fs_copy_source", strings.TrimSpace(r.Form.Get(k)))
  2172. r.Form.Add("fs_copy_target", strings.TrimSpace(r.Form.Get(base+"[fs_copy_target]")))
  2173. continue
  2174. }
  2175. }
  2176. }
  2177. func getEventActionOptionsFromPostFields(r *http.Request) (dataprovider.BaseEventActionOptions, error) {
  2178. updateRepeaterFormActionFields(r)
  2179. httpTimeout, err := strconv.Atoi(r.Form.Get("http_timeout"))
  2180. if err != nil {
  2181. return dataprovider.BaseEventActionOptions{}, fmt.Errorf("invalid http timeout: %w", err)
  2182. }
  2183. cmdTimeout, err := strconv.Atoi(r.Form.Get("cmd_timeout"))
  2184. if err != nil {
  2185. return dataprovider.BaseEventActionOptions{}, fmt.Errorf("invalid command timeout: %w", err)
  2186. }
  2187. foldersRetention, err := getFoldersRetentionFromPostFields(r)
  2188. if err != nil {
  2189. return dataprovider.BaseEventActionOptions{}, err
  2190. }
  2191. fsActionType, err := strconv.Atoi(r.Form.Get("fs_action_type"))
  2192. if err != nil {
  2193. return dataprovider.BaseEventActionOptions{}, fmt.Errorf("invalid fs action type: %w", err)
  2194. }
  2195. pwdExpirationThreshold, err := strconv.Atoi(r.Form.Get("pwd_expiration_threshold"))
  2196. if err != nil {
  2197. return dataprovider.BaseEventActionOptions{}, fmt.Errorf("invalid password expiration threshold: %w", err)
  2198. }
  2199. var disableThreshold, deleteThreshold int
  2200. if val, err := strconv.Atoi(r.Form.Get("inactivity_disable_threshold")); err == nil {
  2201. disableThreshold = val
  2202. }
  2203. if val, err := strconv.Atoi(r.Form.Get("inactivity_delete_threshold")); err == nil {
  2204. deleteThreshold = val
  2205. }
  2206. var emailAttachments []string
  2207. if r.Form.Get("email_attachments") != "" {
  2208. emailAttachments = getSliceFromDelimitedValues(r.Form.Get("email_attachments"), ",")
  2209. }
  2210. var cmdArgs []string
  2211. if r.Form.Get("cmd_arguments") != "" {
  2212. cmdArgs = getSliceFromDelimitedValues(r.Form.Get("cmd_arguments"), ",")
  2213. }
  2214. idpMode := 0
  2215. if r.Form.Get("idp_mode") == "1" {
  2216. idpMode = 1
  2217. }
  2218. emailContentType := 0
  2219. if r.Form.Get("email_content_type") == "1" {
  2220. emailContentType = 1
  2221. }
  2222. options := dataprovider.BaseEventActionOptions{
  2223. HTTPConfig: dataprovider.EventActionHTTPConfig{
  2224. Endpoint: strings.TrimSpace(r.Form.Get("http_endpoint")),
  2225. Username: strings.TrimSpace(r.Form.Get("http_username")),
  2226. Password: getSecretFromFormField(r, "http_password"),
  2227. Headers: getKeyValsFromPostFields(r, "http_header_key", "http_header_value"),
  2228. Timeout: httpTimeout,
  2229. SkipTLSVerify: r.Form.Get("http_skip_tls_verify") != "",
  2230. Method: r.Form.Get("http_method"),
  2231. QueryParameters: getKeyValsFromPostFields(r, "http_query_key", "http_query_value"),
  2232. Body: r.Form.Get("http_body"),
  2233. Parts: getHTTPPartsFromPostFields(r),
  2234. },
  2235. CmdConfig: dataprovider.EventActionCommandConfig{
  2236. Cmd: strings.TrimSpace(r.Form.Get("cmd_path")),
  2237. Args: cmdArgs,
  2238. Timeout: cmdTimeout,
  2239. EnvVars: getKeyValsFromPostFields(r, "cmd_env_key", "cmd_env_value"),
  2240. },
  2241. EmailConfig: dataprovider.EventActionEmailConfig{
  2242. Recipients: getSliceFromDelimitedValues(r.Form.Get("email_recipients"), ","),
  2243. Bcc: getSliceFromDelimitedValues(r.Form.Get("email_bcc"), ","),
  2244. Subject: r.Form.Get("email_subject"),
  2245. ContentType: emailContentType,
  2246. Body: r.Form.Get("email_body"),
  2247. Attachments: emailAttachments,
  2248. },
  2249. RetentionConfig: dataprovider.EventActionDataRetentionConfig{
  2250. Folders: foldersRetention,
  2251. },
  2252. FsConfig: dataprovider.EventActionFilesystemConfig{
  2253. Type: fsActionType,
  2254. Renames: getKeyValsFromPostFields(r, "fs_rename_source", "fs_rename_target"),
  2255. Deletes: getSliceFromDelimitedValues(r.Form.Get("fs_delete_paths"), ","),
  2256. MkDirs: getSliceFromDelimitedValues(r.Form.Get("fs_mkdir_paths"), ","),
  2257. Exist: getSliceFromDelimitedValues(r.Form.Get("fs_exist_paths"), ","),
  2258. Copy: getKeyValsFromPostFields(r, "fs_copy_source", "fs_copy_target"),
  2259. Compress: dataprovider.EventActionFsCompress{
  2260. Name: strings.TrimSpace(r.Form.Get("fs_compress_name")),
  2261. Paths: getSliceFromDelimitedValues(r.Form.Get("fs_compress_paths"), ","),
  2262. },
  2263. },
  2264. PwdExpirationConfig: dataprovider.EventActionPasswordExpiration{
  2265. Threshold: pwdExpirationThreshold,
  2266. },
  2267. UserInactivityConfig: dataprovider.EventActionUserInactivity{
  2268. DisableThreshold: disableThreshold,
  2269. DeleteThreshold: deleteThreshold,
  2270. },
  2271. IDPConfig: dataprovider.EventActionIDPAccountCheck{
  2272. Mode: idpMode,
  2273. TemplateUser: strings.TrimSpace(r.Form.Get("idp_user")),
  2274. TemplateAdmin: strings.TrimSpace(r.Form.Get("idp_admin")),
  2275. },
  2276. }
  2277. return options, nil
  2278. }
  2279. func getEventActionFromPostFields(r *http.Request) (dataprovider.BaseEventAction, error) {
  2280. err := r.ParseForm()
  2281. if err != nil {
  2282. return dataprovider.BaseEventAction{}, util.NewI18nError(err, util.I18nErrorInvalidForm)
  2283. }
  2284. actionType, err := strconv.Atoi(r.Form.Get("type"))
  2285. if err != nil {
  2286. return dataprovider.BaseEventAction{}, fmt.Errorf("invalid action type: %w", err)
  2287. }
  2288. options, err := getEventActionOptionsFromPostFields(r)
  2289. if err != nil {
  2290. return dataprovider.BaseEventAction{}, err
  2291. }
  2292. action := dataprovider.BaseEventAction{
  2293. Name: strings.TrimSpace(r.Form.Get("name")),
  2294. Description: r.Form.Get("description"),
  2295. Type: actionType,
  2296. Options: options,
  2297. }
  2298. return action, nil
  2299. }
  2300. func getIDPLoginEventFromPostField(r *http.Request) int {
  2301. switch r.Form.Get("idp_login_event") {
  2302. case "1":
  2303. return 1
  2304. case "2":
  2305. return 2
  2306. default:
  2307. return 0
  2308. }
  2309. }
  2310. func getEventRuleConditionsFromPostFields(r *http.Request) (dataprovider.EventConditions, error) {
  2311. var schedules []dataprovider.Schedule
  2312. var names, groupNames, roleNames, fsPaths []dataprovider.ConditionPattern
  2313. scheduleHours := r.Form["schedule_hour"]
  2314. scheduleDayOfWeeks := r.Form["schedule_day_of_week"]
  2315. scheduleDayOfMonths := r.Form["schedule_day_of_month"]
  2316. scheduleMonths := r.Form["schedule_month"]
  2317. for idx, hour := range scheduleHours {
  2318. if hour != "" {
  2319. schedules = append(schedules, dataprovider.Schedule{
  2320. Hours: hour,
  2321. DayOfWeek: scheduleDayOfWeeks[idx],
  2322. DayOfMonth: scheduleDayOfMonths[idx],
  2323. Month: scheduleMonths[idx],
  2324. })
  2325. }
  2326. }
  2327. for idx, name := range r.Form["name_pattern"] {
  2328. if name != "" {
  2329. names = append(names, dataprovider.ConditionPattern{
  2330. Pattern: name,
  2331. InverseMatch: r.Form["type_name_pattern"][idx] == inversePatternType,
  2332. })
  2333. }
  2334. }
  2335. for idx, name := range r.Form["group_name_pattern"] {
  2336. if name != "" {
  2337. groupNames = append(groupNames, dataprovider.ConditionPattern{
  2338. Pattern: name,
  2339. InverseMatch: r.Form["type_group_name_pattern"][idx] == inversePatternType,
  2340. })
  2341. }
  2342. }
  2343. for idx, name := range r.Form["role_name_pattern"] {
  2344. if name != "" {
  2345. roleNames = append(roleNames, dataprovider.ConditionPattern{
  2346. Pattern: name,
  2347. InverseMatch: r.Form["type_role_name_pattern"][idx] == inversePatternType,
  2348. })
  2349. }
  2350. }
  2351. for idx, name := range r.Form["fs_path_pattern"] {
  2352. if name != "" {
  2353. fsPaths = append(fsPaths, dataprovider.ConditionPattern{
  2354. Pattern: name,
  2355. InverseMatch: r.Form["type_fs_path_pattern"][idx] == inversePatternType,
  2356. })
  2357. }
  2358. }
  2359. minFileSize, err := util.ParseBytes(r.Form.Get("fs_min_size"))
  2360. if err != nil {
  2361. return dataprovider.EventConditions{}, util.NewI18nError(fmt.Errorf("invalid min file size: %w", err), util.I18nErrorInvalidMinSize)
  2362. }
  2363. maxFileSize, err := util.ParseBytes(r.Form.Get("fs_max_size"))
  2364. if err != nil {
  2365. return dataprovider.EventConditions{}, util.NewI18nError(fmt.Errorf("invalid max file size: %w", err), util.I18nErrorInvalidMaxSize)
  2366. }
  2367. conditions := dataprovider.EventConditions{
  2368. FsEvents: r.Form["fs_events"],
  2369. ProviderEvents: r.Form["provider_events"],
  2370. IDPLoginEvent: getIDPLoginEventFromPostField(r),
  2371. Schedules: schedules,
  2372. Options: dataprovider.ConditionOptions{
  2373. Names: names,
  2374. GroupNames: groupNames,
  2375. RoleNames: roleNames,
  2376. FsPaths: fsPaths,
  2377. Protocols: r.Form["fs_protocols"],
  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. defer oauth2Mgr.removePendingAuth(state)
  3978. pendingAuth, err := oauth2Mgr.getPendingAuth(state)
  3979. if err != nil {
  3980. s.renderMessagePage(w, r, util.I18nOAuth2ErrorTitle, http.StatusInternalServerError,
  3981. util.NewI18nError(err, util.I18nOAuth2ErrorValidateState), "")
  3982. return
  3983. }
  3984. oauth2Config := smtp.OAuth2Config{
  3985. Provider: pendingAuth.Provider,
  3986. ClientID: pendingAuth.ClientID,
  3987. ClientSecret: pendingAuth.ClientSecret.GetPayload(),
  3988. }
  3989. ctx, cancel := context.WithTimeout(context.Background(), 15*time.Second)
  3990. defer cancel()
  3991. cfg := oauth2Config.GetOAuth2()
  3992. cfg.RedirectURL = pendingAuth.RedirectURL
  3993. token, err := cfg.Exchange(ctx, r.URL.Query().Get("code"))
  3994. if err != nil {
  3995. s.renderMessagePage(w, r, util.I18nOAuth2ErrorTitle, http.StatusInternalServerError,
  3996. util.NewI18nError(err, util.I18nOAuth2ErrTokenExchange), "")
  3997. return
  3998. }
  3999. if token.RefreshToken == "" {
  4000. errTxt := "the OAuth2 provider returned an empty token. " +
  4001. "Some providers only return the token when the user first authorizes. " +
  4002. "If you have already registered SFTPGo with this user in the past, revoke access and try again. " +
  4003. "This way you will invalidate the previous token"
  4004. s.renderMessagePage(w, r, util.I18nOAuth2ErrorTitle, http.StatusBadRequest,
  4005. util.NewI18nError(errors.New(errTxt), util.I18nOAuth2ErrNoRefreshToken), "")
  4006. return
  4007. }
  4008. s.renderMessagePageWithString(w, r, util.I18nOAuth2Title, http.StatusOK, nil, util.I18nOAuth2OK,
  4009. fmt.Sprintf("%q", token.RefreshToken))
  4010. }
  4011. func updateSMTPSecrets(newConfigs, currentConfigs *dataprovider.SMTPConfigs) {
  4012. if newConfigs.Password.IsNotPlainAndNotEmpty() {
  4013. newConfigs.Password = currentConfigs.Password
  4014. }
  4015. if newConfigs.OAuth2.ClientSecret.IsNotPlainAndNotEmpty() {
  4016. newConfigs.OAuth2.ClientSecret = currentConfigs.OAuth2.ClientSecret
  4017. }
  4018. if newConfigs.OAuth2.RefreshToken.IsNotPlainAndNotEmpty() {
  4019. newConfigs.OAuth2.RefreshToken = currentConfigs.OAuth2.RefreshToken
  4020. }
  4021. }