webadmin.go 151 KB

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