webadmin.go 81 KB

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