webadmin.go 82 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532
  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. switch user.FsConfig.Provider {
  1324. case sdk.CryptedFilesystemProvider:
  1325. user.FsConfig.CryptConfig = getCryptFsFromTemplate(user.FsConfig.CryptConfig, replacements)
  1326. case sdk.S3FilesystemProvider:
  1327. user.FsConfig.S3Config = getS3FsFromTemplate(user.FsConfig.S3Config, replacements)
  1328. case sdk.GCSFilesystemProvider:
  1329. user.FsConfig.GCSConfig = getGCSFsFromTemplate(user.FsConfig.GCSConfig, replacements)
  1330. case sdk.AzureBlobFilesystemProvider:
  1331. user.FsConfig.AzBlobConfig = getAzBlobFsFromTemplate(user.FsConfig.AzBlobConfig, replacements)
  1332. case sdk.SFTPFilesystemProvider:
  1333. user.FsConfig.SFTPConfig = getSFTPFsFromTemplate(user.FsConfig.SFTPConfig, replacements)
  1334. }
  1335. return user
  1336. }
  1337. func getTransferLimits(r *http.Request) (int64, int64, int64, error) {
  1338. dataTransferUL, err := strconv.ParseInt(r.Form.Get("upload_data_transfer"), 10, 64)
  1339. if err != nil {
  1340. return 0, 0, 0, fmt.Errorf("invalid upload data transfer: %w", err)
  1341. }
  1342. dataTransferDL, err := strconv.ParseInt(r.Form.Get("download_data_transfer"), 10, 64)
  1343. if err != nil {
  1344. return 0, 0, 0, fmt.Errorf("invalid download data transfer: %w", err)
  1345. }
  1346. dataTransferTotal, err := strconv.ParseInt(r.Form.Get("total_data_transfer"), 10, 64)
  1347. if err != nil {
  1348. return 0, 0, 0, fmt.Errorf("invalid total data transfer: %w", err)
  1349. }
  1350. return dataTransferUL, dataTransferDL, dataTransferTotal, nil
  1351. }
  1352. func getQuotaLimits(r *http.Request) (int64, int, error) {
  1353. quotaSize, err := strconv.ParseInt(r.Form.Get("quota_size"), 10, 64)
  1354. if err != nil {
  1355. return 0, 0, fmt.Errorf("invalid quota size: %w", err)
  1356. }
  1357. quotaFiles, err := strconv.Atoi(r.Form.Get("quota_files"))
  1358. if err != nil {
  1359. return 0, 0, fmt.Errorf("invalid quota files: %w", err)
  1360. }
  1361. return quotaSize, quotaFiles, nil
  1362. }
  1363. func getUserFromPostFields(r *http.Request) (dataprovider.User, error) {
  1364. user := dataprovider.User{}
  1365. err := r.ParseMultipartForm(maxRequestSize)
  1366. if err != nil {
  1367. return user, err
  1368. }
  1369. defer r.MultipartForm.RemoveAll() //nolint:errcheck
  1370. uid, err := strconv.Atoi(r.Form.Get("uid"))
  1371. if err != nil {
  1372. return user, fmt.Errorf("invalid uid: %w", err)
  1373. }
  1374. gid, err := strconv.Atoi(r.Form.Get("gid"))
  1375. if err != nil {
  1376. return user, fmt.Errorf("invalid uid: %w", err)
  1377. }
  1378. maxSessions, err := strconv.Atoi(r.Form.Get("max_sessions"))
  1379. if err != nil {
  1380. return user, fmt.Errorf("invalid max sessions: %w", err)
  1381. }
  1382. quotaSize, quotaFiles, err := getQuotaLimits(r)
  1383. if err != nil {
  1384. return user, err
  1385. }
  1386. bandwidthUL, err := strconv.ParseInt(r.Form.Get("upload_bandwidth"), 10, 64)
  1387. if err != nil {
  1388. return user, fmt.Errorf("invalid upload bandwidth: %w", err)
  1389. }
  1390. bandwidthDL, err := strconv.ParseInt(r.Form.Get("download_bandwidth"), 10, 64)
  1391. if err != nil {
  1392. return user, fmt.Errorf("invalid download bandwidth: %w", err)
  1393. }
  1394. dataTransferUL, dataTransferDL, dataTransferTotal, err := getTransferLimits(r)
  1395. if err != nil {
  1396. return user, err
  1397. }
  1398. status, err := strconv.Atoi(r.Form.Get("status"))
  1399. if err != nil {
  1400. return user, fmt.Errorf("invalid status: %w", err)
  1401. }
  1402. expirationDateMillis := int64(0)
  1403. expirationDateString := r.Form.Get("expiration_date")
  1404. if strings.TrimSpace(expirationDateString) != "" {
  1405. expirationDate, err := time.Parse(webDateTimeFormat, expirationDateString)
  1406. if err != nil {
  1407. return user, err
  1408. }
  1409. expirationDateMillis = util.GetTimeAsMsSinceEpoch(expirationDate)
  1410. }
  1411. fsConfig, err := getFsConfigFromPostFields(r)
  1412. if err != nil {
  1413. return user, err
  1414. }
  1415. filters, err := getFiltersFromUserPostFields(r)
  1416. if err != nil {
  1417. return user, err
  1418. }
  1419. user = dataprovider.User{
  1420. BaseUser: sdk.BaseUser{
  1421. Username: r.Form.Get("username"),
  1422. Email: r.Form.Get("email"),
  1423. Password: r.Form.Get("password"),
  1424. PublicKeys: r.Form["public_keys"],
  1425. HomeDir: r.Form.Get("home_dir"),
  1426. UID: uid,
  1427. GID: gid,
  1428. Permissions: getUserPermissionsFromPostFields(r),
  1429. MaxSessions: maxSessions,
  1430. QuotaSize: quotaSize,
  1431. QuotaFiles: quotaFiles,
  1432. UploadBandwidth: bandwidthUL,
  1433. DownloadBandwidth: bandwidthDL,
  1434. UploadDataTransfer: dataTransferUL,
  1435. DownloadDataTransfer: dataTransferDL,
  1436. TotalDataTransfer: dataTransferTotal,
  1437. Status: status,
  1438. ExpirationDate: expirationDateMillis,
  1439. AdditionalInfo: r.Form.Get("additional_info"),
  1440. Description: r.Form.Get("description"),
  1441. },
  1442. Filters: dataprovider.UserFilters{
  1443. BaseUserFilters: filters,
  1444. },
  1445. VirtualFolders: getVirtualFoldersFromPostFields(r),
  1446. FsConfig: fsConfig,
  1447. Groups: getGroupsFromUserPostFields(r),
  1448. }
  1449. return user, nil
  1450. }
  1451. func getGroupFromPostFields(r *http.Request) (dataprovider.Group, error) {
  1452. group := dataprovider.Group{}
  1453. err := r.ParseMultipartForm(maxRequestSize)
  1454. if err != nil {
  1455. return group, err
  1456. }
  1457. defer r.MultipartForm.RemoveAll() //nolint:errcheck
  1458. maxSessions, err := strconv.Atoi(r.Form.Get("max_sessions"))
  1459. if err != nil {
  1460. return group, fmt.Errorf("invalid max sessions: %w", err)
  1461. }
  1462. quotaSize, quotaFiles, err := getQuotaLimits(r)
  1463. if err != nil {
  1464. return group, err
  1465. }
  1466. bandwidthUL, err := strconv.ParseInt(r.Form.Get("upload_bandwidth"), 10, 64)
  1467. if err != nil {
  1468. return group, fmt.Errorf("invalid upload bandwidth: %w", err)
  1469. }
  1470. bandwidthDL, err := strconv.ParseInt(r.Form.Get("download_bandwidth"), 10, 64)
  1471. if err != nil {
  1472. return group, fmt.Errorf("invalid download bandwidth: %w", err)
  1473. }
  1474. dataTransferUL, dataTransferDL, dataTransferTotal, err := getTransferLimits(r)
  1475. if err != nil {
  1476. return group, err
  1477. }
  1478. fsConfig, err := getFsConfigFromPostFields(r)
  1479. if err != nil {
  1480. return group, err
  1481. }
  1482. filters, err := getFiltersFromUserPostFields(r)
  1483. if err != nil {
  1484. return group, err
  1485. }
  1486. group = dataprovider.Group{
  1487. BaseGroup: sdk.BaseGroup{
  1488. Name: r.Form.Get("name"),
  1489. Description: r.Form.Get("description"),
  1490. },
  1491. UserSettings: dataprovider.GroupUserSettings{
  1492. BaseGroupUserSettings: sdk.BaseGroupUserSettings{
  1493. HomeDir: r.Form.Get("home_dir"),
  1494. MaxSessions: maxSessions,
  1495. QuotaSize: quotaSize,
  1496. QuotaFiles: quotaFiles,
  1497. Permissions: getSubDirPermissionsFromPostFields(r),
  1498. UploadBandwidth: bandwidthUL,
  1499. DownloadBandwidth: bandwidthDL,
  1500. UploadDataTransfer: dataTransferUL,
  1501. DownloadDataTransfer: dataTransferDL,
  1502. TotalDataTransfer: dataTransferTotal,
  1503. Filters: filters,
  1504. },
  1505. FsConfig: fsConfig,
  1506. },
  1507. VirtualFolders: getVirtualFoldersFromPostFields(r),
  1508. }
  1509. return group, nil
  1510. }
  1511. func (s *httpdServer) handleWebAdminForgotPwd(w http.ResponseWriter, r *http.Request) {
  1512. r.Body = http.MaxBytesReader(w, r.Body, maxRequestSize)
  1513. if !smtp.IsEnabled() {
  1514. s.renderNotFoundPage(w, r, errors.New("this page does not exist"))
  1515. return
  1516. }
  1517. s.renderForgotPwdPage(w, "", util.GetIPFromRemoteAddress(r.RemoteAddr))
  1518. }
  1519. func (s *httpdServer) handleWebAdminForgotPwdPost(w http.ResponseWriter, r *http.Request) {
  1520. r.Body = http.MaxBytesReader(w, r.Body, maxRequestSize)
  1521. ipAddr := util.GetIPFromRemoteAddress(r.RemoteAddr)
  1522. err := r.ParseForm()
  1523. if err != nil {
  1524. s.renderForgotPwdPage(w, err.Error(), ipAddr)
  1525. return
  1526. }
  1527. if err := verifyCSRFToken(r.Form.Get(csrfFormToken), ipAddr); err != nil {
  1528. s.renderForbiddenPage(w, r, err.Error())
  1529. return
  1530. }
  1531. err = handleForgotPassword(r, r.Form.Get("username"), true)
  1532. if err != nil {
  1533. if e, ok := err.(*util.ValidationError); ok {
  1534. s.renderForgotPwdPage(w, e.GetErrorString(), ipAddr)
  1535. return
  1536. }
  1537. s.renderForgotPwdPage(w, err.Error(), ipAddr)
  1538. return
  1539. }
  1540. http.Redirect(w, r, webAdminResetPwdPath, http.StatusFound)
  1541. }
  1542. func (s *httpdServer) handleWebAdminPasswordReset(w http.ResponseWriter, r *http.Request) {
  1543. r.Body = http.MaxBytesReader(w, r.Body, maxLoginBodySize)
  1544. if !smtp.IsEnabled() {
  1545. s.renderNotFoundPage(w, r, errors.New("this page does not exist"))
  1546. return
  1547. }
  1548. s.renderResetPwdPage(w, "", util.GetIPFromRemoteAddress(r.RemoteAddr))
  1549. }
  1550. func (s *httpdServer) handleWebAdminTwoFactor(w http.ResponseWriter, r *http.Request) {
  1551. r.Body = http.MaxBytesReader(w, r.Body, maxRequestSize)
  1552. s.renderTwoFactorPage(w, "", util.GetIPFromRemoteAddress(r.RemoteAddr))
  1553. }
  1554. func (s *httpdServer) handleWebAdminTwoFactorRecovery(w http.ResponseWriter, r *http.Request) {
  1555. r.Body = http.MaxBytesReader(w, r.Body, maxRequestSize)
  1556. s.renderTwoFactorRecoveryPage(w, "", util.GetIPFromRemoteAddress(r.RemoteAddr))
  1557. }
  1558. func (s *httpdServer) handleWebAdminMFA(w http.ResponseWriter, r *http.Request) {
  1559. r.Body = http.MaxBytesReader(w, r.Body, maxRequestSize)
  1560. s.renderMFAPage(w, r)
  1561. }
  1562. func (s *httpdServer) handleWebAdminProfile(w http.ResponseWriter, r *http.Request) {
  1563. r.Body = http.MaxBytesReader(w, r.Body, maxRequestSize)
  1564. s.renderProfilePage(w, r, "")
  1565. }
  1566. func (s *httpdServer) handleWebAdminChangePwd(w http.ResponseWriter, r *http.Request) {
  1567. r.Body = http.MaxBytesReader(w, r.Body, maxRequestSize)
  1568. s.renderChangePasswordPage(w, r, "")
  1569. }
  1570. func (s *httpdServer) handleWebAdminProfilePost(w http.ResponseWriter, r *http.Request) {
  1571. r.Body = http.MaxBytesReader(w, r.Body, maxRequestSize)
  1572. err := r.ParseForm()
  1573. if err != nil {
  1574. s.renderProfilePage(w, r, err.Error())
  1575. return
  1576. }
  1577. ipAddr := util.GetIPFromRemoteAddress(r.RemoteAddr)
  1578. if err := verifyCSRFToken(r.Form.Get(csrfFormToken), ipAddr); err != nil {
  1579. s.renderForbiddenPage(w, r, err.Error())
  1580. return
  1581. }
  1582. claims, err := getTokenClaims(r)
  1583. if err != nil || claims.Username == "" {
  1584. s.renderProfilePage(w, r, "Invalid token claims")
  1585. return
  1586. }
  1587. admin, err := dataprovider.AdminExists(claims.Username)
  1588. if err != nil {
  1589. s.renderProfilePage(w, r, err.Error())
  1590. return
  1591. }
  1592. admin.Filters.AllowAPIKeyAuth = len(r.Form.Get("allow_api_key_auth")) > 0
  1593. admin.Email = r.Form.Get("email")
  1594. admin.Description = r.Form.Get("description")
  1595. err = dataprovider.UpdateAdmin(&admin, dataprovider.ActionExecutorSelf, ipAddr)
  1596. if err != nil {
  1597. s.renderProfilePage(w, r, err.Error())
  1598. return
  1599. }
  1600. s.renderMessagePage(w, r, "Profile updated", "", http.StatusOK, nil,
  1601. "Your profile has been successfully updated")
  1602. }
  1603. func (s *httpdServer) handleWebMaintenance(w http.ResponseWriter, r *http.Request) {
  1604. r.Body = http.MaxBytesReader(w, r.Body, maxRequestSize)
  1605. s.renderMaintenancePage(w, r, "")
  1606. }
  1607. func (s *httpdServer) handleWebRestore(w http.ResponseWriter, r *http.Request) {
  1608. r.Body = http.MaxBytesReader(w, r.Body, MaxRestoreSize)
  1609. claims, err := getTokenClaims(r)
  1610. if err != nil || claims.Username == "" {
  1611. s.renderBadRequestPage(w, r, errors.New("invalid token claims"))
  1612. return
  1613. }
  1614. err = r.ParseMultipartForm(MaxRestoreSize)
  1615. if err != nil {
  1616. s.renderMaintenancePage(w, r, err.Error())
  1617. return
  1618. }
  1619. defer r.MultipartForm.RemoveAll() //nolint:errcheck
  1620. ipAddr := util.GetIPFromRemoteAddress(r.RemoteAddr)
  1621. if err := verifyCSRFToken(r.Form.Get(csrfFormToken), ipAddr); err != nil {
  1622. s.renderForbiddenPage(w, r, err.Error())
  1623. return
  1624. }
  1625. restoreMode, err := strconv.Atoi(r.Form.Get("mode"))
  1626. if err != nil {
  1627. s.renderMaintenancePage(w, r, err.Error())
  1628. return
  1629. }
  1630. scanQuota, err := strconv.Atoi(r.Form.Get("quota"))
  1631. if err != nil {
  1632. s.renderMaintenancePage(w, r, err.Error())
  1633. return
  1634. }
  1635. backupFile, _, err := r.FormFile("backup_file")
  1636. if err != nil {
  1637. s.renderMaintenancePage(w, r, err.Error())
  1638. return
  1639. }
  1640. defer backupFile.Close()
  1641. backupContent, err := io.ReadAll(backupFile)
  1642. if err != nil || len(backupContent) == 0 {
  1643. if len(backupContent) == 0 {
  1644. err = errors.New("backup file size must be greater than 0")
  1645. }
  1646. s.renderMaintenancePage(w, r, err.Error())
  1647. return
  1648. }
  1649. if err := restoreBackup(backupContent, "", scanQuota, restoreMode, claims.Username, ipAddr); err != nil {
  1650. s.renderMaintenancePage(w, r, err.Error())
  1651. return
  1652. }
  1653. s.renderMessagePage(w, r, "Data restored", "", http.StatusOK, nil, "Your backup was successfully restored")
  1654. }
  1655. func (s *httpdServer) handleGetWebAdmins(w http.ResponseWriter, r *http.Request) {
  1656. r.Body = http.MaxBytesReader(w, r.Body, maxRequestSize)
  1657. limit := defaultQueryLimit
  1658. if _, ok := r.URL.Query()["qlimit"]; ok {
  1659. var err error
  1660. limit, err = strconv.Atoi(r.URL.Query().Get("qlimit"))
  1661. if err != nil {
  1662. limit = defaultQueryLimit
  1663. }
  1664. }
  1665. admins := make([]dataprovider.Admin, 0, limit)
  1666. for {
  1667. a, err := dataprovider.GetAdmins(limit, len(admins), dataprovider.OrderASC)
  1668. if err != nil {
  1669. s.renderInternalServerErrorPage(w, r, err)
  1670. return
  1671. }
  1672. admins = append(admins, a...)
  1673. if len(a) < limit {
  1674. break
  1675. }
  1676. }
  1677. data := adminsPage{
  1678. basePage: s.getBasePageData(pageAdminsTitle, webAdminsPath, r),
  1679. Admins: admins,
  1680. }
  1681. renderAdminTemplate(w, templateAdmins, data)
  1682. }
  1683. func (s *httpdServer) handleWebAdminSetupGet(w http.ResponseWriter, r *http.Request) {
  1684. r.Body = http.MaxBytesReader(w, r.Body, maxLoginBodySize)
  1685. if dataprovider.HasAdmin() {
  1686. http.Redirect(w, r, webAdminLoginPath, http.StatusFound)
  1687. return
  1688. }
  1689. s.renderAdminSetupPage(w, r, "", "")
  1690. }
  1691. func (s *httpdServer) handleWebAddAdminGet(w http.ResponseWriter, r *http.Request) {
  1692. r.Body = http.MaxBytesReader(w, r.Body, maxRequestSize)
  1693. admin := &dataprovider.Admin{
  1694. Status: 1,
  1695. Permissions: []string{dataprovider.PermAdminAny},
  1696. }
  1697. s.renderAddUpdateAdminPage(w, r, admin, "", true)
  1698. }
  1699. func (s *httpdServer) handleWebUpdateAdminGet(w http.ResponseWriter, r *http.Request) {
  1700. r.Body = http.MaxBytesReader(w, r.Body, maxRequestSize)
  1701. username := getURLParam(r, "username")
  1702. admin, err := dataprovider.AdminExists(username)
  1703. if err == nil {
  1704. s.renderAddUpdateAdminPage(w, r, &admin, "", false)
  1705. } else if _, ok := err.(*util.RecordNotFoundError); ok {
  1706. s.renderNotFoundPage(w, r, err)
  1707. } else {
  1708. s.renderInternalServerErrorPage(w, r, err)
  1709. }
  1710. }
  1711. func (s *httpdServer) handleWebAddAdminPost(w http.ResponseWriter, r *http.Request) {
  1712. r.Body = http.MaxBytesReader(w, r.Body, maxRequestSize)
  1713. claims, err := getTokenClaims(r)
  1714. if err != nil || claims.Username == "" {
  1715. s.renderBadRequestPage(w, r, errors.New("invalid token claims"))
  1716. return
  1717. }
  1718. admin, err := getAdminFromPostFields(r)
  1719. if err != nil {
  1720. s.renderAddUpdateAdminPage(w, r, &admin, err.Error(), true)
  1721. return
  1722. }
  1723. if admin.Password == "" && s.binding.isWebAdminLoginFormDisabled() {
  1724. admin.Password = util.GenerateUniqueID()
  1725. }
  1726. ipAddr := util.GetIPFromRemoteAddress(r.RemoteAddr)
  1727. if err := verifyCSRFToken(r.Form.Get(csrfFormToken), ipAddr); err != nil {
  1728. s.renderForbiddenPage(w, r, err.Error())
  1729. return
  1730. }
  1731. err = dataprovider.AddAdmin(&admin, claims.Username, ipAddr)
  1732. if err != nil {
  1733. s.renderAddUpdateAdminPage(w, r, &admin, err.Error(), true)
  1734. return
  1735. }
  1736. http.Redirect(w, r, webAdminsPath, http.StatusSeeOther)
  1737. }
  1738. func (s *httpdServer) handleWebUpdateAdminPost(w http.ResponseWriter, r *http.Request) {
  1739. r.Body = http.MaxBytesReader(w, r.Body, maxRequestSize)
  1740. username := getURLParam(r, "username")
  1741. admin, err := dataprovider.AdminExists(username)
  1742. if _, ok := err.(*util.RecordNotFoundError); ok {
  1743. s.renderNotFoundPage(w, r, err)
  1744. return
  1745. } else if err != nil {
  1746. s.renderInternalServerErrorPage(w, r, err)
  1747. return
  1748. }
  1749. updatedAdmin, err := getAdminFromPostFields(r)
  1750. if err != nil {
  1751. s.renderAddUpdateAdminPage(w, r, &updatedAdmin, err.Error(), false)
  1752. return
  1753. }
  1754. ipAddr := util.GetIPFromRemoteAddress(r.RemoteAddr)
  1755. if err := verifyCSRFToken(r.Form.Get(csrfFormToken), ipAddr); err != nil {
  1756. s.renderForbiddenPage(w, r, err.Error())
  1757. return
  1758. }
  1759. updatedAdmin.ID = admin.ID
  1760. updatedAdmin.Username = admin.Username
  1761. if updatedAdmin.Password == "" {
  1762. updatedAdmin.Password = admin.Password
  1763. }
  1764. updatedAdmin.Filters.TOTPConfig = admin.Filters.TOTPConfig
  1765. updatedAdmin.Filters.RecoveryCodes = admin.Filters.RecoveryCodes
  1766. claims, err := getTokenClaims(r)
  1767. if err != nil || claims.Username == "" {
  1768. s.renderAddUpdateAdminPage(w, r, &updatedAdmin, "Invalid token claims", false)
  1769. return
  1770. }
  1771. if username == claims.Username {
  1772. if claims.isCriticalPermRemoved(updatedAdmin.Permissions) {
  1773. s.renderAddUpdateAdminPage(w, r, &updatedAdmin, "You cannot remove these permissions to yourself", false)
  1774. return
  1775. }
  1776. if updatedAdmin.Status == 0 {
  1777. s.renderAddUpdateAdminPage(w, r, &updatedAdmin, "You cannot disable yourself", false)
  1778. return
  1779. }
  1780. }
  1781. err = dataprovider.UpdateAdmin(&updatedAdmin, claims.Username, ipAddr)
  1782. if err != nil {
  1783. s.renderAddUpdateAdminPage(w, r, &admin, err.Error(), false)
  1784. return
  1785. }
  1786. http.Redirect(w, r, webAdminsPath, http.StatusSeeOther)
  1787. }
  1788. func (s *httpdServer) handleWebDefenderPage(w http.ResponseWriter, r *http.Request) {
  1789. r.Body = http.MaxBytesReader(w, r.Body, maxRequestSize)
  1790. data := defenderHostsPage{
  1791. basePage: s.getBasePageData(pageDefenderTitle, webDefenderPath, r),
  1792. DefenderHostsURL: webDefenderHostsPath,
  1793. }
  1794. renderAdminTemplate(w, templateDefender, data)
  1795. }
  1796. func (s *httpdServer) handleGetWebUsers(w http.ResponseWriter, r *http.Request) {
  1797. r.Body = http.MaxBytesReader(w, r.Body, maxRequestSize)
  1798. var limit int
  1799. if _, ok := r.URL.Query()["qlimit"]; ok {
  1800. var err error
  1801. limit, err = strconv.Atoi(r.URL.Query().Get("qlimit"))
  1802. if err != nil {
  1803. limit = defaultQueryLimit
  1804. }
  1805. } else {
  1806. limit = defaultQueryLimit
  1807. }
  1808. users := make([]dataprovider.User, 0, limit)
  1809. for {
  1810. u, err := dataprovider.GetUsers(limit, len(users), dataprovider.OrderASC)
  1811. if err != nil {
  1812. s.renderInternalServerErrorPage(w, r, err)
  1813. return
  1814. }
  1815. users = append(users, u...)
  1816. if len(u) < limit {
  1817. break
  1818. }
  1819. }
  1820. data := usersPage{
  1821. basePage: s.getBasePageData(pageUsersTitle, webUsersPath, r),
  1822. Users: users,
  1823. }
  1824. renderAdminTemplate(w, templateUsers, data)
  1825. }
  1826. func (s *httpdServer) handleWebTemplateFolderGet(w http.ResponseWriter, r *http.Request) {
  1827. r.Body = http.MaxBytesReader(w, r.Body, maxRequestSize)
  1828. if r.URL.Query().Get("from") != "" {
  1829. name := r.URL.Query().Get("from")
  1830. folder, err := dataprovider.GetFolderByName(name)
  1831. if err == nil {
  1832. folder.FsConfig.SetEmptySecrets()
  1833. s.renderFolderPage(w, r, folder, folderPageModeTemplate, "")
  1834. } else if _, ok := err.(*util.RecordNotFoundError); ok {
  1835. s.renderNotFoundPage(w, r, err)
  1836. } else {
  1837. s.renderInternalServerErrorPage(w, r, err)
  1838. }
  1839. } else {
  1840. folder := vfs.BaseVirtualFolder{}
  1841. s.renderFolderPage(w, r, folder, folderPageModeTemplate, "")
  1842. }
  1843. }
  1844. func (s *httpdServer) handleWebTemplateFolderPost(w http.ResponseWriter, r *http.Request) {
  1845. r.Body = http.MaxBytesReader(w, r.Body, maxRequestSize)
  1846. claims, err := getTokenClaims(r)
  1847. if err != nil || claims.Username == "" {
  1848. s.renderBadRequestPage(w, r, errors.New("invalid token claims"))
  1849. return
  1850. }
  1851. templateFolder := vfs.BaseVirtualFolder{}
  1852. err = r.ParseMultipartForm(maxRequestSize)
  1853. if err != nil {
  1854. s.renderMessagePage(w, r, "Error parsing folders fields", "", http.StatusBadRequest, err, "")
  1855. return
  1856. }
  1857. defer r.MultipartForm.RemoveAll() //nolint:errcheck
  1858. ipAddr := util.GetIPFromRemoteAddress(r.RemoteAddr)
  1859. if err := verifyCSRFToken(r.Form.Get(csrfFormToken), ipAddr); err != nil {
  1860. s.renderForbiddenPage(w, r, err.Error())
  1861. return
  1862. }
  1863. templateFolder.MappedPath = r.Form.Get("mapped_path")
  1864. templateFolder.Description = r.Form.Get("description")
  1865. fsConfig, err := getFsConfigFromPostFields(r)
  1866. if err != nil {
  1867. s.renderMessagePage(w, r, "Error parsing folders fields", "", http.StatusBadRequest, err, "")
  1868. return
  1869. }
  1870. templateFolder.FsConfig = fsConfig
  1871. var dump dataprovider.BackupData
  1872. dump.Version = dataprovider.DumpVersion
  1873. foldersFields := getFoldersForTemplate(r)
  1874. for _, tmpl := range foldersFields {
  1875. f := getFolderFromTemplate(templateFolder, tmpl)
  1876. if err := dataprovider.ValidateFolder(&f); err != nil {
  1877. s.renderMessagePage(w, r, "Folder validation error", fmt.Sprintf("Error validating folder %#v", f.Name),
  1878. http.StatusBadRequest, err, "")
  1879. return
  1880. }
  1881. dump.Folders = append(dump.Folders, f)
  1882. }
  1883. if len(dump.Folders) == 0 {
  1884. s.renderMessagePage(w, r, "No folders defined", "No valid folders defined, unable to complete the requested action",
  1885. http.StatusBadRequest, nil, "")
  1886. return
  1887. }
  1888. if r.Form.Get("form_action") == "export_from_template" {
  1889. w.Header().Set("Content-Disposition", fmt.Sprintf("attachment; filename=\"sftpgo-%v-folders-from-template.json\"",
  1890. len(dump.Folders)))
  1891. render.JSON(w, r, dump)
  1892. return
  1893. }
  1894. if err = RestoreFolders(dump.Folders, "", 1, 0, claims.Username, ipAddr); err != nil {
  1895. s.renderMessagePage(w, r, "Unable to save folders", "Cannot save the defined folders:",
  1896. getRespStatus(err), err, "")
  1897. return
  1898. }
  1899. http.Redirect(w, r, webFoldersPath, http.StatusSeeOther)
  1900. }
  1901. func (s *httpdServer) handleWebTemplateUserGet(w http.ResponseWriter, r *http.Request) {
  1902. r.Body = http.MaxBytesReader(w, r.Body, maxRequestSize)
  1903. if r.URL.Query().Get("from") != "" {
  1904. username := r.URL.Query().Get("from")
  1905. user, err := dataprovider.UserExists(username)
  1906. if err == nil {
  1907. user.SetEmptySecrets()
  1908. user.PublicKeys = nil
  1909. user.Email = ""
  1910. user.Description = ""
  1911. s.renderUserPage(w, r, &user, userPageModeTemplate, "")
  1912. } else if _, ok := err.(*util.RecordNotFoundError); ok {
  1913. s.renderNotFoundPage(w, r, err)
  1914. } else {
  1915. s.renderInternalServerErrorPage(w, r, err)
  1916. }
  1917. } else {
  1918. user := dataprovider.User{BaseUser: sdk.BaseUser{
  1919. Status: 1,
  1920. Permissions: map[string][]string{
  1921. "/": {dataprovider.PermAny},
  1922. },
  1923. }}
  1924. s.renderUserPage(w, r, &user, userPageModeTemplate, "")
  1925. }
  1926. }
  1927. func (s *httpdServer) handleWebTemplateUserPost(w http.ResponseWriter, r *http.Request) {
  1928. r.Body = http.MaxBytesReader(w, r.Body, maxRequestSize)
  1929. claims, err := getTokenClaims(r)
  1930. if err != nil || claims.Username == "" {
  1931. s.renderBadRequestPage(w, r, errors.New("invalid token claims"))
  1932. return
  1933. }
  1934. templateUser, err := getUserFromPostFields(r)
  1935. if err != nil {
  1936. s.renderMessagePage(w, r, "Error parsing user fields", "", http.StatusBadRequest, err, "")
  1937. return
  1938. }
  1939. ipAddr := util.GetIPFromRemoteAddress(r.RemoteAddr)
  1940. if err := verifyCSRFToken(r.Form.Get(csrfFormToken), ipAddr); err != nil {
  1941. s.renderForbiddenPage(w, r, err.Error())
  1942. return
  1943. }
  1944. var dump dataprovider.BackupData
  1945. dump.Version = dataprovider.DumpVersion
  1946. userTmplFields := getUsersForTemplate(r)
  1947. for _, tmpl := range userTmplFields {
  1948. u := getUserFromTemplate(templateUser, tmpl)
  1949. if err := dataprovider.ValidateUser(&u); err != nil {
  1950. s.renderMessagePage(w, r, "User validation error", fmt.Sprintf("Error validating user %#v", u.Username),
  1951. http.StatusBadRequest, err, "")
  1952. return
  1953. }
  1954. dump.Users = append(dump.Users, u)
  1955. for _, folder := range u.VirtualFolders {
  1956. if !dump.HasFolder(folder.Name) {
  1957. dump.Folders = append(dump.Folders, folder.BaseVirtualFolder)
  1958. }
  1959. }
  1960. }
  1961. if len(dump.Users) == 0 {
  1962. s.renderMessagePage(w, r, "No users defined", "No valid users defined, unable to complete the requested action",
  1963. http.StatusBadRequest, nil, "")
  1964. return
  1965. }
  1966. if r.Form.Get("form_action") == "export_from_template" {
  1967. w.Header().Set("Content-Disposition", fmt.Sprintf("attachment; filename=\"sftpgo-%v-users-from-template.json\"",
  1968. len(dump.Users)))
  1969. render.JSON(w, r, dump)
  1970. return
  1971. }
  1972. if err = RestoreUsers(dump.Users, "", 1, 0, claims.Username, ipAddr); err != nil {
  1973. s.renderMessagePage(w, r, "Unable to save users", "Cannot save the defined users:",
  1974. getRespStatus(err), err, "")
  1975. return
  1976. }
  1977. http.Redirect(w, r, webUsersPath, http.StatusSeeOther)
  1978. }
  1979. func (s *httpdServer) handleWebAddUserGet(w http.ResponseWriter, r *http.Request) {
  1980. r.Body = http.MaxBytesReader(w, r.Body, maxRequestSize)
  1981. user := dataprovider.User{BaseUser: sdk.BaseUser{
  1982. Status: 1,
  1983. Permissions: map[string][]string{
  1984. "/": {dataprovider.PermAny},
  1985. },
  1986. }}
  1987. s.renderUserPage(w, r, &user, userPageModeAdd, "")
  1988. }
  1989. func (s *httpdServer) handleWebUpdateUserGet(w http.ResponseWriter, r *http.Request) {
  1990. r.Body = http.MaxBytesReader(w, r.Body, maxRequestSize)
  1991. username := getURLParam(r, "username")
  1992. user, err := dataprovider.UserExists(username)
  1993. if err == nil {
  1994. s.renderUserPage(w, r, &user, userPageModeUpdate, "")
  1995. } else if _, ok := err.(*util.RecordNotFoundError); ok {
  1996. s.renderNotFoundPage(w, r, err)
  1997. } else {
  1998. s.renderInternalServerErrorPage(w, r, err)
  1999. }
  2000. }
  2001. func (s *httpdServer) handleWebAddUserPost(w http.ResponseWriter, r *http.Request) {
  2002. r.Body = http.MaxBytesReader(w, r.Body, maxRequestSize)
  2003. claims, err := getTokenClaims(r)
  2004. if err != nil || claims.Username == "" {
  2005. s.renderBadRequestPage(w, r, errors.New("invalid token claims"))
  2006. return
  2007. }
  2008. user, err := getUserFromPostFields(r)
  2009. if err != nil {
  2010. s.renderUserPage(w, r, &user, userPageModeAdd, err.Error())
  2011. return
  2012. }
  2013. ipAddr := util.GetIPFromRemoteAddress(r.RemoteAddr)
  2014. if err := verifyCSRFToken(r.Form.Get(csrfFormToken), ipAddr); err != nil {
  2015. s.renderForbiddenPage(w, r, err.Error())
  2016. return
  2017. }
  2018. user = getUserFromTemplate(user, userTemplateFields{
  2019. Username: user.Username,
  2020. Password: user.Password,
  2021. PublicKeys: user.PublicKeys,
  2022. })
  2023. err = dataprovider.AddUser(&user, claims.Username, ipAddr)
  2024. if err != nil {
  2025. s.renderUserPage(w, r, &user, userPageModeAdd, err.Error())
  2026. return
  2027. }
  2028. http.Redirect(w, r, webUsersPath, http.StatusSeeOther)
  2029. }
  2030. func (s *httpdServer) handleWebUpdateUserPost(w http.ResponseWriter, r *http.Request) {
  2031. r.Body = http.MaxBytesReader(w, r.Body, maxRequestSize)
  2032. claims, err := getTokenClaims(r)
  2033. if err != nil || claims.Username == "" {
  2034. s.renderBadRequestPage(w, r, errors.New("invalid token claims"))
  2035. return
  2036. }
  2037. username := getURLParam(r, "username")
  2038. user, err := dataprovider.UserExists(username)
  2039. if _, ok := err.(*util.RecordNotFoundError); ok {
  2040. s.renderNotFoundPage(w, r, err)
  2041. return
  2042. } else if err != nil {
  2043. s.renderInternalServerErrorPage(w, r, err)
  2044. return
  2045. }
  2046. updatedUser, err := getUserFromPostFields(r)
  2047. if err != nil {
  2048. s.renderUserPage(w, r, &user, userPageModeUpdate, err.Error())
  2049. return
  2050. }
  2051. ipAddr := util.GetIPFromRemoteAddress(r.RemoteAddr)
  2052. if err := verifyCSRFToken(r.Form.Get(csrfFormToken), ipAddr); err != nil {
  2053. s.renderForbiddenPage(w, r, err.Error())
  2054. return
  2055. }
  2056. updatedUser.ID = user.ID
  2057. updatedUser.Username = user.Username
  2058. updatedUser.Filters.RecoveryCodes = user.Filters.RecoveryCodes
  2059. updatedUser.Filters.TOTPConfig = user.Filters.TOTPConfig
  2060. updatedUser.SetEmptySecretsIfNil()
  2061. if updatedUser.Password == redactedSecret {
  2062. updatedUser.Password = user.Password
  2063. }
  2064. updateEncryptedSecrets(&updatedUser.FsConfig, user.FsConfig.S3Config.AccessSecret, user.FsConfig.AzBlobConfig.AccountKey,
  2065. user.FsConfig.AzBlobConfig.SASURL, user.FsConfig.GCSConfig.Credentials, user.FsConfig.CryptConfig.Passphrase,
  2066. user.FsConfig.SFTPConfig.Password, user.FsConfig.SFTPConfig.PrivateKey, user.FsConfig.SFTPConfig.KeyPassphrase)
  2067. updatedUser = getUserFromTemplate(updatedUser, userTemplateFields{
  2068. Username: updatedUser.Username,
  2069. Password: updatedUser.Password,
  2070. PublicKeys: updatedUser.PublicKeys,
  2071. })
  2072. err = dataprovider.UpdateUser(&updatedUser, claims.Username, ipAddr)
  2073. if err != nil {
  2074. s.renderUserPage(w, r, &updatedUser, userPageModeUpdate, err.Error())
  2075. return
  2076. }
  2077. if r.Form.Get("disconnect") != "" {
  2078. disconnectUser(user.Username)
  2079. }
  2080. http.Redirect(w, r, webUsersPath, http.StatusSeeOther)
  2081. }
  2082. func (s *httpdServer) handleWebGetStatus(w http.ResponseWriter, r *http.Request) {
  2083. r.Body = http.MaxBytesReader(w, r.Body, maxRequestSize)
  2084. data := statusPage{
  2085. basePage: s.getBasePageData(pageStatusTitle, webStatusPath, r),
  2086. Status: getServicesStatus(),
  2087. }
  2088. renderAdminTemplate(w, templateStatus, data)
  2089. }
  2090. func (s *httpdServer) handleWebGetConnections(w http.ResponseWriter, r *http.Request) {
  2091. r.Body = http.MaxBytesReader(w, r.Body, maxRequestSize)
  2092. connectionStats := common.Connections.GetStats()
  2093. data := connectionsPage{
  2094. basePage: s.getBasePageData(pageConnectionsTitle, webConnectionsPath, r),
  2095. Connections: connectionStats,
  2096. }
  2097. renderAdminTemplate(w, templateConnections, data)
  2098. }
  2099. func (s *httpdServer) handleWebAddFolderGet(w http.ResponseWriter, r *http.Request) {
  2100. r.Body = http.MaxBytesReader(w, r.Body, maxRequestSize)
  2101. s.renderFolderPage(w, r, vfs.BaseVirtualFolder{}, folderPageModeAdd, "")
  2102. }
  2103. func (s *httpdServer) handleWebAddFolderPost(w http.ResponseWriter, r *http.Request) {
  2104. r.Body = http.MaxBytesReader(w, r.Body, maxRequestSize)
  2105. folder := vfs.BaseVirtualFolder{}
  2106. err := r.ParseMultipartForm(maxRequestSize)
  2107. if err != nil {
  2108. s.renderFolderPage(w, r, folder, folderPageModeAdd, err.Error())
  2109. return
  2110. }
  2111. defer r.MultipartForm.RemoveAll() //nolint:errcheck
  2112. ipAddr := util.GetIPFromRemoteAddress(r.RemoteAddr)
  2113. if err := verifyCSRFToken(r.Form.Get(csrfFormToken), ipAddr); err != nil {
  2114. s.renderForbiddenPage(w, r, err.Error())
  2115. return
  2116. }
  2117. folder.MappedPath = r.Form.Get("mapped_path")
  2118. folder.Name = r.Form.Get("name")
  2119. folder.Description = r.Form.Get("description")
  2120. fsConfig, err := getFsConfigFromPostFields(r)
  2121. if err != nil {
  2122. s.renderFolderPage(w, r, folder, folderPageModeAdd, err.Error())
  2123. return
  2124. }
  2125. folder.FsConfig = fsConfig
  2126. folder = getFolderFromTemplate(folder, folder.Name)
  2127. err = dataprovider.AddFolder(&folder)
  2128. if err == nil {
  2129. http.Redirect(w, r, webFoldersPath, http.StatusSeeOther)
  2130. } else {
  2131. s.renderFolderPage(w, r, folder, folderPageModeAdd, err.Error())
  2132. }
  2133. }
  2134. func (s *httpdServer) handleWebUpdateFolderGet(w http.ResponseWriter, r *http.Request) {
  2135. r.Body = http.MaxBytesReader(w, r.Body, maxRequestSize)
  2136. name := getURLParam(r, "name")
  2137. folder, err := dataprovider.GetFolderByName(name)
  2138. if err == nil {
  2139. s.renderFolderPage(w, r, folder, folderPageModeUpdate, "")
  2140. } else if _, ok := err.(*util.RecordNotFoundError); ok {
  2141. s.renderNotFoundPage(w, r, err)
  2142. } else {
  2143. s.renderInternalServerErrorPage(w, r, err)
  2144. }
  2145. }
  2146. func (s *httpdServer) handleWebUpdateFolderPost(w http.ResponseWriter, r *http.Request) {
  2147. r.Body = http.MaxBytesReader(w, r.Body, maxRequestSize)
  2148. claims, err := getTokenClaims(r)
  2149. if err != nil || claims.Username == "" {
  2150. s.renderBadRequestPage(w, r, errors.New("invalid token claims"))
  2151. return
  2152. }
  2153. name := getURLParam(r, "name")
  2154. folder, err := dataprovider.GetFolderByName(name)
  2155. if _, ok := err.(*util.RecordNotFoundError); ok {
  2156. s.renderNotFoundPage(w, r, err)
  2157. return
  2158. } else if err != nil {
  2159. s.renderInternalServerErrorPage(w, r, err)
  2160. return
  2161. }
  2162. err = r.ParseMultipartForm(maxRequestSize)
  2163. if err != nil {
  2164. s.renderFolderPage(w, r, folder, folderPageModeUpdate, err.Error())
  2165. return
  2166. }
  2167. defer r.MultipartForm.RemoveAll() //nolint:errcheck
  2168. ipAddr := util.GetIPFromRemoteAddress(r.RemoteAddr)
  2169. if err := verifyCSRFToken(r.Form.Get(csrfFormToken), ipAddr); err != nil {
  2170. s.renderForbiddenPage(w, r, err.Error())
  2171. return
  2172. }
  2173. fsConfig, err := getFsConfigFromPostFields(r)
  2174. if err != nil {
  2175. s.renderFolderPage(w, r, folder, folderPageModeUpdate, err.Error())
  2176. return
  2177. }
  2178. updatedFolder := vfs.BaseVirtualFolder{
  2179. MappedPath: r.Form.Get("mapped_path"),
  2180. Description: r.Form.Get("description"),
  2181. }
  2182. updatedFolder.ID = folder.ID
  2183. updatedFolder.Name = folder.Name
  2184. updatedFolder.FsConfig = fsConfig
  2185. updatedFolder.FsConfig.SetEmptySecretsIfNil()
  2186. updateEncryptedSecrets(&updatedFolder.FsConfig, folder.FsConfig.S3Config.AccessSecret, folder.FsConfig.AzBlobConfig.AccountKey,
  2187. folder.FsConfig.AzBlobConfig.SASURL, folder.FsConfig.GCSConfig.Credentials, folder.FsConfig.CryptConfig.Passphrase,
  2188. folder.FsConfig.SFTPConfig.Password, folder.FsConfig.SFTPConfig.PrivateKey, folder.FsConfig.SFTPConfig.KeyPassphrase)
  2189. updatedFolder = getFolderFromTemplate(updatedFolder, updatedFolder.Name)
  2190. err = dataprovider.UpdateFolder(&updatedFolder, folder.Users, folder.Groups, claims.Username, ipAddr)
  2191. if err != nil {
  2192. s.renderFolderPage(w, r, updatedFolder, folderPageModeUpdate, err.Error())
  2193. return
  2194. }
  2195. http.Redirect(w, r, webFoldersPath, http.StatusSeeOther)
  2196. }
  2197. func (s *httpdServer) getWebVirtualFolders(w http.ResponseWriter, r *http.Request, limit int, minimal bool) ([]vfs.BaseVirtualFolder, error) {
  2198. folders := make([]vfs.BaseVirtualFolder, 0, limit)
  2199. for {
  2200. f, err := dataprovider.GetFolders(limit, len(folders), dataprovider.OrderASC, minimal)
  2201. if err != nil {
  2202. s.renderInternalServerErrorPage(w, r, err)
  2203. return folders, err
  2204. }
  2205. folders = append(folders, f...)
  2206. if len(f) < limit {
  2207. break
  2208. }
  2209. }
  2210. return folders, nil
  2211. }
  2212. func (s *httpdServer) handleWebGetFolders(w http.ResponseWriter, r *http.Request) {
  2213. r.Body = http.MaxBytesReader(w, r.Body, maxRequestSize)
  2214. limit := defaultQueryLimit
  2215. if _, ok := r.URL.Query()["qlimit"]; ok {
  2216. var err error
  2217. limit, err = strconv.Atoi(r.URL.Query().Get("qlimit"))
  2218. if err != nil {
  2219. limit = defaultQueryLimit
  2220. }
  2221. }
  2222. folders, err := s.getWebVirtualFolders(w, r, limit, false)
  2223. if err != nil {
  2224. return
  2225. }
  2226. data := foldersPage{
  2227. basePage: s.getBasePageData(pageFoldersTitle, webFoldersPath, r),
  2228. Folders: folders,
  2229. }
  2230. renderAdminTemplate(w, templateFolders, data)
  2231. }
  2232. func (s *httpdServer) getWebGroups(w http.ResponseWriter, r *http.Request, limit int, minimal bool) ([]dataprovider.Group, error) {
  2233. groups := make([]dataprovider.Group, 0, limit)
  2234. for {
  2235. f, err := dataprovider.GetGroups(limit, len(groups), dataprovider.OrderASC, minimal)
  2236. if err != nil {
  2237. s.renderInternalServerErrorPage(w, r, err)
  2238. return groups, err
  2239. }
  2240. groups = append(groups, f...)
  2241. if len(f) < limit {
  2242. break
  2243. }
  2244. }
  2245. return groups, nil
  2246. }
  2247. func (s *httpdServer) handleWebGetGroups(w http.ResponseWriter, r *http.Request) {
  2248. r.Body = http.MaxBytesReader(w, r.Body, maxRequestSize)
  2249. limit := defaultQueryLimit
  2250. if _, ok := r.URL.Query()["qlimit"]; ok {
  2251. var err error
  2252. limit, err = strconv.Atoi(r.URL.Query().Get("qlimit"))
  2253. if err != nil {
  2254. limit = defaultQueryLimit
  2255. }
  2256. }
  2257. groups, err := s.getWebGroups(w, r, limit, false)
  2258. if err != nil {
  2259. return
  2260. }
  2261. data := groupsPage{
  2262. basePage: s.getBasePageData(pageGroupsTitle, webGroupsPath, r),
  2263. Groups: groups,
  2264. }
  2265. renderAdminTemplate(w, templateGroups, data)
  2266. }
  2267. func (s *httpdServer) handleWebAddGroupGet(w http.ResponseWriter, r *http.Request) {
  2268. r.Body = http.MaxBytesReader(w, r.Body, maxRequestSize)
  2269. s.renderGroupPage(w, r, dataprovider.Group{}, groupPageModeAdd, "")
  2270. }
  2271. func (s *httpdServer) handleWebAddGroupPost(w http.ResponseWriter, r *http.Request) {
  2272. r.Body = http.MaxBytesReader(w, r.Body, maxRequestSize)
  2273. claims, err := getTokenClaims(r)
  2274. if err != nil || claims.Username == "" {
  2275. s.renderBadRequestPage(w, r, errors.New("invalid token claims"))
  2276. return
  2277. }
  2278. group, err := getGroupFromPostFields(r)
  2279. if err != nil {
  2280. s.renderGroupPage(w, r, group, groupPageModeAdd, err.Error())
  2281. return
  2282. }
  2283. ipAddr := util.GetIPFromRemoteAddress(r.RemoteAddr)
  2284. if err := verifyCSRFToken(r.Form.Get(csrfFormToken), ipAddr); err != nil {
  2285. s.renderForbiddenPage(w, r, err.Error())
  2286. return
  2287. }
  2288. err = dataprovider.AddGroup(&group, claims.Username, ipAddr)
  2289. if err != nil {
  2290. s.renderGroupPage(w, r, group, groupPageModeAdd, err.Error())
  2291. return
  2292. }
  2293. http.Redirect(w, r, webGroupsPath, http.StatusSeeOther)
  2294. }
  2295. func (s *httpdServer) handleWebUpdateGroupGet(w http.ResponseWriter, r *http.Request) {
  2296. r.Body = http.MaxBytesReader(w, r.Body, maxRequestSize)
  2297. name := getURLParam(r, "name")
  2298. group, err := dataprovider.GroupExists(name)
  2299. if err == nil {
  2300. s.renderGroupPage(w, r, group, groupPageModeUpdate, "")
  2301. } else if _, ok := err.(*util.RecordNotFoundError); ok {
  2302. s.renderNotFoundPage(w, r, err)
  2303. } else {
  2304. s.renderInternalServerErrorPage(w, r, err)
  2305. }
  2306. }
  2307. func (s *httpdServer) handleWebUpdateGroupPost(w http.ResponseWriter, r *http.Request) {
  2308. r.Body = http.MaxBytesReader(w, r.Body, maxRequestSize)
  2309. claims, err := getTokenClaims(r)
  2310. if err != nil || claims.Username == "" {
  2311. s.renderBadRequestPage(w, r, errors.New("invalid token claims"))
  2312. return
  2313. }
  2314. name := getURLParam(r, "name")
  2315. group, err := dataprovider.GroupExists(name)
  2316. if _, ok := err.(*util.RecordNotFoundError); ok {
  2317. s.renderNotFoundPage(w, r, err)
  2318. return
  2319. } else if err != nil {
  2320. s.renderInternalServerErrorPage(w, r, err)
  2321. return
  2322. }
  2323. updatedGroup, err := getGroupFromPostFields(r)
  2324. if err != nil {
  2325. s.renderGroupPage(w, r, group, groupPageModeUpdate, err.Error())
  2326. return
  2327. }
  2328. ipAddr := util.GetIPFromRemoteAddress(r.RemoteAddr)
  2329. if err := verifyCSRFToken(r.Form.Get(csrfFormToken), ipAddr); err != nil {
  2330. s.renderForbiddenPage(w, r, err.Error())
  2331. return
  2332. }
  2333. updatedGroup.ID = group.ID
  2334. updatedGroup.Name = group.Name
  2335. updatedGroup.SetEmptySecretsIfNil()
  2336. updateEncryptedSecrets(&updatedGroup.UserSettings.FsConfig, group.UserSettings.FsConfig.S3Config.AccessSecret,
  2337. group.UserSettings.FsConfig.AzBlobConfig.AccountKey, group.UserSettings.FsConfig.AzBlobConfig.SASURL,
  2338. group.UserSettings.FsConfig.GCSConfig.Credentials, group.UserSettings.FsConfig.CryptConfig.Passphrase,
  2339. group.UserSettings.FsConfig.SFTPConfig.Password, group.UserSettings.FsConfig.SFTPConfig.PrivateKey,
  2340. group.UserSettings.FsConfig.SFTPConfig.KeyPassphrase)
  2341. err = dataprovider.UpdateGroup(&updatedGroup, group.Users, claims.Username, ipAddr)
  2342. if err != nil {
  2343. s.renderGroupPage(w, r, updatedGroup, groupPageModeUpdate, err.Error())
  2344. return
  2345. }
  2346. http.Redirect(w, r, webGroupsPath, http.StatusSeeOther)
  2347. }