webadmin.go 149 KB

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