webadmin.go 149 KB

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