1
0

webadmin.go 82 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538
  1. // Copyright (C) 2019-2022 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. "errors"
  17. "fmt"
  18. "html/template"
  19. "io"
  20. "net/http"
  21. "net/url"
  22. "os"
  23. "path/filepath"
  24. "strconv"
  25. "strings"
  26. "time"
  27. "github.com/go-chi/render"
  28. "github.com/sftpgo/sdk"
  29. sdkkms "github.com/sftpgo/sdk/kms"
  30. "github.com/drakkan/sftpgo/v2/common"
  31. "github.com/drakkan/sftpgo/v2/dataprovider"
  32. "github.com/drakkan/sftpgo/v2/kms"
  33. "github.com/drakkan/sftpgo/v2/mfa"
  34. "github.com/drakkan/sftpgo/v2/smtp"
  35. "github.com/drakkan/sftpgo/v2/util"
  36. "github.com/drakkan/sftpgo/v2/version"
  37. "github.com/drakkan/sftpgo/v2/vfs"
  38. )
  39. type userPageMode int
  40. const (
  41. userPageModeAdd userPageMode = iota + 1
  42. userPageModeUpdate
  43. userPageModeTemplate
  44. )
  45. type folderPageMode int
  46. const (
  47. folderPageModeAdd folderPageMode = iota + 1
  48. folderPageModeUpdate
  49. folderPageModeTemplate
  50. )
  51. type groupPageMode int
  52. const (
  53. groupPageModeAdd groupPageMode = iota + 1
  54. groupPageModeUpdate
  55. )
  56. const (
  57. templateAdminDir = "webadmin"
  58. templateBase = "base.html"
  59. templateBaseLogin = "baselogin.html"
  60. templateFsConfig = "fsconfig.html"
  61. templateSharedComponents = "sharedcomponents.html"
  62. templateUsers = "users.html"
  63. templateUser = "user.html"
  64. templateAdmins = "admins.html"
  65. templateAdmin = "admin.html"
  66. templateConnections = "connections.html"
  67. templateGroups = "groups.html"
  68. templateGroup = "group.html"
  69. templateFolders = "folders.html"
  70. templateFolder = "folder.html"
  71. templateMessage = "message.html"
  72. templateStatus = "status.html"
  73. templateLogin = "login.html"
  74. templateDefender = "defender.html"
  75. templateProfile = "profile.html"
  76. templateChangePwd = "changepassword.html"
  77. templateMaintenance = "maintenance.html"
  78. templateMFA = "mfa.html"
  79. templateSetup = "adminsetup.html"
  80. pageUsersTitle = "Users"
  81. pageAdminsTitle = "Admins"
  82. pageConnectionsTitle = "Connections"
  83. pageStatusTitle = "Status"
  84. pageFoldersTitle = "Folders"
  85. pageGroupsTitle = "Groups"
  86. pageProfileTitle = "My profile"
  87. pageChangePwdTitle = "Change password"
  88. pageMaintenanceTitle = "Maintenance"
  89. pageDefenderTitle = "Defender"
  90. pageForgotPwdTitle = "SFTPGo Admin - Forgot password"
  91. pageResetPwdTitle = "SFTPGo Admin - Reset password"
  92. pageSetupTitle = "Create first admin user"
  93. defaultQueryLimit = 500
  94. )
  95. var (
  96. adminTemplates = make(map[string]*template.Template)
  97. )
  98. type basePage struct {
  99. Title string
  100. CurrentURL string
  101. UsersURL string
  102. UserURL string
  103. UserTemplateURL string
  104. AdminsURL string
  105. AdminURL string
  106. QuotaScanURL string
  107. ConnectionsURL string
  108. GroupsURL string
  109. GroupURL string
  110. FoldersURL string
  111. FolderURL string
  112. FolderTemplateURL string
  113. DefenderURL string
  114. LogoutURL string
  115. ProfileURL string
  116. ChangePwdURL string
  117. MFAURL string
  118. FolderQuotaScanURL string
  119. StatusURL string
  120. MaintenanceURL string
  121. StaticURL string
  122. UsersTitle string
  123. AdminsTitle string
  124. ConnectionsTitle string
  125. FoldersTitle string
  126. GroupsTitle string
  127. StatusTitle string
  128. MaintenanceTitle string
  129. DefenderTitle string
  130. Version string
  131. CSRFToken string
  132. HasDefender bool
  133. HasExternalLogin bool
  134. LoggedAdmin *dataprovider.Admin
  135. Branding UIBranding
  136. }
  137. type usersPage struct {
  138. basePage
  139. Users []dataprovider.User
  140. }
  141. type adminsPage struct {
  142. basePage
  143. Admins []dataprovider.Admin
  144. }
  145. type foldersPage struct {
  146. basePage
  147. Folders []vfs.BaseVirtualFolder
  148. }
  149. type groupsPage struct {
  150. basePage
  151. Groups []dataprovider.Group
  152. }
  153. type connectionsPage struct {
  154. basePage
  155. Connections []common.ConnectionStatus
  156. }
  157. type statusPage struct {
  158. basePage
  159. Status *ServicesStatus
  160. }
  161. type fsWrapper struct {
  162. vfs.Filesystem
  163. IsUserPage bool
  164. IsGroupPage bool
  165. HasUsersBaseDir bool
  166. DirPath string
  167. }
  168. type userPage struct {
  169. basePage
  170. User *dataprovider.User
  171. RootPerms []string
  172. Error string
  173. ValidPerms []string
  174. ValidLoginMethods []string
  175. ValidProtocols []string
  176. TwoFactorProtocols []string
  177. WebClientOptions []string
  178. RootDirPerms []string
  179. RedactedSecret string
  180. Mode userPageMode
  181. VirtualFolders []vfs.BaseVirtualFolder
  182. Groups []dataprovider.Group
  183. CanImpersonate bool
  184. FsWrapper fsWrapper
  185. }
  186. type adminPage struct {
  187. basePage
  188. Admin *dataprovider.Admin
  189. Error string
  190. IsAdd bool
  191. }
  192. type profilePage struct {
  193. basePage
  194. Error string
  195. AllowAPIKeyAuth bool
  196. Email string
  197. Description string
  198. }
  199. type changePasswordPage struct {
  200. basePage
  201. Error string
  202. }
  203. type mfaPage struct {
  204. basePage
  205. TOTPConfigs []string
  206. TOTPConfig dataprovider.AdminTOTPConfig
  207. GenerateTOTPURL string
  208. ValidateTOTPURL string
  209. SaveTOTPURL string
  210. RecCodesURL string
  211. }
  212. type maintenancePage struct {
  213. basePage
  214. BackupPath string
  215. RestorePath string
  216. Error string
  217. }
  218. type defenderHostsPage struct {
  219. basePage
  220. DefenderHostsURL string
  221. }
  222. type setupPage struct {
  223. basePage
  224. Username string
  225. HasInstallationCode bool
  226. InstallationCodeHint string
  227. HideSupportLink bool
  228. Error string
  229. }
  230. type folderPage struct {
  231. basePage
  232. Folder vfs.BaseVirtualFolder
  233. Error string
  234. Mode folderPageMode
  235. FsWrapper fsWrapper
  236. }
  237. type groupPage struct {
  238. basePage
  239. Group *dataprovider.Group
  240. Error string
  241. Mode groupPageMode
  242. ValidPerms []string
  243. ValidLoginMethods []string
  244. ValidProtocols []string
  245. TwoFactorProtocols []string
  246. WebClientOptions []string
  247. VirtualFolders []vfs.BaseVirtualFolder
  248. FsWrapper fsWrapper
  249. }
  250. type messagePage struct {
  251. basePage
  252. Error string
  253. Success string
  254. }
  255. type userTemplateFields struct {
  256. Username string
  257. Password string
  258. PublicKeys []string
  259. }
  260. func loadAdminTemplates(templatesPath string) {
  261. usersPaths := []string{
  262. filepath.Join(templatesPath, templateCommonDir, templateCommonCSS),
  263. filepath.Join(templatesPath, templateAdminDir, templateBase),
  264. filepath.Join(templatesPath, templateAdminDir, templateUsers),
  265. }
  266. userPaths := []string{
  267. filepath.Join(templatesPath, templateCommonDir, templateCommonCSS),
  268. filepath.Join(templatesPath, templateAdminDir, templateBase),
  269. filepath.Join(templatesPath, templateAdminDir, templateSharedComponents),
  270. filepath.Join(templatesPath, templateAdminDir, templateFsConfig),
  271. filepath.Join(templatesPath, templateAdminDir, templateUser),
  272. }
  273. adminsPaths := []string{
  274. filepath.Join(templatesPath, templateCommonDir, templateCommonCSS),
  275. filepath.Join(templatesPath, templateAdminDir, templateBase),
  276. filepath.Join(templatesPath, templateAdminDir, templateAdmins),
  277. }
  278. adminPaths := []string{
  279. filepath.Join(templatesPath, templateCommonDir, templateCommonCSS),
  280. filepath.Join(templatesPath, templateAdminDir, templateBase),
  281. filepath.Join(templatesPath, templateAdminDir, templateAdmin),
  282. }
  283. profilePaths := []string{
  284. filepath.Join(templatesPath, templateCommonDir, templateCommonCSS),
  285. filepath.Join(templatesPath, templateAdminDir, templateBase),
  286. filepath.Join(templatesPath, templateAdminDir, templateProfile),
  287. }
  288. changePwdPaths := []string{
  289. filepath.Join(templatesPath, templateCommonDir, templateCommonCSS),
  290. filepath.Join(templatesPath, templateAdminDir, templateBase),
  291. filepath.Join(templatesPath, templateAdminDir, templateChangePwd),
  292. }
  293. connectionsPaths := []string{
  294. filepath.Join(templatesPath, templateCommonDir, templateCommonCSS),
  295. filepath.Join(templatesPath, templateAdminDir, templateBase),
  296. filepath.Join(templatesPath, templateAdminDir, templateConnections),
  297. }
  298. messagePaths := []string{
  299. filepath.Join(templatesPath, templateCommonDir, templateCommonCSS),
  300. filepath.Join(templatesPath, templateAdminDir, templateBase),
  301. filepath.Join(templatesPath, templateAdminDir, templateMessage),
  302. }
  303. foldersPaths := []string{
  304. filepath.Join(templatesPath, templateCommonDir, templateCommonCSS),
  305. filepath.Join(templatesPath, templateAdminDir, templateBase),
  306. filepath.Join(templatesPath, templateAdminDir, templateFolders),
  307. }
  308. folderPaths := []string{
  309. filepath.Join(templatesPath, templateCommonDir, templateCommonCSS),
  310. filepath.Join(templatesPath, templateAdminDir, templateBase),
  311. filepath.Join(templatesPath, templateAdminDir, templateFsConfig),
  312. filepath.Join(templatesPath, templateAdminDir, templateFolder),
  313. }
  314. groupsPaths := []string{
  315. filepath.Join(templatesPath, templateCommonDir, templateCommonCSS),
  316. filepath.Join(templatesPath, templateAdminDir, templateBase),
  317. filepath.Join(templatesPath, templateAdminDir, templateGroups),
  318. }
  319. groupPaths := []string{
  320. filepath.Join(templatesPath, templateCommonDir, templateCommonCSS),
  321. filepath.Join(templatesPath, templateAdminDir, templateBase),
  322. filepath.Join(templatesPath, templateAdminDir, templateFsConfig),
  323. filepath.Join(templatesPath, templateAdminDir, templateSharedComponents),
  324. filepath.Join(templatesPath, templateAdminDir, templateGroup),
  325. }
  326. statusPaths := []string{
  327. filepath.Join(templatesPath, templateCommonDir, templateCommonCSS),
  328. filepath.Join(templatesPath, templateAdminDir, templateBase),
  329. filepath.Join(templatesPath, templateAdminDir, templateStatus),
  330. }
  331. loginPaths := []string{
  332. filepath.Join(templatesPath, templateCommonDir, templateCommonCSS),
  333. filepath.Join(templatesPath, templateAdminDir, templateBaseLogin),
  334. filepath.Join(templatesPath, templateAdminDir, templateLogin),
  335. }
  336. maintenancePaths := []string{
  337. filepath.Join(templatesPath, templateCommonDir, templateCommonCSS),
  338. filepath.Join(templatesPath, templateAdminDir, templateBase),
  339. filepath.Join(templatesPath, templateAdminDir, templateMaintenance),
  340. }
  341. defenderPaths := []string{
  342. filepath.Join(templatesPath, templateCommonDir, templateCommonCSS),
  343. filepath.Join(templatesPath, templateAdminDir, templateBase),
  344. filepath.Join(templatesPath, templateAdminDir, templateDefender),
  345. }
  346. mfaPaths := []string{
  347. filepath.Join(templatesPath, templateCommonDir, templateCommonCSS),
  348. filepath.Join(templatesPath, templateAdminDir, templateBase),
  349. filepath.Join(templatesPath, templateAdminDir, templateMFA),
  350. }
  351. twoFactorPaths := []string{
  352. filepath.Join(templatesPath, templateCommonDir, templateCommonCSS),
  353. filepath.Join(templatesPath, templateAdminDir, templateBaseLogin),
  354. filepath.Join(templatesPath, templateAdminDir, templateTwoFactor),
  355. }
  356. twoFactorRecoveryPaths := []string{
  357. filepath.Join(templatesPath, templateCommonDir, templateCommonCSS),
  358. filepath.Join(templatesPath, templateAdminDir, templateBaseLogin),
  359. filepath.Join(templatesPath, templateAdminDir, templateTwoFactorRecovery),
  360. }
  361. setupPaths := []string{
  362. filepath.Join(templatesPath, templateCommonDir, templateCommonCSS),
  363. filepath.Join(templatesPath, templateAdminDir, templateBaseLogin),
  364. filepath.Join(templatesPath, templateAdminDir, templateSetup),
  365. }
  366. forgotPwdPaths := []string{
  367. filepath.Join(templatesPath, templateCommonDir, templateCommonCSS),
  368. filepath.Join(templatesPath, templateCommonDir, templateForgotPassword),
  369. }
  370. resetPwdPaths := []string{
  371. filepath.Join(templatesPath, templateCommonDir, templateCommonCSS),
  372. filepath.Join(templatesPath, templateCommonDir, templateResetPassword),
  373. }
  374. fsBaseTpl := template.New("fsBaseTemplate").Funcs(template.FuncMap{
  375. "ListFSProviders": func() []sdk.FilesystemProvider {
  376. return []sdk.FilesystemProvider{sdk.LocalFilesystemProvider, sdk.CryptedFilesystemProvider,
  377. sdk.S3FilesystemProvider, sdk.GCSFilesystemProvider,
  378. sdk.AzureBlobFilesystemProvider, sdk.SFTPFilesystemProvider,
  379. }
  380. },
  381. })
  382. usersTmpl := util.LoadTemplate(nil, usersPaths...)
  383. userTmpl := util.LoadTemplate(fsBaseTpl, userPaths...)
  384. adminsTmpl := util.LoadTemplate(nil, adminsPaths...)
  385. adminTmpl := util.LoadTemplate(nil, adminPaths...)
  386. connectionsTmpl := util.LoadTemplate(nil, connectionsPaths...)
  387. messageTmpl := util.LoadTemplate(nil, messagePaths...)
  388. groupsTmpl := util.LoadTemplate(nil, groupsPaths...)
  389. groupTmpl := util.LoadTemplate(fsBaseTpl, groupPaths...)
  390. foldersTmpl := util.LoadTemplate(nil, foldersPaths...)
  391. folderTmpl := util.LoadTemplate(fsBaseTpl, folderPaths...)
  392. statusTmpl := util.LoadTemplate(nil, statusPaths...)
  393. loginTmpl := util.LoadTemplate(nil, loginPaths...)
  394. profileTmpl := util.LoadTemplate(nil, profilePaths...)
  395. changePwdTmpl := util.LoadTemplate(nil, changePwdPaths...)
  396. maintenanceTmpl := util.LoadTemplate(nil, maintenancePaths...)
  397. defenderTmpl := util.LoadTemplate(nil, defenderPaths...)
  398. mfaTmpl := util.LoadTemplate(nil, mfaPaths...)
  399. twoFactorTmpl := util.LoadTemplate(nil, twoFactorPaths...)
  400. twoFactorRecoveryTmpl := util.LoadTemplate(nil, twoFactorRecoveryPaths...)
  401. setupTmpl := util.LoadTemplate(nil, setupPaths...)
  402. forgotPwdTmpl := util.LoadTemplate(nil, forgotPwdPaths...)
  403. resetPwdTmpl := util.LoadTemplate(nil, resetPwdPaths...)
  404. adminTemplates[templateUsers] = usersTmpl
  405. adminTemplates[templateUser] = userTmpl
  406. adminTemplates[templateAdmins] = adminsTmpl
  407. adminTemplates[templateAdmin] = adminTmpl
  408. adminTemplates[templateConnections] = connectionsTmpl
  409. adminTemplates[templateMessage] = messageTmpl
  410. adminTemplates[templateGroups] = groupsTmpl
  411. adminTemplates[templateGroup] = groupTmpl
  412. adminTemplates[templateFolders] = foldersTmpl
  413. adminTemplates[templateFolder] = folderTmpl
  414. adminTemplates[templateStatus] = statusTmpl
  415. adminTemplates[templateLogin] = loginTmpl
  416. adminTemplates[templateProfile] = profileTmpl
  417. adminTemplates[templateChangePwd] = changePwdTmpl
  418. adminTemplates[templateMaintenance] = maintenanceTmpl
  419. adminTemplates[templateDefender] = defenderTmpl
  420. adminTemplates[templateMFA] = mfaTmpl
  421. adminTemplates[templateTwoFactor] = twoFactorTmpl
  422. adminTemplates[templateTwoFactorRecovery] = twoFactorRecoveryTmpl
  423. adminTemplates[templateSetup] = setupTmpl
  424. adminTemplates[templateForgotPassword] = forgotPwdTmpl
  425. adminTemplates[templateResetPassword] = resetPwdTmpl
  426. }
  427. func (s *httpdServer) getBasePageData(title, currentURL string, r *http.Request) basePage {
  428. var csrfToken string
  429. if currentURL != "" {
  430. csrfToken = createCSRFToken(util.GetIPFromRemoteAddress(r.RemoteAddr))
  431. }
  432. return basePage{
  433. Title: title,
  434. CurrentURL: currentURL,
  435. UsersURL: webUsersPath,
  436. UserURL: webUserPath,
  437. UserTemplateURL: webTemplateUser,
  438. AdminsURL: webAdminsPath,
  439. AdminURL: webAdminPath,
  440. GroupsURL: webGroupsPath,
  441. GroupURL: webGroupPath,
  442. FoldersURL: webFoldersPath,
  443. FolderURL: webFolderPath,
  444. FolderTemplateURL: webTemplateFolder,
  445. DefenderURL: webDefenderPath,
  446. LogoutURL: webLogoutPath,
  447. ProfileURL: webAdminProfilePath,
  448. ChangePwdURL: webChangeAdminPwdPath,
  449. MFAURL: webAdminMFAPath,
  450. QuotaScanURL: webQuotaScanPath,
  451. ConnectionsURL: webConnectionsPath,
  452. StatusURL: webStatusPath,
  453. FolderQuotaScanURL: webScanVFolderPath,
  454. MaintenanceURL: webMaintenancePath,
  455. StaticURL: webStaticFilesPath,
  456. UsersTitle: pageUsersTitle,
  457. AdminsTitle: pageAdminsTitle,
  458. ConnectionsTitle: pageConnectionsTitle,
  459. FoldersTitle: pageFoldersTitle,
  460. GroupsTitle: pageGroupsTitle,
  461. StatusTitle: pageStatusTitle,
  462. MaintenanceTitle: pageMaintenanceTitle,
  463. DefenderTitle: pageDefenderTitle,
  464. Version: version.GetAsString(),
  465. LoggedAdmin: getAdminFromToken(r),
  466. HasDefender: common.Config.DefenderConfig.Enabled,
  467. HasExternalLogin: isLoggedInWithOIDC(r),
  468. CSRFToken: csrfToken,
  469. Branding: s.binding.Branding.WebAdmin,
  470. }
  471. }
  472. func renderAdminTemplate(w http.ResponseWriter, tmplName string, data any) {
  473. err := adminTemplates[tmplName].ExecuteTemplate(w, tmplName, data)
  474. if err != nil {
  475. http.Error(w, err.Error(), http.StatusInternalServerError)
  476. }
  477. }
  478. func (s *httpdServer) renderMessagePage(w http.ResponseWriter, r *http.Request, title, body string, statusCode int,
  479. err error, message string,
  480. ) {
  481. var errorString string
  482. if body != "" {
  483. errorString = body + " "
  484. }
  485. if err != nil {
  486. errorString += err.Error()
  487. }
  488. data := messagePage{
  489. basePage: s.getBasePageData(title, "", r),
  490. Error: errorString,
  491. Success: message,
  492. }
  493. w.WriteHeader(statusCode)
  494. renderAdminTemplate(w, templateMessage, data)
  495. }
  496. func (s *httpdServer) renderInternalServerErrorPage(w http.ResponseWriter, r *http.Request, err error) {
  497. s.renderMessagePage(w, r, page500Title, page500Body, http.StatusInternalServerError, err, "")
  498. }
  499. func (s *httpdServer) renderBadRequestPage(w http.ResponseWriter, r *http.Request, err error) {
  500. s.renderMessagePage(w, r, page400Title, "", http.StatusBadRequest, err, "")
  501. }
  502. func (s *httpdServer) renderForbiddenPage(w http.ResponseWriter, r *http.Request, body string) {
  503. s.renderMessagePage(w, r, page403Title, "", http.StatusForbidden, nil, body)
  504. }
  505. func (s *httpdServer) renderNotFoundPage(w http.ResponseWriter, r *http.Request, err error) {
  506. s.renderMessagePage(w, r, page404Title, page404Body, http.StatusNotFound, err, "")
  507. }
  508. func (s *httpdServer) renderForgotPwdPage(w http.ResponseWriter, error, ip string) {
  509. data := forgotPwdPage{
  510. CurrentURL: webAdminForgotPwdPath,
  511. Error: error,
  512. CSRFToken: createCSRFToken(ip),
  513. StaticURL: webStaticFilesPath,
  514. Title: pageForgotPwdTitle,
  515. Branding: s.binding.Branding.WebAdmin,
  516. }
  517. renderAdminTemplate(w, templateForgotPassword, data)
  518. }
  519. func (s *httpdServer) renderResetPwdPage(w http.ResponseWriter, error, ip string) {
  520. data := resetPwdPage{
  521. CurrentURL: webAdminResetPwdPath,
  522. Error: error,
  523. CSRFToken: createCSRFToken(ip),
  524. StaticURL: webStaticFilesPath,
  525. Title: pageResetPwdTitle,
  526. Branding: s.binding.Branding.WebAdmin,
  527. }
  528. renderAdminTemplate(w, templateResetPassword, data)
  529. }
  530. func (s *httpdServer) renderTwoFactorPage(w http.ResponseWriter, error, ip string) {
  531. data := twoFactorPage{
  532. CurrentURL: webAdminTwoFactorPath,
  533. Version: version.Get().Version,
  534. Error: error,
  535. CSRFToken: createCSRFToken(ip),
  536. StaticURL: webStaticFilesPath,
  537. RecoveryURL: webAdminTwoFactorRecoveryPath,
  538. Branding: s.binding.Branding.WebAdmin,
  539. }
  540. renderAdminTemplate(w, templateTwoFactor, data)
  541. }
  542. func (s *httpdServer) renderTwoFactorRecoveryPage(w http.ResponseWriter, error, ip string) {
  543. data := twoFactorPage{
  544. CurrentURL: webAdminTwoFactorRecoveryPath,
  545. Version: version.Get().Version,
  546. Error: error,
  547. CSRFToken: createCSRFToken(ip),
  548. StaticURL: webStaticFilesPath,
  549. Branding: s.binding.Branding.WebAdmin,
  550. }
  551. renderAdminTemplate(w, templateTwoFactorRecovery, data)
  552. }
  553. func (s *httpdServer) renderMFAPage(w http.ResponseWriter, r *http.Request) {
  554. data := mfaPage{
  555. basePage: s.getBasePageData(pageMFATitle, webAdminMFAPath, r),
  556. TOTPConfigs: mfa.GetAvailableTOTPConfigNames(),
  557. GenerateTOTPURL: webAdminTOTPGeneratePath,
  558. ValidateTOTPURL: webAdminTOTPValidatePath,
  559. SaveTOTPURL: webAdminTOTPSavePath,
  560. RecCodesURL: webAdminRecoveryCodesPath,
  561. }
  562. admin, err := dataprovider.AdminExists(data.LoggedAdmin.Username)
  563. if err != nil {
  564. s.renderInternalServerErrorPage(w, r, err)
  565. return
  566. }
  567. data.TOTPConfig = admin.Filters.TOTPConfig
  568. renderAdminTemplate(w, templateMFA, data)
  569. }
  570. func (s *httpdServer) renderProfilePage(w http.ResponseWriter, r *http.Request, error string) {
  571. data := profilePage{
  572. basePage: s.getBasePageData(pageProfileTitle, webAdminProfilePath, r),
  573. Error: error,
  574. }
  575. admin, err := dataprovider.AdminExists(data.LoggedAdmin.Username)
  576. if err != nil {
  577. s.renderInternalServerErrorPage(w, r, err)
  578. return
  579. }
  580. data.AllowAPIKeyAuth = admin.Filters.AllowAPIKeyAuth
  581. data.Email = admin.Email
  582. data.Description = admin.Description
  583. renderAdminTemplate(w, templateProfile, data)
  584. }
  585. func (s *httpdServer) renderChangePasswordPage(w http.ResponseWriter, r *http.Request, error string) {
  586. data := changePasswordPage{
  587. basePage: s.getBasePageData(pageChangePwdTitle, webChangeAdminPwdPath, r),
  588. Error: error,
  589. }
  590. renderAdminTemplate(w, templateChangePwd, data)
  591. }
  592. func (s *httpdServer) renderMaintenancePage(w http.ResponseWriter, r *http.Request, error string) {
  593. data := maintenancePage{
  594. basePage: s.getBasePageData(pageMaintenanceTitle, webMaintenancePath, r),
  595. BackupPath: webBackupPath,
  596. RestorePath: webRestorePath,
  597. Error: error,
  598. }
  599. renderAdminTemplate(w, templateMaintenance, data)
  600. }
  601. func (s *httpdServer) renderAdminSetupPage(w http.ResponseWriter, r *http.Request, username, error string) {
  602. data := setupPage{
  603. basePage: s.getBasePageData(pageSetupTitle, webAdminSetupPath, r),
  604. Username: username,
  605. HasInstallationCode: installationCode != "",
  606. InstallationCodeHint: installationCodeHint,
  607. HideSupportLink: hideSupportLink,
  608. Error: error,
  609. }
  610. renderAdminTemplate(w, templateSetup, data)
  611. }
  612. func (s *httpdServer) renderAddUpdateAdminPage(w http.ResponseWriter, r *http.Request, admin *dataprovider.Admin,
  613. error string, isAdd bool) {
  614. currentURL := webAdminPath
  615. title := "Add a new admin"
  616. if !isAdd {
  617. currentURL = fmt.Sprintf("%v/%v", webAdminPath, url.PathEscape(admin.Username))
  618. title = "Update admin"
  619. }
  620. data := adminPage{
  621. basePage: s.getBasePageData(title, currentURL, r),
  622. Admin: admin,
  623. Error: error,
  624. IsAdd: isAdd,
  625. }
  626. renderAdminTemplate(w, templateAdmin, data)
  627. }
  628. func (s *httpdServer) renderUserPage(w http.ResponseWriter, r *http.Request, user *dataprovider.User,
  629. mode userPageMode, error string,
  630. ) {
  631. folders, err := s.getWebVirtualFolders(w, r, defaultQueryLimit, true)
  632. if err != nil {
  633. return
  634. }
  635. groups, err := s.getWebGroups(w, r, defaultQueryLimit, true)
  636. if err != nil {
  637. return
  638. }
  639. user.SetEmptySecretsIfNil()
  640. var title, currentURL string
  641. switch mode {
  642. case userPageModeAdd:
  643. title = "Add a new user"
  644. currentURL = webUserPath
  645. case userPageModeUpdate:
  646. title = "Update user"
  647. currentURL = fmt.Sprintf("%v/%v", webUserPath, url.PathEscape(user.Username))
  648. case userPageModeTemplate:
  649. title = "User template"
  650. currentURL = webTemplateUser
  651. }
  652. if user.Password != "" && user.IsPasswordHashed() && mode == userPageModeUpdate {
  653. user.Password = redactedSecret
  654. }
  655. user.FsConfig.RedactedSecret = redactedSecret
  656. data := userPage{
  657. basePage: s.getBasePageData(title, currentURL, r),
  658. Mode: mode,
  659. Error: error,
  660. User: user,
  661. ValidPerms: dataprovider.ValidPerms,
  662. ValidLoginMethods: dataprovider.ValidLoginMethods,
  663. ValidProtocols: dataprovider.ValidProtocols,
  664. TwoFactorProtocols: dataprovider.MFAProtocols,
  665. WebClientOptions: sdk.WebClientOptions,
  666. RootDirPerms: user.GetPermissionsForPath("/"),
  667. VirtualFolders: folders,
  668. Groups: groups,
  669. CanImpersonate: os.Getuid() == 0,
  670. FsWrapper: fsWrapper{
  671. Filesystem: user.FsConfig,
  672. IsUserPage: true,
  673. IsGroupPage: false,
  674. HasUsersBaseDir: dataprovider.HasUsersBaseDir(),
  675. DirPath: user.HomeDir,
  676. },
  677. }
  678. renderAdminTemplate(w, templateUser, data)
  679. }
  680. func (s *httpdServer) renderGroupPage(w http.ResponseWriter, r *http.Request, group dataprovider.Group,
  681. mode groupPageMode, error string,
  682. ) {
  683. folders, err := s.getWebVirtualFolders(w, r, defaultQueryLimit, true)
  684. if err != nil {
  685. return
  686. }
  687. group.SetEmptySecretsIfNil()
  688. group.UserSettings.FsConfig.RedactedSecret = redactedSecret
  689. var title, currentURL string
  690. switch mode {
  691. case groupPageModeAdd:
  692. title = "Add a new group"
  693. currentURL = webGroupPath
  694. case groupPageModeUpdate:
  695. title = "Update group"
  696. currentURL = fmt.Sprintf("%v/%v", webGroupPath, url.PathEscape(group.Name))
  697. }
  698. group.UserSettings.FsConfig.RedactedSecret = redactedSecret
  699. group.UserSettings.FsConfig.SetEmptySecretsIfNil()
  700. data := groupPage{
  701. basePage: s.getBasePageData(title, currentURL, r),
  702. Error: error,
  703. Group: &group,
  704. Mode: mode,
  705. ValidPerms: dataprovider.ValidPerms,
  706. ValidLoginMethods: dataprovider.ValidLoginMethods,
  707. ValidProtocols: dataprovider.ValidProtocols,
  708. TwoFactorProtocols: dataprovider.MFAProtocols,
  709. WebClientOptions: sdk.WebClientOptions,
  710. VirtualFolders: folders,
  711. FsWrapper: fsWrapper{
  712. Filesystem: group.UserSettings.FsConfig,
  713. IsUserPage: false,
  714. IsGroupPage: true,
  715. HasUsersBaseDir: false,
  716. DirPath: group.UserSettings.HomeDir,
  717. },
  718. }
  719. renderAdminTemplate(w, templateGroup, data)
  720. }
  721. func (s *httpdServer) renderFolderPage(w http.ResponseWriter, r *http.Request, folder vfs.BaseVirtualFolder,
  722. mode folderPageMode, error string,
  723. ) {
  724. var title, currentURL string
  725. switch mode {
  726. case folderPageModeAdd:
  727. title = "Add a new folder"
  728. currentURL = webFolderPath
  729. case folderPageModeUpdate:
  730. title = "Update folder"
  731. currentURL = fmt.Sprintf("%v/%v", webFolderPath, url.PathEscape(folder.Name))
  732. case folderPageModeTemplate:
  733. title = "Folder template"
  734. currentURL = webTemplateFolder
  735. }
  736. folder.FsConfig.RedactedSecret = redactedSecret
  737. folder.FsConfig.SetEmptySecretsIfNil()
  738. data := folderPage{
  739. basePage: s.getBasePageData(title, currentURL, r),
  740. Error: error,
  741. Folder: folder,
  742. Mode: mode,
  743. FsWrapper: fsWrapper{
  744. Filesystem: folder.FsConfig,
  745. IsUserPage: false,
  746. IsGroupPage: false,
  747. HasUsersBaseDir: false,
  748. DirPath: folder.MappedPath,
  749. },
  750. }
  751. renderAdminTemplate(w, templateFolder, data)
  752. }
  753. func getFoldersForTemplate(r *http.Request) []string {
  754. var res []string
  755. folderNames := r.Form["tpl_foldername"]
  756. folders := make(map[string]bool)
  757. for _, name := range folderNames {
  758. name = strings.TrimSpace(name)
  759. if name == "" {
  760. continue
  761. }
  762. if _, ok := folders[name]; ok {
  763. continue
  764. }
  765. folders[name] = true
  766. res = append(res, name)
  767. }
  768. return res
  769. }
  770. func getUsersForTemplate(r *http.Request) []userTemplateFields {
  771. var res []userTemplateFields
  772. tplUsernames := r.Form["tpl_username"]
  773. tplPasswords := r.Form["tpl_password"]
  774. tplPublicKeys := r.Form["tpl_public_keys"]
  775. users := make(map[string]bool)
  776. for idx, username := range tplUsernames {
  777. username = strings.TrimSpace(username)
  778. password := ""
  779. publicKey := ""
  780. if len(tplPasswords) > idx {
  781. password = strings.TrimSpace(tplPasswords[idx])
  782. }
  783. if len(tplPublicKeys) > idx {
  784. publicKey = strings.TrimSpace(tplPublicKeys[idx])
  785. }
  786. if username == "" {
  787. continue
  788. }
  789. if _, ok := users[username]; ok {
  790. continue
  791. }
  792. users[username] = true
  793. res = append(res, userTemplateFields{
  794. Username: username,
  795. Password: password,
  796. PublicKeys: []string{publicKey},
  797. })
  798. }
  799. return res
  800. }
  801. func getVirtualFoldersFromPostFields(r *http.Request) []vfs.VirtualFolder {
  802. var virtualFolders []vfs.VirtualFolder
  803. folderPaths := r.Form["vfolder_path"]
  804. folderNames := r.Form["vfolder_name"]
  805. folderQuotaSizes := r.Form["vfolder_quota_size"]
  806. folderQuotaFiles := r.Form["vfolder_quota_files"]
  807. for idx, p := range folderPaths {
  808. p = strings.TrimSpace(p)
  809. name := ""
  810. if len(folderNames) > idx {
  811. name = folderNames[idx]
  812. }
  813. if p != "" && name != "" {
  814. vfolder := vfs.VirtualFolder{
  815. BaseVirtualFolder: vfs.BaseVirtualFolder{
  816. Name: name,
  817. },
  818. VirtualPath: p,
  819. QuotaFiles: -1,
  820. QuotaSize: -1,
  821. }
  822. if len(folderQuotaSizes) > idx {
  823. quotaSize, err := strconv.ParseInt(strings.TrimSpace(folderQuotaSizes[idx]), 10, 64)
  824. if err == nil {
  825. vfolder.QuotaSize = quotaSize
  826. }
  827. }
  828. if len(folderQuotaFiles) > idx {
  829. quotaFiles, err := strconv.Atoi(strings.TrimSpace(folderQuotaFiles[idx]))
  830. if err == nil {
  831. vfolder.QuotaFiles = quotaFiles
  832. }
  833. }
  834. virtualFolders = append(virtualFolders, vfolder)
  835. }
  836. }
  837. return virtualFolders
  838. }
  839. func getSubDirPermissionsFromPostFields(r *http.Request) map[string][]string {
  840. permissions := make(map[string][]string)
  841. for k := range r.Form {
  842. if strings.HasPrefix(k, "sub_perm_path") {
  843. p := strings.TrimSpace(r.Form.Get(k))
  844. if p != "" {
  845. idx := strings.TrimPrefix(k, "sub_perm_path")
  846. permissions[p] = r.Form[fmt.Sprintf("sub_perm_permissions%v", idx)]
  847. }
  848. }
  849. }
  850. return permissions
  851. }
  852. func getUserPermissionsFromPostFields(r *http.Request) map[string][]string {
  853. permissions := getSubDirPermissionsFromPostFields(r)
  854. permissions["/"] = r.Form["permissions"]
  855. return permissions
  856. }
  857. func getDataTransferLimitsFromPostFields(r *http.Request) ([]sdk.DataTransferLimit, error) {
  858. var result []sdk.DataTransferLimit
  859. for k := range r.Form {
  860. if strings.HasPrefix(k, "data_transfer_limit_sources") {
  861. sources := getSliceFromDelimitedValues(r.Form.Get(k), ",")
  862. if len(sources) > 0 {
  863. dtLimit := sdk.DataTransferLimit{
  864. Sources: sources,
  865. }
  866. idx := strings.TrimPrefix(k, "data_transfer_limit_sources")
  867. ul := r.Form.Get(fmt.Sprintf("upload_data_transfer_source%v", idx))
  868. dl := r.Form.Get(fmt.Sprintf("download_data_transfer_source%v", idx))
  869. total := r.Form.Get(fmt.Sprintf("total_data_transfer_source%v", idx))
  870. if ul != "" {
  871. dataUL, err := strconv.ParseInt(ul, 10, 64)
  872. if err != nil {
  873. return result, fmt.Errorf("invalid upload_data_transfer_source%v %#v: %w", idx, ul, err)
  874. }
  875. dtLimit.UploadDataTransfer = dataUL
  876. }
  877. if dl != "" {
  878. dataDL, err := strconv.ParseInt(dl, 10, 64)
  879. if err != nil {
  880. return result, fmt.Errorf("invalid download_data_transfer_source%v %#v: %w", idx, dl, err)
  881. }
  882. dtLimit.DownloadDataTransfer = dataDL
  883. }
  884. if total != "" {
  885. dataTotal, err := strconv.ParseInt(total, 10, 64)
  886. if err != nil {
  887. return result, fmt.Errorf("invalid total_data_transfer_source%v %#v: %w", idx, total, err)
  888. }
  889. dtLimit.TotalDataTransfer = dataTotal
  890. }
  891. result = append(result, dtLimit)
  892. }
  893. }
  894. }
  895. return result, nil
  896. }
  897. func getBandwidthLimitsFromPostFields(r *http.Request) ([]sdk.BandwidthLimit, error) {
  898. var result []sdk.BandwidthLimit
  899. for k := range r.Form {
  900. if strings.HasPrefix(k, "bandwidth_limit_sources") {
  901. sources := getSliceFromDelimitedValues(r.Form.Get(k), ",")
  902. if len(sources) > 0 {
  903. bwLimit := sdk.BandwidthLimit{
  904. Sources: sources,
  905. }
  906. idx := strings.TrimPrefix(k, "bandwidth_limit_sources")
  907. ul := r.Form.Get(fmt.Sprintf("upload_bandwidth_source%v", idx))
  908. dl := r.Form.Get(fmt.Sprintf("download_bandwidth_source%v", idx))
  909. if ul != "" {
  910. bandwidthUL, err := strconv.ParseInt(ul, 10, 64)
  911. if err != nil {
  912. return result, fmt.Errorf("invalid upload_bandwidth_source%v %#v: %w", idx, ul, err)
  913. }
  914. bwLimit.UploadBandwidth = bandwidthUL
  915. }
  916. if dl != "" {
  917. bandwidthDL, err := strconv.ParseInt(dl, 10, 64)
  918. if err != nil {
  919. return result, fmt.Errorf("invalid download_bandwidth_source%v %#v: %w", idx, ul, err)
  920. }
  921. bwLimit.DownloadBandwidth = bandwidthDL
  922. }
  923. result = append(result, bwLimit)
  924. }
  925. }
  926. }
  927. return result, nil
  928. }
  929. func getPatterDenyPolicyFromString(policy string) int {
  930. denyPolicy := sdk.DenyPolicyDefault
  931. if policy == "1" {
  932. denyPolicy = sdk.DenyPolicyHide
  933. }
  934. return denyPolicy
  935. }
  936. func getFilePatternsFromPostField(r *http.Request) []sdk.PatternsFilter {
  937. var result []sdk.PatternsFilter
  938. allowedPatterns := make(map[string][]string)
  939. deniedPatterns := make(map[string][]string)
  940. patternPolicies := make(map[string]string)
  941. for k := range r.Form {
  942. if strings.HasPrefix(k, "pattern_path") {
  943. p := strings.TrimSpace(r.Form.Get(k))
  944. idx := strings.TrimPrefix(k, "pattern_path")
  945. filters := strings.TrimSpace(r.Form.Get(fmt.Sprintf("patterns%v", idx)))
  946. filters = strings.ReplaceAll(filters, " ", "")
  947. patternType := r.Form.Get(fmt.Sprintf("pattern_type%v", idx))
  948. patternPolicy := r.Form.Get(fmt.Sprintf("pattern_policy%v", idx))
  949. if p != "" && filters != "" {
  950. if patternType == "allowed" {
  951. allowedPatterns[p] = append(allowedPatterns[p], strings.Split(filters, ",")...)
  952. } else {
  953. deniedPatterns[p] = append(deniedPatterns[p], strings.Split(filters, ",")...)
  954. }
  955. if patternPolicy != "" && patternPolicy != "0" {
  956. patternPolicies[p] = patternPolicy
  957. }
  958. }
  959. }
  960. }
  961. for dirAllowed, allowPatterns := range allowedPatterns {
  962. filter := sdk.PatternsFilter{
  963. Path: dirAllowed,
  964. AllowedPatterns: allowPatterns,
  965. DenyPolicy: getPatterDenyPolicyFromString(patternPolicies[dirAllowed]),
  966. }
  967. for dirDenied, denPatterns := range deniedPatterns {
  968. if dirAllowed == dirDenied {
  969. filter.DeniedPatterns = denPatterns
  970. break
  971. }
  972. }
  973. result = append(result, filter)
  974. }
  975. for dirDenied, denPatterns := range deniedPatterns {
  976. found := false
  977. for _, res := range result {
  978. if res.Path == dirDenied {
  979. found = true
  980. break
  981. }
  982. }
  983. if !found {
  984. result = append(result, sdk.PatternsFilter{
  985. Path: dirDenied,
  986. DeniedPatterns: denPatterns,
  987. DenyPolicy: getPatterDenyPolicyFromString(patternPolicies[dirDenied]),
  988. })
  989. }
  990. }
  991. return result
  992. }
  993. func getGroupsFromUserPostFields(r *http.Request) []sdk.GroupMapping {
  994. var groups []sdk.GroupMapping
  995. primaryGroup := r.Form.Get("primary_group")
  996. if primaryGroup != "" {
  997. groups = append(groups, sdk.GroupMapping{
  998. Name: primaryGroup,
  999. Type: sdk.GroupTypePrimary,
  1000. })
  1001. }
  1002. secondaryGroups := r.Form["secondary_groups"]
  1003. for _, name := range secondaryGroups {
  1004. groups = append(groups, sdk.GroupMapping{
  1005. Name: name,
  1006. Type: sdk.GroupTypeSecondary,
  1007. })
  1008. }
  1009. return groups
  1010. }
  1011. func getFiltersFromUserPostFields(r *http.Request) (sdk.BaseUserFilters, error) {
  1012. var filters sdk.BaseUserFilters
  1013. bwLimits, err := getBandwidthLimitsFromPostFields(r)
  1014. if err != nil {
  1015. return filters, err
  1016. }
  1017. dtLimits, err := getDataTransferLimitsFromPostFields(r)
  1018. if err != nil {
  1019. return filters, err
  1020. }
  1021. maxFileSize, err := strconv.ParseInt(r.Form.Get("max_upload_file_size"), 10, 64)
  1022. if err != nil {
  1023. return filters, fmt.Errorf("invalid max upload file size: %w", err)
  1024. }
  1025. filters.BandwidthLimits = bwLimits
  1026. filters.DataTransferLimits = dtLimits
  1027. filters.AllowedIP = getSliceFromDelimitedValues(r.Form.Get("allowed_ip"), ",")
  1028. filters.DeniedIP = getSliceFromDelimitedValues(r.Form.Get("denied_ip"), ",")
  1029. filters.DeniedLoginMethods = r.Form["denied_login_methods"]
  1030. filters.DeniedProtocols = r.Form["denied_protocols"]
  1031. filters.TwoFactorAuthProtocols = r.Form["required_two_factor_protocols"]
  1032. filters.FilePatterns = getFilePatternsFromPostField(r)
  1033. filters.TLSUsername = sdk.TLSUsername(r.Form.Get("tls_username"))
  1034. filters.WebClient = r.Form["web_client_options"]
  1035. hooks := r.Form["hooks"]
  1036. if util.Contains(hooks, "external_auth_disabled") {
  1037. filters.Hooks.ExternalAuthDisabled = true
  1038. }
  1039. if util.Contains(hooks, "pre_login_disabled") {
  1040. filters.Hooks.PreLoginDisabled = true
  1041. }
  1042. if util.Contains(hooks, "check_password_disabled") {
  1043. filters.Hooks.CheckPasswordDisabled = true
  1044. }
  1045. filters.DisableFsChecks = len(r.Form.Get("disable_fs_checks")) > 0
  1046. filters.AllowAPIKeyAuth = len(r.Form.Get("allow_api_key_auth")) > 0
  1047. filters.StartDirectory = r.Form.Get("start_directory")
  1048. filters.MaxUploadFileSize = maxFileSize
  1049. filters.ExternalAuthCacheTime, err = strconv.ParseInt(r.Form.Get("external_auth_cache_time"), 10, 64)
  1050. if err != nil {
  1051. return filters, fmt.Errorf("invalid external auth cache time: %w", err)
  1052. }
  1053. return filters, nil
  1054. }
  1055. func getSecretFromFormField(r *http.Request, field string) *kms.Secret {
  1056. secret := kms.NewPlainSecret(r.Form.Get(field))
  1057. if strings.TrimSpace(secret.GetPayload()) == redactedSecret {
  1058. secret.SetStatus(sdkkms.SecretStatusRedacted)
  1059. }
  1060. if strings.TrimSpace(secret.GetPayload()) == "" {
  1061. secret.SetStatus("")
  1062. }
  1063. return secret
  1064. }
  1065. func getS3Config(r *http.Request) (vfs.S3FsConfig, error) {
  1066. var err error
  1067. config := vfs.S3FsConfig{}
  1068. config.Bucket = r.Form.Get("s3_bucket")
  1069. config.Region = r.Form.Get("s3_region")
  1070. config.AccessKey = r.Form.Get("s3_access_key")
  1071. config.RoleARN = r.Form.Get("s3_role_arn")
  1072. config.AccessSecret = getSecretFromFormField(r, "s3_access_secret")
  1073. config.Endpoint = r.Form.Get("s3_endpoint")
  1074. config.StorageClass = r.Form.Get("s3_storage_class")
  1075. config.ACL = r.Form.Get("s3_acl")
  1076. config.KeyPrefix = r.Form.Get("s3_key_prefix")
  1077. config.UploadPartSize, err = strconv.ParseInt(r.Form.Get("s3_upload_part_size"), 10, 64)
  1078. if err != nil {
  1079. return config, fmt.Errorf("invalid s3 upload part size: %w", err)
  1080. }
  1081. config.UploadConcurrency, err = strconv.Atoi(r.Form.Get("s3_upload_concurrency"))
  1082. if err != nil {
  1083. return config, fmt.Errorf("invalid s3 upload concurrency: %w", err)
  1084. }
  1085. config.DownloadPartSize, err = strconv.ParseInt(r.Form.Get("s3_download_part_size"), 10, 64)
  1086. if err != nil {
  1087. return config, fmt.Errorf("invalid s3 download part size: %w", err)
  1088. }
  1089. config.DownloadConcurrency, err = strconv.Atoi(r.Form.Get("s3_download_concurrency"))
  1090. if err != nil {
  1091. return config, fmt.Errorf("invalid s3 download concurrency: %w", err)
  1092. }
  1093. config.ForcePathStyle = r.Form.Get("s3_force_path_style") != ""
  1094. config.DownloadPartMaxTime, err = strconv.Atoi(r.Form.Get("s3_download_part_max_time"))
  1095. if err != nil {
  1096. return config, fmt.Errorf("invalid s3 download part max time: %w", err)
  1097. }
  1098. config.UploadPartMaxTime, err = strconv.Atoi(r.Form.Get("s3_upload_part_max_time"))
  1099. if err != nil {
  1100. return config, fmt.Errorf("invalid s3 upload part max time: %w", err)
  1101. }
  1102. return config, nil
  1103. }
  1104. func getGCSConfig(r *http.Request) (vfs.GCSFsConfig, error) {
  1105. var err error
  1106. config := vfs.GCSFsConfig{}
  1107. config.Bucket = r.Form.Get("gcs_bucket")
  1108. config.StorageClass = r.Form.Get("gcs_storage_class")
  1109. config.ACL = r.Form.Get("gcs_acl")
  1110. config.KeyPrefix = r.Form.Get("gcs_key_prefix")
  1111. autoCredentials := r.Form.Get("gcs_auto_credentials")
  1112. if autoCredentials != "" {
  1113. config.AutomaticCredentials = 1
  1114. } else {
  1115. config.AutomaticCredentials = 0
  1116. }
  1117. credentials, _, err := r.FormFile("gcs_credential_file")
  1118. if err == http.ErrMissingFile {
  1119. return config, nil
  1120. }
  1121. if err != nil {
  1122. return config, err
  1123. }
  1124. defer credentials.Close()
  1125. fileBytes, err := io.ReadAll(credentials)
  1126. if err != nil || len(fileBytes) == 0 {
  1127. if len(fileBytes) == 0 {
  1128. err = errors.New("credentials file size must be greater than 0")
  1129. }
  1130. return config, err
  1131. }
  1132. config.Credentials = kms.NewPlainSecret(string(fileBytes))
  1133. config.AutomaticCredentials = 0
  1134. return config, err
  1135. }
  1136. func getSFTPConfig(r *http.Request) (vfs.SFTPFsConfig, error) {
  1137. var err error
  1138. config := vfs.SFTPFsConfig{}
  1139. config.Endpoint = r.Form.Get("sftp_endpoint")
  1140. config.Username = r.Form.Get("sftp_username")
  1141. config.Password = getSecretFromFormField(r, "sftp_password")
  1142. config.PrivateKey = getSecretFromFormField(r, "sftp_private_key")
  1143. config.KeyPassphrase = getSecretFromFormField(r, "sftp_key_passphrase")
  1144. fingerprintsFormValue := r.Form.Get("sftp_fingerprints")
  1145. config.Fingerprints = getSliceFromDelimitedValues(fingerprintsFormValue, "\n")
  1146. config.Prefix = r.Form.Get("sftp_prefix")
  1147. config.DisableCouncurrentReads = len(r.Form.Get("sftp_disable_concurrent_reads")) > 0
  1148. config.BufferSize, err = strconv.ParseInt(r.Form.Get("sftp_buffer_size"), 10, 64)
  1149. if err != nil {
  1150. return config, fmt.Errorf("invalid SFTP buffer size: %w", err)
  1151. }
  1152. return config, nil
  1153. }
  1154. func getAzureConfig(r *http.Request) (vfs.AzBlobFsConfig, error) {
  1155. var err error
  1156. config := vfs.AzBlobFsConfig{}
  1157. config.Container = r.Form.Get("az_container")
  1158. config.AccountName = r.Form.Get("az_account_name")
  1159. config.AccountKey = getSecretFromFormField(r, "az_account_key")
  1160. config.SASURL = getSecretFromFormField(r, "az_sas_url")
  1161. config.Endpoint = r.Form.Get("az_endpoint")
  1162. config.KeyPrefix = r.Form.Get("az_key_prefix")
  1163. config.AccessTier = r.Form.Get("az_access_tier")
  1164. config.UseEmulator = len(r.Form.Get("az_use_emulator")) > 0
  1165. config.UploadPartSize, err = strconv.ParseInt(r.Form.Get("az_upload_part_size"), 10, 64)
  1166. if err != nil {
  1167. return config, fmt.Errorf("invalid azure upload part size: %w", err)
  1168. }
  1169. config.UploadConcurrency, err = strconv.Atoi(r.Form.Get("az_upload_concurrency"))
  1170. if err != nil {
  1171. return config, fmt.Errorf("invalid azure upload concurrency: %w", err)
  1172. }
  1173. config.DownloadPartSize, err = strconv.ParseInt(r.Form.Get("az_download_part_size"), 10, 64)
  1174. if err != nil {
  1175. return config, fmt.Errorf("invalid azure download part size: %w", err)
  1176. }
  1177. config.DownloadConcurrency, err = strconv.Atoi(r.Form.Get("az_download_concurrency"))
  1178. if err != nil {
  1179. return config, fmt.Errorf("invalid azure download concurrency: %w", err)
  1180. }
  1181. return config, nil
  1182. }
  1183. func getFsConfigFromPostFields(r *http.Request) (vfs.Filesystem, error) {
  1184. var fs vfs.Filesystem
  1185. fs.Provider = sdk.GetProviderByName(r.Form.Get("fs_provider"))
  1186. switch fs.Provider {
  1187. case sdk.S3FilesystemProvider:
  1188. config, err := getS3Config(r)
  1189. if err != nil {
  1190. return fs, err
  1191. }
  1192. fs.S3Config = config
  1193. case sdk.AzureBlobFilesystemProvider:
  1194. config, err := getAzureConfig(r)
  1195. if err != nil {
  1196. return fs, err
  1197. }
  1198. fs.AzBlobConfig = config
  1199. case sdk.GCSFilesystemProvider:
  1200. config, err := getGCSConfig(r)
  1201. if err != nil {
  1202. return fs, err
  1203. }
  1204. fs.GCSConfig = config
  1205. case sdk.CryptedFilesystemProvider:
  1206. fs.CryptConfig.Passphrase = getSecretFromFormField(r, "crypt_passphrase")
  1207. case sdk.SFTPFilesystemProvider:
  1208. config, err := getSFTPConfig(r)
  1209. if err != nil {
  1210. return fs, err
  1211. }
  1212. fs.SFTPConfig = config
  1213. }
  1214. return fs, nil
  1215. }
  1216. func getAdminFromPostFields(r *http.Request) (dataprovider.Admin, error) {
  1217. var admin dataprovider.Admin
  1218. err := r.ParseForm()
  1219. if err != nil {
  1220. return admin, err
  1221. }
  1222. status, err := strconv.Atoi(r.Form.Get("status"))
  1223. if err != nil {
  1224. return admin, fmt.Errorf("invalid status: %w", err)
  1225. }
  1226. admin.Username = r.Form.Get("username")
  1227. admin.Password = r.Form.Get("password")
  1228. admin.Permissions = r.Form["permissions"]
  1229. admin.Email = r.Form.Get("email")
  1230. admin.Status = status
  1231. admin.Filters.AllowList = getSliceFromDelimitedValues(r.Form.Get("allowed_ip"), ",")
  1232. admin.Filters.AllowAPIKeyAuth = len(r.Form.Get("allow_api_key_auth")) > 0
  1233. admin.AdditionalInfo = r.Form.Get("additional_info")
  1234. admin.Description = r.Form.Get("description")
  1235. return admin, nil
  1236. }
  1237. func replacePlaceholders(field string, replacements map[string]string) string {
  1238. for k, v := range replacements {
  1239. field = strings.ReplaceAll(field, k, v)
  1240. }
  1241. return field
  1242. }
  1243. func getFolderFromTemplate(folder vfs.BaseVirtualFolder, name string) vfs.BaseVirtualFolder {
  1244. folder.Name = name
  1245. replacements := make(map[string]string)
  1246. replacements["%name%"] = folder.Name
  1247. folder.MappedPath = replacePlaceholders(folder.MappedPath, replacements)
  1248. folder.Description = replacePlaceholders(folder.Description, replacements)
  1249. switch folder.FsConfig.Provider {
  1250. case sdk.CryptedFilesystemProvider:
  1251. folder.FsConfig.CryptConfig = getCryptFsFromTemplate(folder.FsConfig.CryptConfig, replacements)
  1252. case sdk.S3FilesystemProvider:
  1253. folder.FsConfig.S3Config = getS3FsFromTemplate(folder.FsConfig.S3Config, replacements)
  1254. case sdk.GCSFilesystemProvider:
  1255. folder.FsConfig.GCSConfig = getGCSFsFromTemplate(folder.FsConfig.GCSConfig, replacements)
  1256. case sdk.AzureBlobFilesystemProvider:
  1257. folder.FsConfig.AzBlobConfig = getAzBlobFsFromTemplate(folder.FsConfig.AzBlobConfig, replacements)
  1258. case sdk.SFTPFilesystemProvider:
  1259. folder.FsConfig.SFTPConfig = getSFTPFsFromTemplate(folder.FsConfig.SFTPConfig, replacements)
  1260. }
  1261. return folder
  1262. }
  1263. func getCryptFsFromTemplate(fsConfig vfs.CryptFsConfig, replacements map[string]string) vfs.CryptFsConfig {
  1264. if fsConfig.Passphrase != nil {
  1265. if fsConfig.Passphrase.IsPlain() {
  1266. payload := replacePlaceholders(fsConfig.Passphrase.GetPayload(), replacements)
  1267. fsConfig.Passphrase = kms.NewPlainSecret(payload)
  1268. }
  1269. }
  1270. return fsConfig
  1271. }
  1272. func getS3FsFromTemplate(fsConfig vfs.S3FsConfig, replacements map[string]string) vfs.S3FsConfig {
  1273. fsConfig.KeyPrefix = replacePlaceholders(fsConfig.KeyPrefix, replacements)
  1274. fsConfig.AccessKey = replacePlaceholders(fsConfig.AccessKey, replacements)
  1275. if fsConfig.AccessSecret != nil && fsConfig.AccessSecret.IsPlain() {
  1276. payload := replacePlaceholders(fsConfig.AccessSecret.GetPayload(), replacements)
  1277. fsConfig.AccessSecret = kms.NewPlainSecret(payload)
  1278. }
  1279. return fsConfig
  1280. }
  1281. func getGCSFsFromTemplate(fsConfig vfs.GCSFsConfig, replacements map[string]string) vfs.GCSFsConfig {
  1282. fsConfig.KeyPrefix = replacePlaceholders(fsConfig.KeyPrefix, replacements)
  1283. return fsConfig
  1284. }
  1285. func getAzBlobFsFromTemplate(fsConfig vfs.AzBlobFsConfig, replacements map[string]string) vfs.AzBlobFsConfig {
  1286. fsConfig.KeyPrefix = replacePlaceholders(fsConfig.KeyPrefix, replacements)
  1287. fsConfig.AccountName = replacePlaceholders(fsConfig.AccountName, replacements)
  1288. if fsConfig.AccountKey != nil && fsConfig.AccountKey.IsPlain() {
  1289. payload := replacePlaceholders(fsConfig.AccountKey.GetPayload(), replacements)
  1290. fsConfig.AccountKey = kms.NewPlainSecret(payload)
  1291. }
  1292. return fsConfig
  1293. }
  1294. func getSFTPFsFromTemplate(fsConfig vfs.SFTPFsConfig, replacements map[string]string) vfs.SFTPFsConfig {
  1295. fsConfig.Prefix = replacePlaceholders(fsConfig.Prefix, replacements)
  1296. fsConfig.Username = replacePlaceholders(fsConfig.Username, replacements)
  1297. if fsConfig.Password != nil && fsConfig.Password.IsPlain() {
  1298. payload := replacePlaceholders(fsConfig.Password.GetPayload(), replacements)
  1299. fsConfig.Password = kms.NewPlainSecret(payload)
  1300. }
  1301. return fsConfig
  1302. }
  1303. func getUserFromTemplate(user dataprovider.User, template userTemplateFields) dataprovider.User {
  1304. user.Username = template.Username
  1305. user.Password = template.Password
  1306. user.PublicKeys = template.PublicKeys
  1307. replacements := make(map[string]string)
  1308. replacements["%username%"] = user.Username
  1309. if user.Password != "" && !user.IsPasswordHashed() {
  1310. user.Password = replacePlaceholders(user.Password, replacements)
  1311. replacements["%password%"] = user.Password
  1312. }
  1313. user.HomeDir = replacePlaceholders(user.HomeDir, replacements)
  1314. var vfolders []vfs.VirtualFolder
  1315. for _, vfolder := range user.VirtualFolders {
  1316. vfolder.Name = replacePlaceholders(vfolder.Name, replacements)
  1317. vfolder.VirtualPath = replacePlaceholders(vfolder.VirtualPath, replacements)
  1318. vfolders = append(vfolders, vfolder)
  1319. }
  1320. user.VirtualFolders = vfolders
  1321. user.Description = replacePlaceholders(user.Description, replacements)
  1322. user.AdditionalInfo = replacePlaceholders(user.AdditionalInfo, replacements)
  1323. user.Filters.StartDirectory = replacePlaceholders(user.Filters.StartDirectory, replacements)
  1324. switch user.FsConfig.Provider {
  1325. case sdk.CryptedFilesystemProvider:
  1326. user.FsConfig.CryptConfig = getCryptFsFromTemplate(user.FsConfig.CryptConfig, replacements)
  1327. case sdk.S3FilesystemProvider:
  1328. user.FsConfig.S3Config = getS3FsFromTemplate(user.FsConfig.S3Config, replacements)
  1329. case sdk.GCSFilesystemProvider:
  1330. user.FsConfig.GCSConfig = getGCSFsFromTemplate(user.FsConfig.GCSConfig, replacements)
  1331. case sdk.AzureBlobFilesystemProvider:
  1332. user.FsConfig.AzBlobConfig = getAzBlobFsFromTemplate(user.FsConfig.AzBlobConfig, replacements)
  1333. case sdk.SFTPFilesystemProvider:
  1334. user.FsConfig.SFTPConfig = getSFTPFsFromTemplate(user.FsConfig.SFTPConfig, replacements)
  1335. }
  1336. return user
  1337. }
  1338. func getTransferLimits(r *http.Request) (int64, int64, int64, error) {
  1339. dataTransferUL, err := strconv.ParseInt(r.Form.Get("upload_data_transfer"), 10, 64)
  1340. if err != nil {
  1341. return 0, 0, 0, fmt.Errorf("invalid upload data transfer: %w", err)
  1342. }
  1343. dataTransferDL, err := strconv.ParseInt(r.Form.Get("download_data_transfer"), 10, 64)
  1344. if err != nil {
  1345. return 0, 0, 0, fmt.Errorf("invalid download data transfer: %w", err)
  1346. }
  1347. dataTransferTotal, err := strconv.ParseInt(r.Form.Get("total_data_transfer"), 10, 64)
  1348. if err != nil {
  1349. return 0, 0, 0, fmt.Errorf("invalid total data transfer: %w", err)
  1350. }
  1351. return dataTransferUL, dataTransferDL, dataTransferTotal, nil
  1352. }
  1353. func getQuotaLimits(r *http.Request) (int64, int, error) {
  1354. quotaSize, err := strconv.ParseInt(r.Form.Get("quota_size"), 10, 64)
  1355. if err != nil {
  1356. return 0, 0, fmt.Errorf("invalid quota size: %w", err)
  1357. }
  1358. quotaFiles, err := strconv.Atoi(r.Form.Get("quota_files"))
  1359. if err != nil {
  1360. return 0, 0, fmt.Errorf("invalid quota files: %w", err)
  1361. }
  1362. return quotaSize, quotaFiles, nil
  1363. }
  1364. func getUserFromPostFields(r *http.Request) (dataprovider.User, error) {
  1365. user := dataprovider.User{}
  1366. err := r.ParseMultipartForm(maxRequestSize)
  1367. if err != nil {
  1368. return user, err
  1369. }
  1370. defer r.MultipartForm.RemoveAll() //nolint:errcheck
  1371. uid, err := strconv.Atoi(r.Form.Get("uid"))
  1372. if err != nil {
  1373. return user, fmt.Errorf("invalid uid: %w", err)
  1374. }
  1375. gid, err := strconv.Atoi(r.Form.Get("gid"))
  1376. if err != nil {
  1377. return user, fmt.Errorf("invalid uid: %w", err)
  1378. }
  1379. maxSessions, err := strconv.Atoi(r.Form.Get("max_sessions"))
  1380. if err != nil {
  1381. return user, fmt.Errorf("invalid max sessions: %w", err)
  1382. }
  1383. quotaSize, quotaFiles, err := getQuotaLimits(r)
  1384. if err != nil {
  1385. return user, err
  1386. }
  1387. bandwidthUL, err := strconv.ParseInt(r.Form.Get("upload_bandwidth"), 10, 64)
  1388. if err != nil {
  1389. return user, fmt.Errorf("invalid upload bandwidth: %w", err)
  1390. }
  1391. bandwidthDL, err := strconv.ParseInt(r.Form.Get("download_bandwidth"), 10, 64)
  1392. if err != nil {
  1393. return user, fmt.Errorf("invalid download bandwidth: %w", err)
  1394. }
  1395. dataTransferUL, dataTransferDL, dataTransferTotal, err := getTransferLimits(r)
  1396. if err != nil {
  1397. return user, err
  1398. }
  1399. status, err := strconv.Atoi(r.Form.Get("status"))
  1400. if err != nil {
  1401. return user, fmt.Errorf("invalid status: %w", err)
  1402. }
  1403. expirationDateMillis := int64(0)
  1404. expirationDateString := r.Form.Get("expiration_date")
  1405. if strings.TrimSpace(expirationDateString) != "" {
  1406. expirationDate, err := time.Parse(webDateTimeFormat, expirationDateString)
  1407. if err != nil {
  1408. return user, err
  1409. }
  1410. expirationDateMillis = util.GetTimeAsMsSinceEpoch(expirationDate)
  1411. }
  1412. fsConfig, err := getFsConfigFromPostFields(r)
  1413. if err != nil {
  1414. return user, err
  1415. }
  1416. filters, err := getFiltersFromUserPostFields(r)
  1417. if err != nil {
  1418. return user, err
  1419. }
  1420. user = dataprovider.User{
  1421. BaseUser: sdk.BaseUser{
  1422. Username: r.Form.Get("username"),
  1423. Email: r.Form.Get("email"),
  1424. Password: r.Form.Get("password"),
  1425. PublicKeys: r.Form["public_keys"],
  1426. HomeDir: r.Form.Get("home_dir"),
  1427. UID: uid,
  1428. GID: gid,
  1429. Permissions: getUserPermissionsFromPostFields(r),
  1430. MaxSessions: maxSessions,
  1431. QuotaSize: quotaSize,
  1432. QuotaFiles: quotaFiles,
  1433. UploadBandwidth: bandwidthUL,
  1434. DownloadBandwidth: bandwidthDL,
  1435. UploadDataTransfer: dataTransferUL,
  1436. DownloadDataTransfer: dataTransferDL,
  1437. TotalDataTransfer: dataTransferTotal,
  1438. Status: status,
  1439. ExpirationDate: expirationDateMillis,
  1440. AdditionalInfo: r.Form.Get("additional_info"),
  1441. Description: r.Form.Get("description"),
  1442. },
  1443. Filters: dataprovider.UserFilters{
  1444. BaseUserFilters: filters,
  1445. },
  1446. VirtualFolders: getVirtualFoldersFromPostFields(r),
  1447. FsConfig: fsConfig,
  1448. Groups: getGroupsFromUserPostFields(r),
  1449. }
  1450. return user, nil
  1451. }
  1452. func getGroupFromPostFields(r *http.Request) (dataprovider.Group, error) {
  1453. group := dataprovider.Group{}
  1454. err := r.ParseMultipartForm(maxRequestSize)
  1455. if err != nil {
  1456. return group, err
  1457. }
  1458. defer r.MultipartForm.RemoveAll() //nolint:errcheck
  1459. maxSessions, err := strconv.Atoi(r.Form.Get("max_sessions"))
  1460. if err != nil {
  1461. return group, fmt.Errorf("invalid max sessions: %w", err)
  1462. }
  1463. quotaSize, quotaFiles, err := getQuotaLimits(r)
  1464. if err != nil {
  1465. return group, err
  1466. }
  1467. bandwidthUL, err := strconv.ParseInt(r.Form.Get("upload_bandwidth"), 10, 64)
  1468. if err != nil {
  1469. return group, fmt.Errorf("invalid upload bandwidth: %w", err)
  1470. }
  1471. bandwidthDL, err := strconv.ParseInt(r.Form.Get("download_bandwidth"), 10, 64)
  1472. if err != nil {
  1473. return group, fmt.Errorf("invalid download bandwidth: %w", err)
  1474. }
  1475. dataTransferUL, dataTransferDL, dataTransferTotal, err := getTransferLimits(r)
  1476. if err != nil {
  1477. return group, err
  1478. }
  1479. fsConfig, err := getFsConfigFromPostFields(r)
  1480. if err != nil {
  1481. return group, err
  1482. }
  1483. filters, err := getFiltersFromUserPostFields(r)
  1484. if err != nil {
  1485. return group, err
  1486. }
  1487. group = dataprovider.Group{
  1488. BaseGroup: sdk.BaseGroup{
  1489. Name: r.Form.Get("name"),
  1490. Description: r.Form.Get("description"),
  1491. },
  1492. UserSettings: dataprovider.GroupUserSettings{
  1493. BaseGroupUserSettings: sdk.BaseGroupUserSettings{
  1494. HomeDir: r.Form.Get("home_dir"),
  1495. MaxSessions: maxSessions,
  1496. QuotaSize: quotaSize,
  1497. QuotaFiles: quotaFiles,
  1498. Permissions: getSubDirPermissionsFromPostFields(r),
  1499. UploadBandwidth: bandwidthUL,
  1500. DownloadBandwidth: bandwidthDL,
  1501. UploadDataTransfer: dataTransferUL,
  1502. DownloadDataTransfer: dataTransferDL,
  1503. TotalDataTransfer: dataTransferTotal,
  1504. Filters: filters,
  1505. },
  1506. FsConfig: fsConfig,
  1507. },
  1508. VirtualFolders: getVirtualFoldersFromPostFields(r),
  1509. }
  1510. return group, nil
  1511. }
  1512. func (s *httpdServer) handleWebAdminForgotPwd(w http.ResponseWriter, r *http.Request) {
  1513. r.Body = http.MaxBytesReader(w, r.Body, maxRequestSize)
  1514. if !smtp.IsEnabled() {
  1515. s.renderNotFoundPage(w, r, errors.New("this page does not exist"))
  1516. return
  1517. }
  1518. s.renderForgotPwdPage(w, "", util.GetIPFromRemoteAddress(r.RemoteAddr))
  1519. }
  1520. func (s *httpdServer) handleWebAdminForgotPwdPost(w http.ResponseWriter, r *http.Request) {
  1521. r.Body = http.MaxBytesReader(w, r.Body, maxRequestSize)
  1522. ipAddr := util.GetIPFromRemoteAddress(r.RemoteAddr)
  1523. err := r.ParseForm()
  1524. if err != nil {
  1525. s.renderForgotPwdPage(w, err.Error(), ipAddr)
  1526. return
  1527. }
  1528. if err := verifyCSRFToken(r.Form.Get(csrfFormToken), ipAddr); err != nil {
  1529. s.renderForbiddenPage(w, r, err.Error())
  1530. return
  1531. }
  1532. err = handleForgotPassword(r, r.Form.Get("username"), true)
  1533. if err != nil {
  1534. if e, ok := err.(*util.ValidationError); ok {
  1535. s.renderForgotPwdPage(w, e.GetErrorString(), ipAddr)
  1536. return
  1537. }
  1538. s.renderForgotPwdPage(w, err.Error(), ipAddr)
  1539. return
  1540. }
  1541. http.Redirect(w, r, webAdminResetPwdPath, http.StatusFound)
  1542. }
  1543. func (s *httpdServer) handleWebAdminPasswordReset(w http.ResponseWriter, r *http.Request) {
  1544. r.Body = http.MaxBytesReader(w, r.Body, maxLoginBodySize)
  1545. if !smtp.IsEnabled() {
  1546. s.renderNotFoundPage(w, r, errors.New("this page does not exist"))
  1547. return
  1548. }
  1549. s.renderResetPwdPage(w, "", util.GetIPFromRemoteAddress(r.RemoteAddr))
  1550. }
  1551. func (s *httpdServer) handleWebAdminTwoFactor(w http.ResponseWriter, r *http.Request) {
  1552. r.Body = http.MaxBytesReader(w, r.Body, maxRequestSize)
  1553. s.renderTwoFactorPage(w, "", util.GetIPFromRemoteAddress(r.RemoteAddr))
  1554. }
  1555. func (s *httpdServer) handleWebAdminTwoFactorRecovery(w http.ResponseWriter, r *http.Request) {
  1556. r.Body = http.MaxBytesReader(w, r.Body, maxRequestSize)
  1557. s.renderTwoFactorRecoveryPage(w, "", util.GetIPFromRemoteAddress(r.RemoteAddr))
  1558. }
  1559. func (s *httpdServer) handleWebAdminMFA(w http.ResponseWriter, r *http.Request) {
  1560. r.Body = http.MaxBytesReader(w, r.Body, maxRequestSize)
  1561. s.renderMFAPage(w, r)
  1562. }
  1563. func (s *httpdServer) handleWebAdminProfile(w http.ResponseWriter, r *http.Request) {
  1564. r.Body = http.MaxBytesReader(w, r.Body, maxRequestSize)
  1565. s.renderProfilePage(w, r, "")
  1566. }
  1567. func (s *httpdServer) handleWebAdminChangePwd(w http.ResponseWriter, r *http.Request) {
  1568. r.Body = http.MaxBytesReader(w, r.Body, maxRequestSize)
  1569. s.renderChangePasswordPage(w, r, "")
  1570. }
  1571. func (s *httpdServer) handleWebAdminProfilePost(w http.ResponseWriter, r *http.Request) {
  1572. r.Body = http.MaxBytesReader(w, r.Body, maxRequestSize)
  1573. err := r.ParseForm()
  1574. if err != nil {
  1575. s.renderProfilePage(w, r, err.Error())
  1576. return
  1577. }
  1578. ipAddr := util.GetIPFromRemoteAddress(r.RemoteAddr)
  1579. if err := verifyCSRFToken(r.Form.Get(csrfFormToken), ipAddr); err != nil {
  1580. s.renderForbiddenPage(w, r, err.Error())
  1581. return
  1582. }
  1583. claims, err := getTokenClaims(r)
  1584. if err != nil || claims.Username == "" {
  1585. s.renderProfilePage(w, r, "Invalid token claims")
  1586. return
  1587. }
  1588. admin, err := dataprovider.AdminExists(claims.Username)
  1589. if err != nil {
  1590. s.renderProfilePage(w, r, err.Error())
  1591. return
  1592. }
  1593. admin.Filters.AllowAPIKeyAuth = len(r.Form.Get("allow_api_key_auth")) > 0
  1594. admin.Email = r.Form.Get("email")
  1595. admin.Description = r.Form.Get("description")
  1596. err = dataprovider.UpdateAdmin(&admin, dataprovider.ActionExecutorSelf, ipAddr)
  1597. if err != nil {
  1598. s.renderProfilePage(w, r, err.Error())
  1599. return
  1600. }
  1601. s.renderMessagePage(w, r, "Profile updated", "", http.StatusOK, nil,
  1602. "Your profile has been successfully updated")
  1603. }
  1604. func (s *httpdServer) handleWebMaintenance(w http.ResponseWriter, r *http.Request) {
  1605. r.Body = http.MaxBytesReader(w, r.Body, maxRequestSize)
  1606. s.renderMaintenancePage(w, r, "")
  1607. }
  1608. func (s *httpdServer) handleWebRestore(w http.ResponseWriter, r *http.Request) {
  1609. r.Body = http.MaxBytesReader(w, r.Body, MaxRestoreSize)
  1610. claims, err := getTokenClaims(r)
  1611. if err != nil || claims.Username == "" {
  1612. s.renderBadRequestPage(w, r, errors.New("invalid token claims"))
  1613. return
  1614. }
  1615. err = r.ParseMultipartForm(MaxRestoreSize)
  1616. if err != nil {
  1617. s.renderMaintenancePage(w, r, err.Error())
  1618. return
  1619. }
  1620. defer r.MultipartForm.RemoveAll() //nolint:errcheck
  1621. ipAddr := util.GetIPFromRemoteAddress(r.RemoteAddr)
  1622. if err := verifyCSRFToken(r.Form.Get(csrfFormToken), ipAddr); err != nil {
  1623. s.renderForbiddenPage(w, r, err.Error())
  1624. return
  1625. }
  1626. restoreMode, err := strconv.Atoi(r.Form.Get("mode"))
  1627. if err != nil {
  1628. s.renderMaintenancePage(w, r, err.Error())
  1629. return
  1630. }
  1631. scanQuota, err := strconv.Atoi(r.Form.Get("quota"))
  1632. if err != nil {
  1633. s.renderMaintenancePage(w, r, err.Error())
  1634. return
  1635. }
  1636. backupFile, _, err := r.FormFile("backup_file")
  1637. if err != nil {
  1638. s.renderMaintenancePage(w, r, err.Error())
  1639. return
  1640. }
  1641. defer backupFile.Close()
  1642. backupContent, err := io.ReadAll(backupFile)
  1643. if err != nil || len(backupContent) == 0 {
  1644. if len(backupContent) == 0 {
  1645. err = errors.New("backup file size must be greater than 0")
  1646. }
  1647. s.renderMaintenancePage(w, r, err.Error())
  1648. return
  1649. }
  1650. if err := restoreBackup(backupContent, "", scanQuota, restoreMode, claims.Username, ipAddr); err != nil {
  1651. s.renderMaintenancePage(w, r, err.Error())
  1652. return
  1653. }
  1654. s.renderMessagePage(w, r, "Data restored", "", http.StatusOK, nil, "Your backup was successfully restored")
  1655. }
  1656. func (s *httpdServer) handleGetWebAdmins(w http.ResponseWriter, r *http.Request) {
  1657. r.Body = http.MaxBytesReader(w, r.Body, maxRequestSize)
  1658. limit := defaultQueryLimit
  1659. if _, ok := r.URL.Query()["qlimit"]; ok {
  1660. var err error
  1661. limit, err = strconv.Atoi(r.URL.Query().Get("qlimit"))
  1662. if err != nil {
  1663. limit = defaultQueryLimit
  1664. }
  1665. }
  1666. admins := make([]dataprovider.Admin, 0, limit)
  1667. for {
  1668. a, err := dataprovider.GetAdmins(limit, len(admins), dataprovider.OrderASC)
  1669. if err != nil {
  1670. s.renderInternalServerErrorPage(w, r, err)
  1671. return
  1672. }
  1673. admins = append(admins, a...)
  1674. if len(a) < limit {
  1675. break
  1676. }
  1677. }
  1678. data := adminsPage{
  1679. basePage: s.getBasePageData(pageAdminsTitle, webAdminsPath, r),
  1680. Admins: admins,
  1681. }
  1682. renderAdminTemplate(w, templateAdmins, data)
  1683. }
  1684. func (s *httpdServer) handleWebAdminSetupGet(w http.ResponseWriter, r *http.Request) {
  1685. r.Body = http.MaxBytesReader(w, r.Body, maxLoginBodySize)
  1686. if dataprovider.HasAdmin() {
  1687. http.Redirect(w, r, webAdminLoginPath, http.StatusFound)
  1688. return
  1689. }
  1690. s.renderAdminSetupPage(w, r, "", "")
  1691. }
  1692. func (s *httpdServer) handleWebAddAdminGet(w http.ResponseWriter, r *http.Request) {
  1693. r.Body = http.MaxBytesReader(w, r.Body, maxRequestSize)
  1694. admin := &dataprovider.Admin{
  1695. Status: 1,
  1696. Permissions: []string{dataprovider.PermAdminAny},
  1697. }
  1698. s.renderAddUpdateAdminPage(w, r, admin, "", true)
  1699. }
  1700. func (s *httpdServer) handleWebUpdateAdminGet(w http.ResponseWriter, r *http.Request) {
  1701. r.Body = http.MaxBytesReader(w, r.Body, maxRequestSize)
  1702. username := getURLParam(r, "username")
  1703. admin, err := dataprovider.AdminExists(username)
  1704. if err == nil {
  1705. s.renderAddUpdateAdminPage(w, r, &admin, "", false)
  1706. } else if _, ok := err.(*util.RecordNotFoundError); ok {
  1707. s.renderNotFoundPage(w, r, err)
  1708. } else {
  1709. s.renderInternalServerErrorPage(w, r, err)
  1710. }
  1711. }
  1712. func (s *httpdServer) handleWebAddAdminPost(w http.ResponseWriter, r *http.Request) {
  1713. r.Body = http.MaxBytesReader(w, r.Body, maxRequestSize)
  1714. claims, err := getTokenClaims(r)
  1715. if err != nil || claims.Username == "" {
  1716. s.renderBadRequestPage(w, r, errors.New("invalid token claims"))
  1717. return
  1718. }
  1719. admin, err := getAdminFromPostFields(r)
  1720. if err != nil {
  1721. s.renderAddUpdateAdminPage(w, r, &admin, err.Error(), true)
  1722. return
  1723. }
  1724. if admin.Password == "" && s.binding.isWebAdminLoginFormDisabled() {
  1725. admin.Password = util.GenerateUniqueID()
  1726. }
  1727. ipAddr := util.GetIPFromRemoteAddress(r.RemoteAddr)
  1728. if err := verifyCSRFToken(r.Form.Get(csrfFormToken), ipAddr); err != nil {
  1729. s.renderForbiddenPage(w, r, err.Error())
  1730. return
  1731. }
  1732. err = dataprovider.AddAdmin(&admin, claims.Username, ipAddr)
  1733. if err != nil {
  1734. s.renderAddUpdateAdminPage(w, r, &admin, err.Error(), true)
  1735. return
  1736. }
  1737. http.Redirect(w, r, webAdminsPath, http.StatusSeeOther)
  1738. }
  1739. func (s *httpdServer) handleWebUpdateAdminPost(w http.ResponseWriter, r *http.Request) {
  1740. r.Body = http.MaxBytesReader(w, r.Body, maxRequestSize)
  1741. username := getURLParam(r, "username")
  1742. admin, err := dataprovider.AdminExists(username)
  1743. if _, ok := err.(*util.RecordNotFoundError); ok {
  1744. s.renderNotFoundPage(w, r, err)
  1745. return
  1746. } else if err != nil {
  1747. s.renderInternalServerErrorPage(w, r, err)
  1748. return
  1749. }
  1750. updatedAdmin, err := getAdminFromPostFields(r)
  1751. if err != nil {
  1752. s.renderAddUpdateAdminPage(w, r, &updatedAdmin, err.Error(), false)
  1753. return
  1754. }
  1755. ipAddr := util.GetIPFromRemoteAddress(r.RemoteAddr)
  1756. if err := verifyCSRFToken(r.Form.Get(csrfFormToken), ipAddr); err != nil {
  1757. s.renderForbiddenPage(w, r, err.Error())
  1758. return
  1759. }
  1760. updatedAdmin.ID = admin.ID
  1761. updatedAdmin.Username = admin.Username
  1762. if updatedAdmin.Password == "" {
  1763. updatedAdmin.Password = admin.Password
  1764. }
  1765. updatedAdmin.Filters.TOTPConfig = admin.Filters.TOTPConfig
  1766. updatedAdmin.Filters.RecoveryCodes = admin.Filters.RecoveryCodes
  1767. claims, err := getTokenClaims(r)
  1768. if err != nil || claims.Username == "" {
  1769. s.renderAddUpdateAdminPage(w, r, &updatedAdmin, "Invalid token claims", false)
  1770. return
  1771. }
  1772. if username == claims.Username {
  1773. if claims.isCriticalPermRemoved(updatedAdmin.Permissions) {
  1774. s.renderAddUpdateAdminPage(w, r, &updatedAdmin, "You cannot remove these permissions to yourself", false)
  1775. return
  1776. }
  1777. if updatedAdmin.Status == 0 {
  1778. s.renderAddUpdateAdminPage(w, r, &updatedAdmin, "You cannot disable yourself", false)
  1779. return
  1780. }
  1781. }
  1782. err = dataprovider.UpdateAdmin(&updatedAdmin, claims.Username, ipAddr)
  1783. if err != nil {
  1784. s.renderAddUpdateAdminPage(w, r, &admin, err.Error(), false)
  1785. return
  1786. }
  1787. http.Redirect(w, r, webAdminsPath, http.StatusSeeOther)
  1788. }
  1789. func (s *httpdServer) handleWebDefenderPage(w http.ResponseWriter, r *http.Request) {
  1790. r.Body = http.MaxBytesReader(w, r.Body, maxRequestSize)
  1791. data := defenderHostsPage{
  1792. basePage: s.getBasePageData(pageDefenderTitle, webDefenderPath, r),
  1793. DefenderHostsURL: webDefenderHostsPath,
  1794. }
  1795. renderAdminTemplate(w, templateDefender, data)
  1796. }
  1797. func (s *httpdServer) handleGetWebUsers(w http.ResponseWriter, r *http.Request) {
  1798. r.Body = http.MaxBytesReader(w, r.Body, maxRequestSize)
  1799. var limit int
  1800. if _, ok := r.URL.Query()["qlimit"]; ok {
  1801. var err error
  1802. limit, err = strconv.Atoi(r.URL.Query().Get("qlimit"))
  1803. if err != nil {
  1804. limit = defaultQueryLimit
  1805. }
  1806. } else {
  1807. limit = defaultQueryLimit
  1808. }
  1809. users := make([]dataprovider.User, 0, limit)
  1810. for {
  1811. u, err := dataprovider.GetUsers(limit, len(users), dataprovider.OrderASC)
  1812. if err != nil {
  1813. s.renderInternalServerErrorPage(w, r, err)
  1814. return
  1815. }
  1816. users = append(users, u...)
  1817. if len(u) < limit {
  1818. break
  1819. }
  1820. }
  1821. data := usersPage{
  1822. basePage: s.getBasePageData(pageUsersTitle, webUsersPath, r),
  1823. Users: users,
  1824. }
  1825. renderAdminTemplate(w, templateUsers, data)
  1826. }
  1827. func (s *httpdServer) handleWebTemplateFolderGet(w http.ResponseWriter, r *http.Request) {
  1828. r.Body = http.MaxBytesReader(w, r.Body, maxRequestSize)
  1829. if r.URL.Query().Get("from") != "" {
  1830. name := r.URL.Query().Get("from")
  1831. folder, err := dataprovider.GetFolderByName(name)
  1832. if err == nil {
  1833. folder.FsConfig.SetEmptySecrets()
  1834. s.renderFolderPage(w, r, folder, folderPageModeTemplate, "")
  1835. } else if _, ok := err.(*util.RecordNotFoundError); ok {
  1836. s.renderNotFoundPage(w, r, err)
  1837. } else {
  1838. s.renderInternalServerErrorPage(w, r, err)
  1839. }
  1840. } else {
  1841. folder := vfs.BaseVirtualFolder{}
  1842. s.renderFolderPage(w, r, folder, folderPageModeTemplate, "")
  1843. }
  1844. }
  1845. func (s *httpdServer) handleWebTemplateFolderPost(w http.ResponseWriter, r *http.Request) {
  1846. r.Body = http.MaxBytesReader(w, r.Body, maxRequestSize)
  1847. claims, err := getTokenClaims(r)
  1848. if err != nil || claims.Username == "" {
  1849. s.renderBadRequestPage(w, r, errors.New("invalid token claims"))
  1850. return
  1851. }
  1852. templateFolder := vfs.BaseVirtualFolder{}
  1853. err = r.ParseMultipartForm(maxRequestSize)
  1854. if err != nil {
  1855. s.renderMessagePage(w, r, "Error parsing folders fields", "", http.StatusBadRequest, err, "")
  1856. return
  1857. }
  1858. defer r.MultipartForm.RemoveAll() //nolint:errcheck
  1859. ipAddr := util.GetIPFromRemoteAddress(r.RemoteAddr)
  1860. if err := verifyCSRFToken(r.Form.Get(csrfFormToken), ipAddr); err != nil {
  1861. s.renderForbiddenPage(w, r, err.Error())
  1862. return
  1863. }
  1864. templateFolder.MappedPath = r.Form.Get("mapped_path")
  1865. templateFolder.Description = r.Form.Get("description")
  1866. fsConfig, err := getFsConfigFromPostFields(r)
  1867. if err != nil {
  1868. s.renderMessagePage(w, r, "Error parsing folders fields", "", http.StatusBadRequest, err, "")
  1869. return
  1870. }
  1871. templateFolder.FsConfig = fsConfig
  1872. var dump dataprovider.BackupData
  1873. dump.Version = dataprovider.DumpVersion
  1874. foldersFields := getFoldersForTemplate(r)
  1875. for _, tmpl := range foldersFields {
  1876. f := getFolderFromTemplate(templateFolder, tmpl)
  1877. if err := dataprovider.ValidateFolder(&f); err != nil {
  1878. s.renderMessagePage(w, r, "Folder validation error", fmt.Sprintf("Error validating folder %#v", f.Name),
  1879. http.StatusBadRequest, err, "")
  1880. return
  1881. }
  1882. dump.Folders = append(dump.Folders, f)
  1883. }
  1884. if len(dump.Folders) == 0 {
  1885. s.renderMessagePage(w, r, "No folders defined", "No valid folders defined, unable to complete the requested action",
  1886. http.StatusBadRequest, nil, "")
  1887. return
  1888. }
  1889. if r.Form.Get("form_action") == "export_from_template" {
  1890. w.Header().Set("Content-Disposition", fmt.Sprintf("attachment; filename=\"sftpgo-%v-folders-from-template.json\"",
  1891. len(dump.Folders)))
  1892. render.JSON(w, r, dump)
  1893. return
  1894. }
  1895. if err = RestoreFolders(dump.Folders, "", 1, 0, claims.Username, ipAddr); err != nil {
  1896. s.renderMessagePage(w, r, "Unable to save folders", "Cannot save the defined folders:",
  1897. getRespStatus(err), err, "")
  1898. return
  1899. }
  1900. http.Redirect(w, r, webFoldersPath, http.StatusSeeOther)
  1901. }
  1902. func (s *httpdServer) handleWebTemplateUserGet(w http.ResponseWriter, r *http.Request) {
  1903. r.Body = http.MaxBytesReader(w, r.Body, maxRequestSize)
  1904. if r.URL.Query().Get("from") != "" {
  1905. username := r.URL.Query().Get("from")
  1906. user, err := dataprovider.UserExists(username)
  1907. if err == nil {
  1908. user.SetEmptySecrets()
  1909. user.PublicKeys = nil
  1910. user.Email = ""
  1911. user.Description = ""
  1912. s.renderUserPage(w, r, &user, userPageModeTemplate, "")
  1913. } else if _, ok := err.(*util.RecordNotFoundError); ok {
  1914. s.renderNotFoundPage(w, r, err)
  1915. } else {
  1916. s.renderInternalServerErrorPage(w, r, err)
  1917. }
  1918. } else {
  1919. user := dataprovider.User{BaseUser: sdk.BaseUser{
  1920. Status: 1,
  1921. Permissions: map[string][]string{
  1922. "/": {dataprovider.PermAny},
  1923. },
  1924. }}
  1925. s.renderUserPage(w, r, &user, userPageModeTemplate, "")
  1926. }
  1927. }
  1928. func (s *httpdServer) handleWebTemplateUserPost(w http.ResponseWriter, r *http.Request) {
  1929. r.Body = http.MaxBytesReader(w, r.Body, maxRequestSize)
  1930. claims, err := getTokenClaims(r)
  1931. if err != nil || claims.Username == "" {
  1932. s.renderBadRequestPage(w, r, errors.New("invalid token claims"))
  1933. return
  1934. }
  1935. templateUser, err := getUserFromPostFields(r)
  1936. if err != nil {
  1937. s.renderMessagePage(w, r, "Error parsing user fields", "", http.StatusBadRequest, err, "")
  1938. return
  1939. }
  1940. ipAddr := util.GetIPFromRemoteAddress(r.RemoteAddr)
  1941. if err := verifyCSRFToken(r.Form.Get(csrfFormToken), ipAddr); err != nil {
  1942. s.renderForbiddenPage(w, r, err.Error())
  1943. return
  1944. }
  1945. var dump dataprovider.BackupData
  1946. dump.Version = dataprovider.DumpVersion
  1947. userTmplFields := getUsersForTemplate(r)
  1948. for _, tmpl := range userTmplFields {
  1949. u := getUserFromTemplate(templateUser, tmpl)
  1950. if err := dataprovider.ValidateUser(&u); err != nil {
  1951. s.renderMessagePage(w, r, "User validation error", fmt.Sprintf("Error validating user %#v", u.Username),
  1952. http.StatusBadRequest, err, "")
  1953. return
  1954. }
  1955. dump.Users = append(dump.Users, u)
  1956. for _, folder := range u.VirtualFolders {
  1957. if !dump.HasFolder(folder.Name) {
  1958. dump.Folders = append(dump.Folders, folder.BaseVirtualFolder)
  1959. }
  1960. }
  1961. }
  1962. if len(dump.Users) == 0 {
  1963. s.renderMessagePage(w, r, "No users defined", "No valid users defined, unable to complete the requested action",
  1964. http.StatusBadRequest, nil, "")
  1965. return
  1966. }
  1967. if r.Form.Get("form_action") == "export_from_template" {
  1968. w.Header().Set("Content-Disposition", fmt.Sprintf("attachment; filename=\"sftpgo-%v-users-from-template.json\"",
  1969. len(dump.Users)))
  1970. render.JSON(w, r, dump)
  1971. return
  1972. }
  1973. if err = RestoreUsers(dump.Users, "", 1, 0, claims.Username, ipAddr); err != nil {
  1974. s.renderMessagePage(w, r, "Unable to save users", "Cannot save the defined users:",
  1975. getRespStatus(err), err, "")
  1976. return
  1977. }
  1978. http.Redirect(w, r, webUsersPath, http.StatusSeeOther)
  1979. }
  1980. func (s *httpdServer) handleWebAddUserGet(w http.ResponseWriter, r *http.Request) {
  1981. r.Body = http.MaxBytesReader(w, r.Body, maxRequestSize)
  1982. user := dataprovider.User{BaseUser: sdk.BaseUser{
  1983. Status: 1,
  1984. Permissions: map[string][]string{
  1985. "/": {dataprovider.PermAny},
  1986. },
  1987. }}
  1988. s.renderUserPage(w, r, &user, userPageModeAdd, "")
  1989. }
  1990. func (s *httpdServer) handleWebUpdateUserGet(w http.ResponseWriter, r *http.Request) {
  1991. r.Body = http.MaxBytesReader(w, r.Body, maxRequestSize)
  1992. username := getURLParam(r, "username")
  1993. user, err := dataprovider.UserExists(username)
  1994. if err == nil {
  1995. s.renderUserPage(w, r, &user, userPageModeUpdate, "")
  1996. } else if _, ok := err.(*util.RecordNotFoundError); ok {
  1997. s.renderNotFoundPage(w, r, err)
  1998. } else {
  1999. s.renderInternalServerErrorPage(w, r, err)
  2000. }
  2001. }
  2002. func (s *httpdServer) handleWebAddUserPost(w http.ResponseWriter, r *http.Request) {
  2003. r.Body = http.MaxBytesReader(w, r.Body, maxRequestSize)
  2004. claims, err := getTokenClaims(r)
  2005. if err != nil || claims.Username == "" {
  2006. s.renderBadRequestPage(w, r, errors.New("invalid token claims"))
  2007. return
  2008. }
  2009. user, err := getUserFromPostFields(r)
  2010. if err != nil {
  2011. s.renderUserPage(w, r, &user, userPageModeAdd, err.Error())
  2012. return
  2013. }
  2014. ipAddr := util.GetIPFromRemoteAddress(r.RemoteAddr)
  2015. if err := verifyCSRFToken(r.Form.Get(csrfFormToken), ipAddr); err != nil {
  2016. s.renderForbiddenPage(w, r, err.Error())
  2017. return
  2018. }
  2019. user = getUserFromTemplate(user, userTemplateFields{
  2020. Username: user.Username,
  2021. Password: user.Password,
  2022. PublicKeys: user.PublicKeys,
  2023. })
  2024. err = dataprovider.AddUser(&user, claims.Username, ipAddr)
  2025. if err != nil {
  2026. s.renderUserPage(w, r, &user, userPageModeAdd, err.Error())
  2027. return
  2028. }
  2029. http.Redirect(w, r, webUsersPath, http.StatusSeeOther)
  2030. }
  2031. func (s *httpdServer) handleWebUpdateUserPost(w http.ResponseWriter, r *http.Request) {
  2032. r.Body = http.MaxBytesReader(w, r.Body, maxRequestSize)
  2033. claims, err := getTokenClaims(r)
  2034. if err != nil || claims.Username == "" {
  2035. s.renderBadRequestPage(w, r, errors.New("invalid token claims"))
  2036. return
  2037. }
  2038. username := getURLParam(r, "username")
  2039. user, err := dataprovider.UserExists(username)
  2040. if _, ok := err.(*util.RecordNotFoundError); ok {
  2041. s.renderNotFoundPage(w, r, err)
  2042. return
  2043. } else if err != nil {
  2044. s.renderInternalServerErrorPage(w, r, err)
  2045. return
  2046. }
  2047. updatedUser, err := getUserFromPostFields(r)
  2048. if err != nil {
  2049. s.renderUserPage(w, r, &user, userPageModeUpdate, err.Error())
  2050. return
  2051. }
  2052. ipAddr := util.GetIPFromRemoteAddress(r.RemoteAddr)
  2053. if err := verifyCSRFToken(r.Form.Get(csrfFormToken), ipAddr); err != nil {
  2054. s.renderForbiddenPage(w, r, err.Error())
  2055. return
  2056. }
  2057. updatedUser.ID = user.ID
  2058. updatedUser.Username = user.Username
  2059. updatedUser.Filters.RecoveryCodes = user.Filters.RecoveryCodes
  2060. updatedUser.Filters.TOTPConfig = user.Filters.TOTPConfig
  2061. updatedUser.SetEmptySecretsIfNil()
  2062. if updatedUser.Password == redactedSecret {
  2063. updatedUser.Password = user.Password
  2064. }
  2065. updateEncryptedSecrets(&updatedUser.FsConfig, user.FsConfig.S3Config.AccessSecret, user.FsConfig.AzBlobConfig.AccountKey,
  2066. user.FsConfig.AzBlobConfig.SASURL, user.FsConfig.GCSConfig.Credentials, user.FsConfig.CryptConfig.Passphrase,
  2067. user.FsConfig.SFTPConfig.Password, user.FsConfig.SFTPConfig.PrivateKey, user.FsConfig.SFTPConfig.KeyPassphrase)
  2068. updatedUser = getUserFromTemplate(updatedUser, userTemplateFields{
  2069. Username: updatedUser.Username,
  2070. Password: updatedUser.Password,
  2071. PublicKeys: updatedUser.PublicKeys,
  2072. })
  2073. err = dataprovider.UpdateUser(&updatedUser, claims.Username, ipAddr)
  2074. if err != nil {
  2075. s.renderUserPage(w, r, &updatedUser, userPageModeUpdate, err.Error())
  2076. return
  2077. }
  2078. if r.Form.Get("disconnect") != "" {
  2079. disconnectUser(user.Username)
  2080. }
  2081. http.Redirect(w, r, webUsersPath, http.StatusSeeOther)
  2082. }
  2083. func (s *httpdServer) handleWebGetStatus(w http.ResponseWriter, r *http.Request) {
  2084. r.Body = http.MaxBytesReader(w, r.Body, maxRequestSize)
  2085. data := statusPage{
  2086. basePage: s.getBasePageData(pageStatusTitle, webStatusPath, r),
  2087. Status: getServicesStatus(),
  2088. }
  2089. renderAdminTemplate(w, templateStatus, data)
  2090. }
  2091. func (s *httpdServer) handleWebGetConnections(w http.ResponseWriter, r *http.Request) {
  2092. r.Body = http.MaxBytesReader(w, r.Body, maxRequestSize)
  2093. connectionStats := common.Connections.GetStats()
  2094. data := connectionsPage{
  2095. basePage: s.getBasePageData(pageConnectionsTitle, webConnectionsPath, r),
  2096. Connections: connectionStats,
  2097. }
  2098. renderAdminTemplate(w, templateConnections, data)
  2099. }
  2100. func (s *httpdServer) handleWebAddFolderGet(w http.ResponseWriter, r *http.Request) {
  2101. r.Body = http.MaxBytesReader(w, r.Body, maxRequestSize)
  2102. s.renderFolderPage(w, r, vfs.BaseVirtualFolder{}, folderPageModeAdd, "")
  2103. }
  2104. func (s *httpdServer) handleWebAddFolderPost(w http.ResponseWriter, r *http.Request) {
  2105. r.Body = http.MaxBytesReader(w, r.Body, maxRequestSize)
  2106. claims, err := getTokenClaims(r)
  2107. if err != nil || claims.Username == "" {
  2108. s.renderBadRequestPage(w, r, errors.New("invalid token claims"))
  2109. return
  2110. }
  2111. folder := vfs.BaseVirtualFolder{}
  2112. err = r.ParseMultipartForm(maxRequestSize)
  2113. if err != nil {
  2114. s.renderFolderPage(w, r, folder, folderPageModeAdd, err.Error())
  2115. return
  2116. }
  2117. defer r.MultipartForm.RemoveAll() //nolint:errcheck
  2118. ipAddr := util.GetIPFromRemoteAddress(r.RemoteAddr)
  2119. if err := verifyCSRFToken(r.Form.Get(csrfFormToken), ipAddr); err != nil {
  2120. s.renderForbiddenPage(w, r, err.Error())
  2121. return
  2122. }
  2123. folder.MappedPath = r.Form.Get("mapped_path")
  2124. folder.Name = r.Form.Get("name")
  2125. folder.Description = r.Form.Get("description")
  2126. fsConfig, err := getFsConfigFromPostFields(r)
  2127. if err != nil {
  2128. s.renderFolderPage(w, r, folder, folderPageModeAdd, err.Error())
  2129. return
  2130. }
  2131. folder.FsConfig = fsConfig
  2132. folder = getFolderFromTemplate(folder, folder.Name)
  2133. err = dataprovider.AddFolder(&folder, claims.Username, ipAddr)
  2134. if err == nil {
  2135. http.Redirect(w, r, webFoldersPath, http.StatusSeeOther)
  2136. } else {
  2137. s.renderFolderPage(w, r, folder, folderPageModeAdd, err.Error())
  2138. }
  2139. }
  2140. func (s *httpdServer) handleWebUpdateFolderGet(w http.ResponseWriter, r *http.Request) {
  2141. r.Body = http.MaxBytesReader(w, r.Body, maxRequestSize)
  2142. name := getURLParam(r, "name")
  2143. folder, err := dataprovider.GetFolderByName(name)
  2144. if err == nil {
  2145. s.renderFolderPage(w, r, folder, folderPageModeUpdate, "")
  2146. } else if _, ok := err.(*util.RecordNotFoundError); ok {
  2147. s.renderNotFoundPage(w, r, err)
  2148. } else {
  2149. s.renderInternalServerErrorPage(w, r, err)
  2150. }
  2151. }
  2152. func (s *httpdServer) handleWebUpdateFolderPost(w http.ResponseWriter, r *http.Request) {
  2153. r.Body = http.MaxBytesReader(w, r.Body, maxRequestSize)
  2154. claims, err := getTokenClaims(r)
  2155. if err != nil || claims.Username == "" {
  2156. s.renderBadRequestPage(w, r, errors.New("invalid token claims"))
  2157. return
  2158. }
  2159. name := getURLParam(r, "name")
  2160. folder, err := dataprovider.GetFolderByName(name)
  2161. if _, ok := err.(*util.RecordNotFoundError); ok {
  2162. s.renderNotFoundPage(w, r, err)
  2163. return
  2164. } else if err != nil {
  2165. s.renderInternalServerErrorPage(w, r, err)
  2166. return
  2167. }
  2168. err = r.ParseMultipartForm(maxRequestSize)
  2169. if err != nil {
  2170. s.renderFolderPage(w, r, folder, folderPageModeUpdate, err.Error())
  2171. return
  2172. }
  2173. defer r.MultipartForm.RemoveAll() //nolint:errcheck
  2174. ipAddr := util.GetIPFromRemoteAddress(r.RemoteAddr)
  2175. if err := verifyCSRFToken(r.Form.Get(csrfFormToken), ipAddr); err != nil {
  2176. s.renderForbiddenPage(w, r, err.Error())
  2177. return
  2178. }
  2179. fsConfig, err := getFsConfigFromPostFields(r)
  2180. if err != nil {
  2181. s.renderFolderPage(w, r, folder, folderPageModeUpdate, err.Error())
  2182. return
  2183. }
  2184. updatedFolder := vfs.BaseVirtualFolder{
  2185. MappedPath: r.Form.Get("mapped_path"),
  2186. Description: r.Form.Get("description"),
  2187. }
  2188. updatedFolder.ID = folder.ID
  2189. updatedFolder.Name = folder.Name
  2190. updatedFolder.FsConfig = fsConfig
  2191. updatedFolder.FsConfig.SetEmptySecretsIfNil()
  2192. updateEncryptedSecrets(&updatedFolder.FsConfig, folder.FsConfig.S3Config.AccessSecret, folder.FsConfig.AzBlobConfig.AccountKey,
  2193. folder.FsConfig.AzBlobConfig.SASURL, folder.FsConfig.GCSConfig.Credentials, folder.FsConfig.CryptConfig.Passphrase,
  2194. folder.FsConfig.SFTPConfig.Password, folder.FsConfig.SFTPConfig.PrivateKey, folder.FsConfig.SFTPConfig.KeyPassphrase)
  2195. updatedFolder = getFolderFromTemplate(updatedFolder, updatedFolder.Name)
  2196. err = dataprovider.UpdateFolder(&updatedFolder, folder.Users, folder.Groups, claims.Username, ipAddr)
  2197. if err != nil {
  2198. s.renderFolderPage(w, r, updatedFolder, folderPageModeUpdate, err.Error())
  2199. return
  2200. }
  2201. http.Redirect(w, r, webFoldersPath, http.StatusSeeOther)
  2202. }
  2203. func (s *httpdServer) getWebVirtualFolders(w http.ResponseWriter, r *http.Request, limit int, minimal bool) ([]vfs.BaseVirtualFolder, error) {
  2204. folders := make([]vfs.BaseVirtualFolder, 0, limit)
  2205. for {
  2206. f, err := dataprovider.GetFolders(limit, len(folders), dataprovider.OrderASC, minimal)
  2207. if err != nil {
  2208. s.renderInternalServerErrorPage(w, r, err)
  2209. return folders, err
  2210. }
  2211. folders = append(folders, f...)
  2212. if len(f) < limit {
  2213. break
  2214. }
  2215. }
  2216. return folders, nil
  2217. }
  2218. func (s *httpdServer) handleWebGetFolders(w http.ResponseWriter, r *http.Request) {
  2219. r.Body = http.MaxBytesReader(w, r.Body, maxRequestSize)
  2220. limit := defaultQueryLimit
  2221. if _, ok := r.URL.Query()["qlimit"]; ok {
  2222. var err error
  2223. limit, err = strconv.Atoi(r.URL.Query().Get("qlimit"))
  2224. if err != nil {
  2225. limit = defaultQueryLimit
  2226. }
  2227. }
  2228. folders, err := s.getWebVirtualFolders(w, r, limit, false)
  2229. if err != nil {
  2230. return
  2231. }
  2232. data := foldersPage{
  2233. basePage: s.getBasePageData(pageFoldersTitle, webFoldersPath, r),
  2234. Folders: folders,
  2235. }
  2236. renderAdminTemplate(w, templateFolders, data)
  2237. }
  2238. func (s *httpdServer) getWebGroups(w http.ResponseWriter, r *http.Request, limit int, minimal bool) ([]dataprovider.Group, error) {
  2239. groups := make([]dataprovider.Group, 0, limit)
  2240. for {
  2241. f, err := dataprovider.GetGroups(limit, len(groups), dataprovider.OrderASC, minimal)
  2242. if err != nil {
  2243. s.renderInternalServerErrorPage(w, r, err)
  2244. return groups, err
  2245. }
  2246. groups = append(groups, f...)
  2247. if len(f) < limit {
  2248. break
  2249. }
  2250. }
  2251. return groups, nil
  2252. }
  2253. func (s *httpdServer) handleWebGetGroups(w http.ResponseWriter, r *http.Request) {
  2254. r.Body = http.MaxBytesReader(w, r.Body, maxRequestSize)
  2255. limit := defaultQueryLimit
  2256. if _, ok := r.URL.Query()["qlimit"]; ok {
  2257. var err error
  2258. limit, err = strconv.Atoi(r.URL.Query().Get("qlimit"))
  2259. if err != nil {
  2260. limit = defaultQueryLimit
  2261. }
  2262. }
  2263. groups, err := s.getWebGroups(w, r, limit, false)
  2264. if err != nil {
  2265. return
  2266. }
  2267. data := groupsPage{
  2268. basePage: s.getBasePageData(pageGroupsTitle, webGroupsPath, r),
  2269. Groups: groups,
  2270. }
  2271. renderAdminTemplate(w, templateGroups, data)
  2272. }
  2273. func (s *httpdServer) handleWebAddGroupGet(w http.ResponseWriter, r *http.Request) {
  2274. r.Body = http.MaxBytesReader(w, r.Body, maxRequestSize)
  2275. s.renderGroupPage(w, r, dataprovider.Group{}, groupPageModeAdd, "")
  2276. }
  2277. func (s *httpdServer) handleWebAddGroupPost(w http.ResponseWriter, r *http.Request) {
  2278. r.Body = http.MaxBytesReader(w, r.Body, maxRequestSize)
  2279. claims, err := getTokenClaims(r)
  2280. if err != nil || claims.Username == "" {
  2281. s.renderBadRequestPage(w, r, errors.New("invalid token claims"))
  2282. return
  2283. }
  2284. group, err := getGroupFromPostFields(r)
  2285. if err != nil {
  2286. s.renderGroupPage(w, r, group, groupPageModeAdd, err.Error())
  2287. return
  2288. }
  2289. ipAddr := util.GetIPFromRemoteAddress(r.RemoteAddr)
  2290. if err := verifyCSRFToken(r.Form.Get(csrfFormToken), ipAddr); err != nil {
  2291. s.renderForbiddenPage(w, r, err.Error())
  2292. return
  2293. }
  2294. err = dataprovider.AddGroup(&group, claims.Username, ipAddr)
  2295. if err != nil {
  2296. s.renderGroupPage(w, r, group, groupPageModeAdd, err.Error())
  2297. return
  2298. }
  2299. http.Redirect(w, r, webGroupsPath, http.StatusSeeOther)
  2300. }
  2301. func (s *httpdServer) handleWebUpdateGroupGet(w http.ResponseWriter, r *http.Request) {
  2302. r.Body = http.MaxBytesReader(w, r.Body, maxRequestSize)
  2303. name := getURLParam(r, "name")
  2304. group, err := dataprovider.GroupExists(name)
  2305. if err == nil {
  2306. s.renderGroupPage(w, r, group, groupPageModeUpdate, "")
  2307. } else if _, ok := err.(*util.RecordNotFoundError); ok {
  2308. s.renderNotFoundPage(w, r, err)
  2309. } else {
  2310. s.renderInternalServerErrorPage(w, r, err)
  2311. }
  2312. }
  2313. func (s *httpdServer) handleWebUpdateGroupPost(w http.ResponseWriter, r *http.Request) {
  2314. r.Body = http.MaxBytesReader(w, r.Body, maxRequestSize)
  2315. claims, err := getTokenClaims(r)
  2316. if err != nil || claims.Username == "" {
  2317. s.renderBadRequestPage(w, r, errors.New("invalid token claims"))
  2318. return
  2319. }
  2320. name := getURLParam(r, "name")
  2321. group, err := dataprovider.GroupExists(name)
  2322. if _, ok := err.(*util.RecordNotFoundError); ok {
  2323. s.renderNotFoundPage(w, r, err)
  2324. return
  2325. } else if err != nil {
  2326. s.renderInternalServerErrorPage(w, r, err)
  2327. return
  2328. }
  2329. updatedGroup, err := getGroupFromPostFields(r)
  2330. if err != nil {
  2331. s.renderGroupPage(w, r, group, groupPageModeUpdate, err.Error())
  2332. return
  2333. }
  2334. ipAddr := util.GetIPFromRemoteAddress(r.RemoteAddr)
  2335. if err := verifyCSRFToken(r.Form.Get(csrfFormToken), ipAddr); err != nil {
  2336. s.renderForbiddenPage(w, r, err.Error())
  2337. return
  2338. }
  2339. updatedGroup.ID = group.ID
  2340. updatedGroup.Name = group.Name
  2341. updatedGroup.SetEmptySecretsIfNil()
  2342. updateEncryptedSecrets(&updatedGroup.UserSettings.FsConfig, group.UserSettings.FsConfig.S3Config.AccessSecret,
  2343. group.UserSettings.FsConfig.AzBlobConfig.AccountKey, group.UserSettings.FsConfig.AzBlobConfig.SASURL,
  2344. group.UserSettings.FsConfig.GCSConfig.Credentials, group.UserSettings.FsConfig.CryptConfig.Passphrase,
  2345. group.UserSettings.FsConfig.SFTPConfig.Password, group.UserSettings.FsConfig.SFTPConfig.PrivateKey,
  2346. group.UserSettings.FsConfig.SFTPConfig.KeyPassphrase)
  2347. err = dataprovider.UpdateGroup(&updatedGroup, group.Users, claims.Username, ipAddr)
  2348. if err != nil {
  2349. s.renderGroupPage(w, r, updatedGroup, groupPageModeUpdate, err.Error())
  2350. return
  2351. }
  2352. http.Redirect(w, r, webGroupsPath, http.StatusSeeOther)
  2353. }