1
0

web.go 46 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548
  1. package httpd
  2. import (
  3. "errors"
  4. "fmt"
  5. "html/template"
  6. "io"
  7. "net/http"
  8. "net/url"
  9. "path"
  10. "path/filepath"
  11. "strconv"
  12. "strings"
  13. "time"
  14. "github.com/go-chi/render"
  15. "github.com/drakkan/sftpgo/common"
  16. "github.com/drakkan/sftpgo/dataprovider"
  17. "github.com/drakkan/sftpgo/kms"
  18. "github.com/drakkan/sftpgo/utils"
  19. "github.com/drakkan/sftpgo/version"
  20. "github.com/drakkan/sftpgo/vfs"
  21. )
  22. type userPageMode int
  23. const (
  24. userPageModeAdd userPageMode = iota + 1
  25. userPageModeUpdate
  26. userPageModeTemplate
  27. )
  28. type folderPageMode int
  29. const (
  30. folderPageModeAdd folderPageMode = iota + 1
  31. folderPageModeUpdate
  32. folderPageModeTemplate
  33. )
  34. const (
  35. templateBase = "base.html"
  36. templateUsers = "users.html"
  37. templateUser = "user.html"
  38. templateAdmins = "admins.html"
  39. templateAdmin = "admin.html"
  40. templateConnections = "connections.html"
  41. templateFolders = "folders.html"
  42. templateFolder = "folder.html"
  43. templateMessage = "message.html"
  44. templateStatus = "status.html"
  45. templateLogin = "login.html"
  46. templateChangePwd = "changepwd.html"
  47. templateMaintenance = "maintenance.html"
  48. pageUsersTitle = "Users"
  49. pageAdminsTitle = "Admins"
  50. pageConnectionsTitle = "Connections"
  51. pageStatusTitle = "Status"
  52. pageFoldersTitle = "Folders"
  53. pageChangePwdTitle = "Change password"
  54. pageMaintenanceTitle = "Maintenance"
  55. page400Title = "Bad request"
  56. page403Title = "Forbidden"
  57. page404Title = "Not found"
  58. page404Body = "The page you are looking for does not exist."
  59. page500Title = "Internal Server Error"
  60. page500Body = "The server is unable to fulfill your request."
  61. defaultQueryLimit = 500
  62. webDateTimeFormat = "2006-01-02 15:04:05" // YYYY-MM-DD HH:MM:SS
  63. redactedSecret = "[**redacted**]"
  64. csrfFormToken = "_form_token"
  65. csrfHeaderToken = "X-CSRF-TOKEN"
  66. )
  67. var (
  68. templates = make(map[string]*template.Template)
  69. )
  70. type basePage struct {
  71. Title string
  72. CurrentURL string
  73. UsersURL string
  74. UserURL string
  75. UserTemplateURL string
  76. AdminsURL string
  77. AdminURL string
  78. QuotaScanURL string
  79. ConnectionsURL string
  80. FoldersURL string
  81. FolderURL string
  82. FolderTemplateURL string
  83. LogoutURL string
  84. ChangeAdminPwdURL string
  85. FolderQuotaScanURL string
  86. StatusURL string
  87. MaintenanceURL string
  88. UsersTitle string
  89. AdminsTitle string
  90. ConnectionsTitle string
  91. FoldersTitle string
  92. StatusTitle string
  93. MaintenanceTitle string
  94. Version string
  95. CSRFToken string
  96. LoggedAdmin *dataprovider.Admin
  97. }
  98. type usersPage struct {
  99. basePage
  100. Users []dataprovider.User
  101. }
  102. type adminsPage struct {
  103. basePage
  104. Admins []dataprovider.Admin
  105. }
  106. type foldersPage struct {
  107. basePage
  108. Folders []vfs.BaseVirtualFolder
  109. }
  110. type connectionsPage struct {
  111. basePage
  112. Connections []*common.ConnectionStatus
  113. }
  114. type statusPage struct {
  115. basePage
  116. Status ServicesStatus
  117. }
  118. type userPage struct {
  119. basePage
  120. User *dataprovider.User
  121. RootPerms []string
  122. Error string
  123. ValidPerms []string
  124. ValidLoginMethods []string
  125. ValidProtocols []string
  126. RootDirPerms []string
  127. RedactedSecret string
  128. Mode userPageMode
  129. }
  130. type adminPage struct {
  131. basePage
  132. Admin *dataprovider.Admin
  133. Error string
  134. IsAdd bool
  135. }
  136. type changePwdPage struct {
  137. basePage
  138. Error string
  139. }
  140. type maintenancePage struct {
  141. basePage
  142. BackupPath string
  143. RestorePath string
  144. Error string
  145. }
  146. type folderPage struct {
  147. basePage
  148. Folder vfs.BaseVirtualFolder
  149. Error string
  150. Mode folderPageMode
  151. }
  152. type messagePage struct {
  153. basePage
  154. Error string
  155. Success string
  156. }
  157. type loginPage struct {
  158. CurrentURL string
  159. Version string
  160. Error string
  161. CSRFToken string
  162. }
  163. type userTemplateFields struct {
  164. Username string
  165. Password string
  166. PublicKey string
  167. }
  168. func loadTemplates(templatesPath string) {
  169. usersPaths := []string{
  170. filepath.Join(templatesPath, templateBase),
  171. filepath.Join(templatesPath, templateUsers),
  172. }
  173. userPaths := []string{
  174. filepath.Join(templatesPath, templateBase),
  175. filepath.Join(templatesPath, templateUser),
  176. }
  177. adminsPaths := []string{
  178. filepath.Join(templatesPath, templateBase),
  179. filepath.Join(templatesPath, templateAdmins),
  180. }
  181. adminPaths := []string{
  182. filepath.Join(templatesPath, templateBase),
  183. filepath.Join(templatesPath, templateAdmin),
  184. }
  185. changePwdPaths := []string{
  186. filepath.Join(templatesPath, templateBase),
  187. filepath.Join(templatesPath, templateChangePwd),
  188. }
  189. connectionsPaths := []string{
  190. filepath.Join(templatesPath, templateBase),
  191. filepath.Join(templatesPath, templateConnections),
  192. }
  193. messagePath := []string{
  194. filepath.Join(templatesPath, templateBase),
  195. filepath.Join(templatesPath, templateMessage),
  196. }
  197. foldersPath := []string{
  198. filepath.Join(templatesPath, templateBase),
  199. filepath.Join(templatesPath, templateFolders),
  200. }
  201. folderPath := []string{
  202. filepath.Join(templatesPath, templateBase),
  203. filepath.Join(templatesPath, templateFolder),
  204. }
  205. statusPath := []string{
  206. filepath.Join(templatesPath, templateBase),
  207. filepath.Join(templatesPath, templateStatus),
  208. }
  209. loginPath := []string{
  210. filepath.Join(templatesPath, templateLogin),
  211. }
  212. maintenancePath := []string{
  213. filepath.Join(templatesPath, templateBase),
  214. filepath.Join(templatesPath, templateMaintenance),
  215. }
  216. usersTmpl := utils.LoadTemplate(template.ParseFiles(usersPaths...))
  217. userTmpl := utils.LoadTemplate(template.ParseFiles(userPaths...))
  218. adminsTmpl := utils.LoadTemplate(template.ParseFiles(adminsPaths...))
  219. adminTmpl := utils.LoadTemplate(template.ParseFiles(adminPaths...))
  220. connectionsTmpl := utils.LoadTemplate(template.ParseFiles(connectionsPaths...))
  221. messageTmpl := utils.LoadTemplate(template.ParseFiles(messagePath...))
  222. foldersTmpl := utils.LoadTemplate(template.ParseFiles(foldersPath...))
  223. folderTmpl := utils.LoadTemplate(template.ParseFiles(folderPath...))
  224. statusTmpl := utils.LoadTemplate(template.ParseFiles(statusPath...))
  225. loginTmpl := utils.LoadTemplate(template.ParseFiles(loginPath...))
  226. changePwdTmpl := utils.LoadTemplate(template.ParseFiles(changePwdPaths...))
  227. maintenanceTmpl := utils.LoadTemplate(template.ParseFiles(maintenancePath...))
  228. templates[templateUsers] = usersTmpl
  229. templates[templateUser] = userTmpl
  230. templates[templateAdmins] = adminsTmpl
  231. templates[templateAdmin] = adminTmpl
  232. templates[templateConnections] = connectionsTmpl
  233. templates[templateMessage] = messageTmpl
  234. templates[templateFolders] = foldersTmpl
  235. templates[templateFolder] = folderTmpl
  236. templates[templateStatus] = statusTmpl
  237. templates[templateLogin] = loginTmpl
  238. templates[templateChangePwd] = changePwdTmpl
  239. templates[templateMaintenance] = maintenanceTmpl
  240. }
  241. func getBasePageData(title, currentURL string, r *http.Request) basePage {
  242. var csrfToken string
  243. if currentURL != "" {
  244. csrfToken = createCSRFToken()
  245. }
  246. return basePage{
  247. Title: title,
  248. CurrentURL: currentURL,
  249. UsersURL: webUsersPath,
  250. UserURL: webUserPath,
  251. UserTemplateURL: webTemplateUser,
  252. AdminsURL: webAdminsPath,
  253. AdminURL: webAdminPath,
  254. FoldersURL: webFoldersPath,
  255. FolderURL: webFolderPath,
  256. FolderTemplateURL: webTemplateFolder,
  257. LogoutURL: webLogoutPath,
  258. ChangeAdminPwdURL: webChangeAdminPwdPath,
  259. QuotaScanURL: webQuotaScanPath,
  260. ConnectionsURL: webConnectionsPath,
  261. StatusURL: webStatusPath,
  262. FolderQuotaScanURL: webScanVFolderPath,
  263. MaintenanceURL: webMaintenancePath,
  264. UsersTitle: pageUsersTitle,
  265. AdminsTitle: pageAdminsTitle,
  266. ConnectionsTitle: pageConnectionsTitle,
  267. FoldersTitle: pageFoldersTitle,
  268. StatusTitle: pageStatusTitle,
  269. MaintenanceTitle: pageMaintenanceTitle,
  270. Version: version.GetAsString(),
  271. LoggedAdmin: getAdminFromToken(r),
  272. CSRFToken: csrfToken,
  273. }
  274. }
  275. func renderTemplate(w http.ResponseWriter, tmplName string, data interface{}) {
  276. err := templates[tmplName].ExecuteTemplate(w, tmplName, data)
  277. if err != nil {
  278. http.Error(w, err.Error(), http.StatusInternalServerError)
  279. }
  280. }
  281. func renderMessagePage(w http.ResponseWriter, r *http.Request, title, body string, statusCode int, err error, message string) {
  282. var errorString string
  283. if body != "" {
  284. errorString = body + " "
  285. }
  286. if err != nil {
  287. errorString += err.Error()
  288. }
  289. data := messagePage{
  290. basePage: getBasePageData(title, "", r),
  291. Error: errorString,
  292. Success: message,
  293. }
  294. w.WriteHeader(statusCode)
  295. renderTemplate(w, templateMessage, data)
  296. }
  297. func renderInternalServerErrorPage(w http.ResponseWriter, r *http.Request, err error) {
  298. renderMessagePage(w, r, page500Title, page500Body, http.StatusInternalServerError, err, "")
  299. }
  300. func renderBadRequestPage(w http.ResponseWriter, r *http.Request, err error) {
  301. renderMessagePage(w, r, page400Title, "", http.StatusBadRequest, err, "")
  302. }
  303. func renderForbiddenPage(w http.ResponseWriter, r *http.Request, body string) {
  304. renderMessagePage(w, r, page403Title, "", http.StatusForbidden, nil, body)
  305. }
  306. func renderNotFoundPage(w http.ResponseWriter, r *http.Request, err error) {
  307. renderMessagePage(w, r, page404Title, page404Body, http.StatusNotFound, err, "")
  308. }
  309. func renderChangePwdPage(w http.ResponseWriter, r *http.Request, error string) {
  310. data := changePwdPage{
  311. basePage: getBasePageData(pageChangePwdTitle, webChangeAdminPwdPath, r),
  312. Error: error,
  313. }
  314. renderTemplate(w, templateChangePwd, data)
  315. }
  316. func renderMaintenancePage(w http.ResponseWriter, r *http.Request, error string) {
  317. data := maintenancePage{
  318. basePage: getBasePageData(pageMaintenanceTitle, webMaintenancePath, r),
  319. BackupPath: webBackupPath,
  320. RestorePath: webRestorePath,
  321. Error: error,
  322. }
  323. renderTemplate(w, templateMaintenance, data)
  324. }
  325. func renderAddUpdateAdminPage(w http.ResponseWriter, r *http.Request, admin *dataprovider.Admin,
  326. error string, isAdd bool) {
  327. currentURL := webAdminPath
  328. if !isAdd {
  329. currentURL = fmt.Sprintf("%v/%v", webAdminPath, url.PathEscape(admin.Username))
  330. }
  331. data := adminPage{
  332. basePage: getBasePageData("Add a new user", currentURL, r),
  333. Admin: admin,
  334. Error: error,
  335. IsAdd: isAdd,
  336. }
  337. renderTemplate(w, templateAdmin, data)
  338. }
  339. func renderUserPage(w http.ResponseWriter, r *http.Request, user *dataprovider.User, mode userPageMode, error string) {
  340. user.SetEmptySecretsIfNil()
  341. var title, currentURL string
  342. switch mode {
  343. case userPageModeAdd:
  344. title = "Add a new user"
  345. currentURL = webUserPath
  346. case userPageModeUpdate:
  347. title = "Update user"
  348. currentURL = fmt.Sprintf("%v/%v", webUserPath, url.PathEscape(user.Username))
  349. case userPageModeTemplate:
  350. title = "User template"
  351. currentURL = webTemplateUser
  352. }
  353. if user.Password != "" && user.IsPasswordHashed() && mode == userPageModeUpdate {
  354. user.Password = redactedSecret
  355. }
  356. data := userPage{
  357. basePage: getBasePageData(title, currentURL, r),
  358. Mode: mode,
  359. Error: error,
  360. User: user,
  361. ValidPerms: dataprovider.ValidPerms,
  362. ValidLoginMethods: dataprovider.ValidLoginMethods,
  363. ValidProtocols: dataprovider.ValidProtocols,
  364. RootDirPerms: user.GetPermissionsForPath("/"),
  365. RedactedSecret: redactedSecret,
  366. }
  367. renderTemplate(w, templateUser, data)
  368. }
  369. func renderFolderPage(w http.ResponseWriter, r *http.Request, folder vfs.BaseVirtualFolder, mode folderPageMode, error string) {
  370. var title, currentURL string
  371. switch mode {
  372. case folderPageModeAdd:
  373. title = "Add a new folder"
  374. currentURL = webFolderPath
  375. case folderPageModeUpdate:
  376. title = "Update folder"
  377. currentURL = fmt.Sprintf("%v/%v", webFolderPath, url.PathEscape(folder.Name))
  378. case folderPageModeTemplate:
  379. title = "Folder template"
  380. currentURL = webTemplateFolder
  381. }
  382. data := folderPage{
  383. basePage: getBasePageData(title, currentURL, r),
  384. Error: error,
  385. Folder: folder,
  386. Mode: mode,
  387. }
  388. renderTemplate(w, templateFolder, data)
  389. }
  390. func getFoldersForTemplate(r *http.Request) []string {
  391. var res []string
  392. formValue := r.Form.Get("folders")
  393. folders := make(map[string]bool)
  394. for _, name := range getSliceFromDelimitedValues(formValue, "\n") {
  395. if _, ok := folders[name]; ok {
  396. continue
  397. }
  398. folders[name] = true
  399. res = append(res, name)
  400. }
  401. return res
  402. }
  403. func getUsersForTemplate(r *http.Request) []userTemplateFields {
  404. var res []userTemplateFields
  405. formValue := r.Form.Get("users")
  406. users := make(map[string]bool)
  407. for _, cleaned := range getSliceFromDelimitedValues(formValue, "\n") {
  408. if strings.Contains(cleaned, "::") {
  409. mapping := strings.Split(cleaned, "::")
  410. if len(mapping) > 1 {
  411. username := strings.TrimSpace(mapping[0])
  412. password := strings.TrimSpace(mapping[1])
  413. var publicKey string
  414. if len(mapping) > 2 {
  415. publicKey = strings.TrimSpace(mapping[2])
  416. }
  417. if username == "" || (password == "" && publicKey == "") {
  418. continue
  419. }
  420. if _, ok := users[username]; ok {
  421. continue
  422. }
  423. users[username] = true
  424. res = append(res, userTemplateFields{
  425. Username: username,
  426. Password: password,
  427. PublicKey: publicKey,
  428. })
  429. }
  430. }
  431. }
  432. return res
  433. }
  434. func getVirtualFoldersFromPostFields(r *http.Request) []vfs.VirtualFolder {
  435. var virtualFolders []vfs.VirtualFolder
  436. formValue := r.Form.Get("virtual_folders")
  437. for _, cleaned := range getSliceFromDelimitedValues(formValue, "\n") {
  438. if strings.Contains(cleaned, "::") {
  439. mapping := strings.Split(cleaned, "::")
  440. if len(mapping) > 1 {
  441. vfolder := vfs.VirtualFolder{
  442. BaseVirtualFolder: vfs.BaseVirtualFolder{
  443. Name: strings.TrimSpace(mapping[1]),
  444. },
  445. VirtualPath: strings.TrimSpace(mapping[0]),
  446. QuotaFiles: -1,
  447. QuotaSize: -1,
  448. }
  449. if len(mapping) > 2 {
  450. quotaFiles, err := strconv.Atoi(strings.TrimSpace(mapping[2]))
  451. if err == nil {
  452. vfolder.QuotaFiles = quotaFiles
  453. }
  454. }
  455. if len(mapping) > 3 {
  456. quotaSize, err := strconv.ParseInt(strings.TrimSpace(mapping[3]), 10, 64)
  457. if err == nil {
  458. vfolder.QuotaSize = quotaSize
  459. }
  460. }
  461. virtualFolders = append(virtualFolders, vfolder)
  462. }
  463. }
  464. }
  465. return virtualFolders
  466. }
  467. func getUserPermissionsFromPostFields(r *http.Request) map[string][]string {
  468. permissions := make(map[string][]string)
  469. permissions["/"] = r.Form["permissions"]
  470. subDirsPermsValue := r.Form.Get("sub_dirs_permissions")
  471. for _, cleaned := range getSliceFromDelimitedValues(subDirsPermsValue, "\n") {
  472. if strings.Contains(cleaned, "::") {
  473. dirPerms := strings.Split(cleaned, "::")
  474. if len(dirPerms) > 1 {
  475. dir := dirPerms[0]
  476. dir = strings.TrimSpace(dir)
  477. perms := []string{}
  478. for _, p := range strings.Split(dirPerms[1], ",") {
  479. cleanedPerm := strings.TrimSpace(p)
  480. if cleanedPerm != "" {
  481. perms = append(perms, cleanedPerm)
  482. }
  483. }
  484. if dir != "" {
  485. permissions[dir] = perms
  486. }
  487. }
  488. }
  489. }
  490. return permissions
  491. }
  492. func getSliceFromDelimitedValues(values, delimiter string) []string {
  493. result := []string{}
  494. for _, v := range strings.Split(values, delimiter) {
  495. cleaned := strings.TrimSpace(v)
  496. if cleaned != "" {
  497. result = append(result, cleaned)
  498. }
  499. }
  500. return result
  501. }
  502. func getListFromPostFields(value string) map[string][]string {
  503. result := make(map[string][]string)
  504. for _, cleaned := range getSliceFromDelimitedValues(value, "\n") {
  505. if strings.Contains(cleaned, "::") {
  506. dirExts := strings.Split(cleaned, "::")
  507. if len(dirExts) > 1 {
  508. dir := dirExts[0]
  509. dir = path.Clean(strings.TrimSpace(dir))
  510. exts := []string{}
  511. for _, e := range strings.Split(dirExts[1], ",") {
  512. cleanedExt := strings.TrimSpace(e)
  513. if cleanedExt != "" {
  514. exts = append(exts, cleanedExt)
  515. }
  516. }
  517. if dir != "" {
  518. if _, ok := result[dir]; ok {
  519. result[dir] = append(result[dir], exts...)
  520. } else {
  521. result[dir] = exts
  522. }
  523. result[dir] = utils.RemoveDuplicates(result[dir])
  524. }
  525. }
  526. }
  527. }
  528. return result
  529. }
  530. func getFilePatternsFromPostField(valueAllowed, valuesDenied string) []dataprovider.PatternsFilter {
  531. var result []dataprovider.PatternsFilter
  532. allowedPatterns := getListFromPostFields(valueAllowed)
  533. deniedPatterns := getListFromPostFields(valuesDenied)
  534. for dirAllowed, allowPatterns := range allowedPatterns {
  535. filter := dataprovider.PatternsFilter{
  536. Path: dirAllowed,
  537. AllowedPatterns: allowPatterns,
  538. }
  539. for dirDenied, denPatterns := range deniedPatterns {
  540. if dirAllowed == dirDenied {
  541. filter.DeniedPatterns = denPatterns
  542. break
  543. }
  544. }
  545. result = append(result, filter)
  546. }
  547. for dirDenied, denPatterns := range deniedPatterns {
  548. found := false
  549. for _, res := range result {
  550. if res.Path == dirDenied {
  551. found = true
  552. break
  553. }
  554. }
  555. if !found {
  556. result = append(result, dataprovider.PatternsFilter{
  557. Path: dirDenied,
  558. DeniedPatterns: denPatterns,
  559. })
  560. }
  561. }
  562. return result
  563. }
  564. func getFileExtensionsFromPostField(valueAllowed, valuesDenied string) []dataprovider.ExtensionsFilter {
  565. var result []dataprovider.ExtensionsFilter
  566. allowedExtensions := getListFromPostFields(valueAllowed)
  567. deniedExtensions := getListFromPostFields(valuesDenied)
  568. for dirAllowed, allowedExts := range allowedExtensions {
  569. filter := dataprovider.ExtensionsFilter{
  570. Path: dirAllowed,
  571. AllowedExtensions: allowedExts,
  572. }
  573. for dirDenied, deniedExts := range deniedExtensions {
  574. if dirAllowed == dirDenied {
  575. filter.DeniedExtensions = deniedExts
  576. break
  577. }
  578. }
  579. result = append(result, filter)
  580. }
  581. for dirDenied, deniedExts := range deniedExtensions {
  582. found := false
  583. for _, res := range result {
  584. if res.Path == dirDenied {
  585. found = true
  586. break
  587. }
  588. }
  589. if !found {
  590. result = append(result, dataprovider.ExtensionsFilter{
  591. Path: dirDenied,
  592. DeniedExtensions: deniedExts,
  593. })
  594. }
  595. }
  596. return result
  597. }
  598. func getFiltersFromUserPostFields(r *http.Request) dataprovider.UserFilters {
  599. var filters dataprovider.UserFilters
  600. filters.AllowedIP = getSliceFromDelimitedValues(r.Form.Get("allowed_ip"), ",")
  601. filters.DeniedIP = getSliceFromDelimitedValues(r.Form.Get("denied_ip"), ",")
  602. filters.DeniedLoginMethods = r.Form["ssh_login_methods"]
  603. filters.DeniedProtocols = r.Form["denied_protocols"]
  604. filters.FileExtensions = getFileExtensionsFromPostField(r.Form.Get("allowed_extensions"), r.Form.Get("denied_extensions"))
  605. filters.FilePatterns = getFilePatternsFromPostField(r.Form.Get("allowed_patterns"), r.Form.Get("denied_patterns"))
  606. filters.TLSUsername = dataprovider.TLSUsername(r.Form.Get("tls_username"))
  607. return filters
  608. }
  609. func getSecretFromFormField(r *http.Request, field string) *kms.Secret {
  610. secret := kms.NewPlainSecret(r.Form.Get(field))
  611. if strings.TrimSpace(secret.GetPayload()) == redactedSecret {
  612. secret.SetStatus(kms.SecretStatusRedacted)
  613. }
  614. if strings.TrimSpace(secret.GetPayload()) == "" {
  615. secret.SetStatus("")
  616. }
  617. return secret
  618. }
  619. func getS3Config(r *http.Request) (vfs.S3FsConfig, error) {
  620. var err error
  621. config := vfs.S3FsConfig{}
  622. config.Bucket = r.Form.Get("s3_bucket")
  623. config.Region = r.Form.Get("s3_region")
  624. config.AccessKey = r.Form.Get("s3_access_key")
  625. config.AccessSecret = getSecretFromFormField(r, "s3_access_secret")
  626. config.Endpoint = r.Form.Get("s3_endpoint")
  627. config.StorageClass = r.Form.Get("s3_storage_class")
  628. config.KeyPrefix = r.Form.Get("s3_key_prefix")
  629. config.UploadPartSize, err = strconv.ParseInt(r.Form.Get("s3_upload_part_size"), 10, 64)
  630. if err != nil {
  631. return config, err
  632. }
  633. config.UploadConcurrency, err = strconv.Atoi(r.Form.Get("s3_upload_concurrency"))
  634. return config, err
  635. }
  636. func getGCSConfig(r *http.Request) (vfs.GCSFsConfig, error) {
  637. var err error
  638. config := vfs.GCSFsConfig{}
  639. config.Bucket = r.Form.Get("gcs_bucket")
  640. config.StorageClass = r.Form.Get("gcs_storage_class")
  641. config.KeyPrefix = r.Form.Get("gcs_key_prefix")
  642. autoCredentials := r.Form.Get("gcs_auto_credentials")
  643. if autoCredentials != "" {
  644. config.AutomaticCredentials = 1
  645. } else {
  646. config.AutomaticCredentials = 0
  647. }
  648. credentials, _, err := r.FormFile("gcs_credential_file")
  649. if err == http.ErrMissingFile {
  650. return config, nil
  651. }
  652. if err != nil {
  653. return config, err
  654. }
  655. defer credentials.Close()
  656. fileBytes, err := io.ReadAll(credentials)
  657. if err != nil || len(fileBytes) == 0 {
  658. if len(fileBytes) == 0 {
  659. err = errors.New("credentials file size must be greater than 0")
  660. }
  661. return config, err
  662. }
  663. config.Credentials = kms.NewPlainSecret(string(fileBytes))
  664. config.AutomaticCredentials = 0
  665. return config, err
  666. }
  667. func getSFTPConfig(r *http.Request) vfs.SFTPFsConfig {
  668. config := vfs.SFTPFsConfig{}
  669. config.Endpoint = r.Form.Get("sftp_endpoint")
  670. config.Username = r.Form.Get("sftp_username")
  671. config.Password = getSecretFromFormField(r, "sftp_password")
  672. config.PrivateKey = getSecretFromFormField(r, "sftp_private_key")
  673. fingerprintsFormValue := r.Form.Get("sftp_fingerprints")
  674. config.Fingerprints = getSliceFromDelimitedValues(fingerprintsFormValue, "\n")
  675. config.Prefix = r.Form.Get("sftp_prefix")
  676. config.DisableCouncurrentReads = len(r.Form.Get("sftp_disable_concurrent_reads")) > 0
  677. return config
  678. }
  679. func getAzureConfig(r *http.Request) (vfs.AzBlobFsConfig, error) {
  680. var err error
  681. config := vfs.AzBlobFsConfig{}
  682. config.Container = r.Form.Get("az_container")
  683. config.AccountName = r.Form.Get("az_account_name")
  684. config.AccountKey = getSecretFromFormField(r, "az_account_key")
  685. config.SASURL = r.Form.Get("az_sas_url")
  686. config.Endpoint = r.Form.Get("az_endpoint")
  687. config.KeyPrefix = r.Form.Get("az_key_prefix")
  688. config.AccessTier = r.Form.Get("az_access_tier")
  689. config.UseEmulator = len(r.Form.Get("az_use_emulator")) > 0
  690. config.UploadPartSize, err = strconv.ParseInt(r.Form.Get("az_upload_part_size"), 10, 64)
  691. if err != nil {
  692. return config, err
  693. }
  694. config.UploadConcurrency, err = strconv.Atoi(r.Form.Get("az_upload_concurrency"))
  695. return config, err
  696. }
  697. func getFsConfigFromUserPostFields(r *http.Request) (dataprovider.Filesystem, error) {
  698. var fs dataprovider.Filesystem
  699. provider, err := strconv.Atoi(r.Form.Get("fs_provider"))
  700. if err != nil {
  701. provider = int(dataprovider.LocalFilesystemProvider)
  702. }
  703. fs.Provider = dataprovider.FilesystemProvider(provider)
  704. switch fs.Provider {
  705. case dataprovider.S3FilesystemProvider:
  706. config, err := getS3Config(r)
  707. if err != nil {
  708. return fs, err
  709. }
  710. fs.S3Config = config
  711. case dataprovider.AzureBlobFilesystemProvider:
  712. config, err := getAzureConfig(r)
  713. if err != nil {
  714. return fs, err
  715. }
  716. fs.AzBlobConfig = config
  717. case dataprovider.GCSFilesystemProvider:
  718. config, err := getGCSConfig(r)
  719. if err != nil {
  720. return fs, err
  721. }
  722. fs.GCSConfig = config
  723. case dataprovider.CryptedFilesystemProvider:
  724. fs.CryptConfig.Passphrase = getSecretFromFormField(r, "crypt_passphrase")
  725. case dataprovider.SFTPFilesystemProvider:
  726. fs.SFTPConfig = getSFTPConfig(r)
  727. }
  728. return fs, nil
  729. }
  730. func getAdminFromPostFields(r *http.Request) (dataprovider.Admin, error) {
  731. var admin dataprovider.Admin
  732. err := r.ParseForm()
  733. if err != nil {
  734. return admin, err
  735. }
  736. status, err := strconv.Atoi(r.Form.Get("status"))
  737. if err != nil {
  738. return admin, err
  739. }
  740. admin.Username = r.Form.Get("username")
  741. admin.Password = r.Form.Get("password")
  742. admin.Permissions = r.Form["permissions"]
  743. admin.Email = r.Form.Get("email")
  744. admin.Status = status
  745. admin.Filters.AllowList = getSliceFromDelimitedValues(r.Form.Get("allowed_ip"), ",")
  746. admin.AdditionalInfo = r.Form.Get("additional_info")
  747. admin.Description = r.Form.Get("description")
  748. return admin, nil
  749. }
  750. func replacePlaceholders(field string, replacements map[string]string) string {
  751. for k, v := range replacements {
  752. field = strings.ReplaceAll(field, k, v)
  753. }
  754. return field
  755. }
  756. func getFolderFromTemplate(folder vfs.BaseVirtualFolder, name string) vfs.BaseVirtualFolder {
  757. folder.Name = name
  758. replacements := make(map[string]string)
  759. replacements["%name%"] = folder.Name
  760. folder.MappedPath = replacePlaceholders(folder.MappedPath, replacements)
  761. folder.Description = replacePlaceholders(folder.Description, replacements)
  762. return folder
  763. }
  764. func getCryptFsFromTemplate(fsConfig vfs.CryptFsConfig, replacements map[string]string) vfs.CryptFsConfig {
  765. if fsConfig.Passphrase != nil {
  766. if fsConfig.Passphrase.IsPlain() {
  767. payload := replacePlaceholders(fsConfig.Passphrase.GetPayload(), replacements)
  768. fsConfig.Passphrase = kms.NewPlainSecret(payload)
  769. }
  770. }
  771. return fsConfig
  772. }
  773. func getS3FsFromTemplate(fsConfig vfs.S3FsConfig, replacements map[string]string) vfs.S3FsConfig {
  774. fsConfig.KeyPrefix = replacePlaceholders(fsConfig.KeyPrefix, replacements)
  775. fsConfig.AccessKey = replacePlaceholders(fsConfig.AccessKey, replacements)
  776. if fsConfig.AccessSecret != nil && fsConfig.AccessSecret.IsPlain() {
  777. payload := replacePlaceholders(fsConfig.AccessSecret.GetPayload(), replacements)
  778. fsConfig.AccessSecret = kms.NewPlainSecret(payload)
  779. }
  780. return fsConfig
  781. }
  782. func getGCSFsFromTemplate(fsConfig vfs.GCSFsConfig, replacements map[string]string) vfs.GCSFsConfig {
  783. fsConfig.KeyPrefix = replacePlaceholders(fsConfig.KeyPrefix, replacements)
  784. return fsConfig
  785. }
  786. func getAzBlobFsFromTemplate(fsConfig vfs.AzBlobFsConfig, replacements map[string]string) vfs.AzBlobFsConfig {
  787. fsConfig.KeyPrefix = replacePlaceholders(fsConfig.KeyPrefix, replacements)
  788. fsConfig.AccountName = replacePlaceholders(fsConfig.AccountName, replacements)
  789. if fsConfig.AccountKey != nil && fsConfig.AccountKey.IsPlain() {
  790. payload := replacePlaceholders(fsConfig.AccountKey.GetPayload(), replacements)
  791. fsConfig.AccountKey = kms.NewPlainSecret(payload)
  792. }
  793. return fsConfig
  794. }
  795. func getSFTPFsFromTemplate(fsConfig vfs.SFTPFsConfig, replacements map[string]string) vfs.SFTPFsConfig {
  796. fsConfig.Prefix = replacePlaceholders(fsConfig.Prefix, replacements)
  797. fsConfig.Username = replacePlaceholders(fsConfig.Username, replacements)
  798. if fsConfig.Password != nil && fsConfig.Password.IsPlain() {
  799. payload := replacePlaceholders(fsConfig.Password.GetPayload(), replacements)
  800. fsConfig.Password = kms.NewPlainSecret(payload)
  801. }
  802. return fsConfig
  803. }
  804. func getUserFromTemplate(user dataprovider.User, template userTemplateFields) dataprovider.User {
  805. user.Username = template.Username
  806. user.Password = template.Password
  807. user.PublicKeys = nil
  808. if template.PublicKey != "" {
  809. user.PublicKeys = append(user.PublicKeys, template.PublicKey)
  810. }
  811. replacements := make(map[string]string)
  812. replacements["%username%"] = user.Username
  813. user.Password = replacePlaceholders(user.Password, replacements)
  814. replacements["%password%"] = user.Password
  815. user.HomeDir = replacePlaceholders(user.HomeDir, replacements)
  816. var vfolders []vfs.VirtualFolder
  817. for _, vfolder := range user.VirtualFolders {
  818. vfolder.Name = replacePlaceholders(vfolder.Name, replacements)
  819. vfolder.VirtualPath = replacePlaceholders(vfolder.VirtualPath, replacements)
  820. vfolders = append(vfolders, vfolder)
  821. }
  822. user.VirtualFolders = vfolders
  823. user.Description = replacePlaceholders(user.Description, replacements)
  824. user.AdditionalInfo = replacePlaceholders(user.AdditionalInfo, replacements)
  825. switch user.FsConfig.Provider {
  826. case dataprovider.CryptedFilesystemProvider:
  827. user.FsConfig.CryptConfig = getCryptFsFromTemplate(user.FsConfig.CryptConfig, replacements)
  828. case dataprovider.S3FilesystemProvider:
  829. user.FsConfig.S3Config = getS3FsFromTemplate(user.FsConfig.S3Config, replacements)
  830. case dataprovider.GCSFilesystemProvider:
  831. user.FsConfig.GCSConfig = getGCSFsFromTemplate(user.FsConfig.GCSConfig, replacements)
  832. case dataprovider.AzureBlobFilesystemProvider:
  833. user.FsConfig.AzBlobConfig = getAzBlobFsFromTemplate(user.FsConfig.AzBlobConfig, replacements)
  834. case dataprovider.SFTPFilesystemProvider:
  835. user.FsConfig.SFTPConfig = getSFTPFsFromTemplate(user.FsConfig.SFTPConfig, replacements)
  836. }
  837. return user
  838. }
  839. func getUserFromPostFields(r *http.Request) (dataprovider.User, error) {
  840. var user dataprovider.User
  841. err := r.ParseMultipartForm(maxRequestSize)
  842. if err != nil {
  843. return user, err
  844. }
  845. publicKeysFormValue := r.Form.Get("public_keys")
  846. publicKeys := getSliceFromDelimitedValues(publicKeysFormValue, "\n")
  847. uid, err := strconv.Atoi(r.Form.Get("uid"))
  848. if err != nil {
  849. return user, err
  850. }
  851. gid, err := strconv.Atoi(r.Form.Get("gid"))
  852. if err != nil {
  853. return user, err
  854. }
  855. maxSessions, err := strconv.Atoi(r.Form.Get("max_sessions"))
  856. if err != nil {
  857. return user, err
  858. }
  859. quotaSize, err := strconv.ParseInt(r.Form.Get("quota_size"), 10, 64)
  860. if err != nil {
  861. return user, err
  862. }
  863. quotaFiles, err := strconv.Atoi(r.Form.Get("quota_files"))
  864. if err != nil {
  865. return user, err
  866. }
  867. bandwidthUL, err := strconv.ParseInt(r.Form.Get("upload_bandwidth"), 10, 64)
  868. if err != nil {
  869. return user, err
  870. }
  871. bandwidthDL, err := strconv.ParseInt(r.Form.Get("download_bandwidth"), 10, 64)
  872. if err != nil {
  873. return user, err
  874. }
  875. status, err := strconv.Atoi(r.Form.Get("status"))
  876. if err != nil {
  877. return user, err
  878. }
  879. expirationDateMillis := int64(0)
  880. expirationDateString := r.Form.Get("expiration_date")
  881. if len(strings.TrimSpace(expirationDateString)) > 0 {
  882. expirationDate, err := time.Parse(webDateTimeFormat, expirationDateString)
  883. if err != nil {
  884. return user, err
  885. }
  886. expirationDateMillis = utils.GetTimeAsMsSinceEpoch(expirationDate)
  887. }
  888. fsConfig, err := getFsConfigFromUserPostFields(r)
  889. if err != nil {
  890. return user, err
  891. }
  892. user = dataprovider.User{
  893. Username: r.Form.Get("username"),
  894. Password: r.Form.Get("password"),
  895. PublicKeys: publicKeys,
  896. HomeDir: r.Form.Get("home_dir"),
  897. VirtualFolders: getVirtualFoldersFromPostFields(r),
  898. UID: uid,
  899. GID: gid,
  900. Permissions: getUserPermissionsFromPostFields(r),
  901. MaxSessions: maxSessions,
  902. QuotaSize: quotaSize,
  903. QuotaFiles: quotaFiles,
  904. UploadBandwidth: bandwidthUL,
  905. DownloadBandwidth: bandwidthDL,
  906. Status: status,
  907. ExpirationDate: expirationDateMillis,
  908. Filters: getFiltersFromUserPostFields(r),
  909. FsConfig: fsConfig,
  910. AdditionalInfo: r.Form.Get("additional_info"),
  911. Description: r.Form.Get("description"),
  912. }
  913. maxFileSize, err := strconv.ParseInt(r.Form.Get("max_upload_file_size"), 10, 64)
  914. user.Filters.MaxUploadFileSize = maxFileSize
  915. return user, err
  916. }
  917. func renderLoginPage(w http.ResponseWriter, error string) {
  918. data := loginPage{
  919. CurrentURL: webLoginPath,
  920. Version: version.Get().Version,
  921. Error: error,
  922. CSRFToken: createCSRFToken(),
  923. }
  924. renderTemplate(w, templateLogin, data)
  925. }
  926. func handleWebAdminChangePwd(w http.ResponseWriter, r *http.Request) {
  927. renderChangePwdPage(w, r, "")
  928. }
  929. func handleWebAdminChangePwdPost(w http.ResponseWriter, r *http.Request) {
  930. r.Body = http.MaxBytesReader(w, r.Body, maxRequestSize)
  931. err := r.ParseForm()
  932. if err != nil {
  933. renderChangePwdPage(w, r, err.Error())
  934. return
  935. }
  936. if err := verifyCSRFToken(r.Form.Get(csrfFormToken)); err != nil {
  937. renderForbiddenPage(w, r, err.Error())
  938. return
  939. }
  940. err = doChangeAdminPassword(r, r.Form.Get("current_password"), r.Form.Get("new_password1"),
  941. r.Form.Get("new_password2"))
  942. if err != nil {
  943. renderChangePwdPage(w, r, err.Error())
  944. return
  945. }
  946. handleWebLogout(w, r)
  947. }
  948. func handleWebLogout(w http.ResponseWriter, r *http.Request) {
  949. c := jwtTokenClaims{}
  950. c.removeCookie(w, r)
  951. http.Redirect(w, r, webLoginPath, http.StatusFound)
  952. }
  953. func handleWebLogin(w http.ResponseWriter, r *http.Request) {
  954. renderLoginPage(w, "")
  955. }
  956. func handleWebMaintenance(w http.ResponseWriter, r *http.Request) {
  957. renderMaintenancePage(w, r, "")
  958. }
  959. func handleWebRestore(w http.ResponseWriter, r *http.Request) {
  960. err := r.ParseMultipartForm(MaxRestoreSize)
  961. if err != nil {
  962. renderMaintenancePage(w, r, err.Error())
  963. return
  964. }
  965. if err := verifyCSRFToken(r.Form.Get(csrfFormToken)); err != nil {
  966. renderForbiddenPage(w, r, err.Error())
  967. return
  968. }
  969. restoreMode, err := strconv.Atoi(r.Form.Get("mode"))
  970. if err != nil {
  971. renderMaintenancePage(w, r, err.Error())
  972. return
  973. }
  974. scanQuota, err := strconv.Atoi(r.Form.Get("quota"))
  975. if err != nil {
  976. renderMaintenancePage(w, r, err.Error())
  977. return
  978. }
  979. backupFile, _, err := r.FormFile("backup_file")
  980. if err != nil {
  981. renderMaintenancePage(w, r, err.Error())
  982. return
  983. }
  984. defer backupFile.Close()
  985. backupContent, err := io.ReadAll(backupFile)
  986. if err != nil || len(backupContent) == 0 {
  987. if len(backupContent) == 0 {
  988. err = errors.New("backup file size must be greater than 0")
  989. }
  990. renderMaintenancePage(w, r, err.Error())
  991. return
  992. }
  993. if err := restoreBackup(backupContent, "", scanQuota, restoreMode); err != nil {
  994. renderMaintenancePage(w, r, err.Error())
  995. return
  996. }
  997. renderMessagePage(w, r, "Data restored", "", http.StatusOK, nil, "Your backup was successfully restored")
  998. }
  999. func handleGetWebAdmins(w http.ResponseWriter, r *http.Request) {
  1000. limit := defaultQueryLimit
  1001. if _, ok := r.URL.Query()["qlimit"]; ok {
  1002. var err error
  1003. limit, err = strconv.Atoi(r.URL.Query().Get("qlimit"))
  1004. if err != nil {
  1005. limit = defaultQueryLimit
  1006. }
  1007. }
  1008. admins := make([]dataprovider.Admin, 0, limit)
  1009. for {
  1010. a, err := dataprovider.GetAdmins(limit, len(admins), dataprovider.OrderASC)
  1011. if err != nil {
  1012. renderInternalServerErrorPage(w, r, err)
  1013. return
  1014. }
  1015. admins = append(admins, a...)
  1016. if len(a) < limit {
  1017. break
  1018. }
  1019. }
  1020. data := adminsPage{
  1021. basePage: getBasePageData(pageAdminsTitle, webAdminsPath, r),
  1022. Admins: admins,
  1023. }
  1024. renderTemplate(w, templateAdmins, data)
  1025. }
  1026. func handleWebAddAdminGet(w http.ResponseWriter, r *http.Request) {
  1027. admin := &dataprovider.Admin{Status: 1}
  1028. renderAddUpdateAdminPage(w, r, admin, "", true)
  1029. }
  1030. func handleWebUpdateAdminGet(w http.ResponseWriter, r *http.Request) {
  1031. username := getURLParam(r, "username")
  1032. admin, err := dataprovider.AdminExists(username)
  1033. if err == nil {
  1034. renderAddUpdateAdminPage(w, r, &admin, "", false)
  1035. } else if _, ok := err.(*dataprovider.RecordNotFoundError); ok {
  1036. renderNotFoundPage(w, r, err)
  1037. } else {
  1038. renderInternalServerErrorPage(w, r, err)
  1039. }
  1040. }
  1041. func handleWebAddAdminPost(w http.ResponseWriter, r *http.Request) {
  1042. r.Body = http.MaxBytesReader(w, r.Body, maxRequestSize)
  1043. admin, err := getAdminFromPostFields(r)
  1044. if err != nil {
  1045. renderAddUpdateAdminPage(w, r, &admin, err.Error(), true)
  1046. return
  1047. }
  1048. if err := verifyCSRFToken(r.Form.Get(csrfFormToken)); err != nil {
  1049. renderForbiddenPage(w, r, err.Error())
  1050. return
  1051. }
  1052. err = dataprovider.AddAdmin(&admin)
  1053. if err != nil {
  1054. renderAddUpdateAdminPage(w, r, &admin, err.Error(), true)
  1055. return
  1056. }
  1057. http.Redirect(w, r, webAdminsPath, http.StatusSeeOther)
  1058. }
  1059. func handleWebUpdateAdminPost(w http.ResponseWriter, r *http.Request) {
  1060. r.Body = http.MaxBytesReader(w, r.Body, maxRequestSize)
  1061. username := getURLParam(r, "username")
  1062. admin, err := dataprovider.AdminExists(username)
  1063. if _, ok := err.(*dataprovider.RecordNotFoundError); ok {
  1064. renderNotFoundPage(w, r, err)
  1065. return
  1066. } else if err != nil {
  1067. renderInternalServerErrorPage(w, r, err)
  1068. return
  1069. }
  1070. updatedAdmin, err := getAdminFromPostFields(r)
  1071. if err != nil {
  1072. renderAddUpdateAdminPage(w, r, &updatedAdmin, err.Error(), false)
  1073. return
  1074. }
  1075. if err := verifyCSRFToken(r.Form.Get(csrfFormToken)); err != nil {
  1076. renderForbiddenPage(w, r, err.Error())
  1077. return
  1078. }
  1079. updatedAdmin.ID = admin.ID
  1080. updatedAdmin.Username = admin.Username
  1081. if updatedAdmin.Password == "" {
  1082. updatedAdmin.Password = admin.Password
  1083. }
  1084. claims, err := getTokenClaims(r)
  1085. if err != nil || claims.Username == "" {
  1086. renderAddUpdateAdminPage(w, r, &updatedAdmin, fmt.Sprintf("Invalid token claims: %v", err), false)
  1087. return
  1088. }
  1089. if username == claims.Username {
  1090. if claims.isCriticalPermRemoved(updatedAdmin.Permissions) {
  1091. renderAddUpdateAdminPage(w, r, &updatedAdmin, "You cannot remove these permissions to yourself", false)
  1092. return
  1093. }
  1094. if updatedAdmin.Status == 0 {
  1095. renderAddUpdateAdminPage(w, r, &updatedAdmin, "You cannot disable yourself", false)
  1096. return
  1097. }
  1098. }
  1099. err = dataprovider.UpdateAdmin(&updatedAdmin)
  1100. if err != nil {
  1101. renderAddUpdateAdminPage(w, r, &admin, err.Error(), false)
  1102. return
  1103. }
  1104. http.Redirect(w, r, webAdminsPath, http.StatusSeeOther)
  1105. }
  1106. func handleGetWebUsers(w http.ResponseWriter, r *http.Request) {
  1107. limit := defaultQueryLimit
  1108. if _, ok := r.URL.Query()["qlimit"]; ok {
  1109. var err error
  1110. limit, err = strconv.Atoi(r.URL.Query().Get("qlimit"))
  1111. if err != nil {
  1112. limit = defaultQueryLimit
  1113. }
  1114. }
  1115. users := make([]dataprovider.User, 0, limit)
  1116. for {
  1117. u, err := dataprovider.GetUsers(limit, len(users), dataprovider.OrderASC)
  1118. if err != nil {
  1119. renderInternalServerErrorPage(w, r, err)
  1120. return
  1121. }
  1122. users = append(users, u...)
  1123. if len(u) < limit {
  1124. break
  1125. }
  1126. }
  1127. data := usersPage{
  1128. basePage: getBasePageData(pageUsersTitle, webUsersPath, r),
  1129. Users: users,
  1130. }
  1131. renderTemplate(w, templateUsers, data)
  1132. }
  1133. func handleWebTemplateFolderGet(w http.ResponseWriter, r *http.Request) {
  1134. if r.URL.Query().Get("from") != "" {
  1135. name := r.URL.Query().Get("from")
  1136. folder, err := dataprovider.GetFolderByName(name)
  1137. if err == nil {
  1138. renderFolderPage(w, r, folder, folderPageModeTemplate, "")
  1139. } else if _, ok := err.(*dataprovider.RecordNotFoundError); ok {
  1140. renderNotFoundPage(w, r, err)
  1141. } else {
  1142. renderInternalServerErrorPage(w, r, err)
  1143. }
  1144. } else {
  1145. folder := vfs.BaseVirtualFolder{}
  1146. renderFolderPage(w, r, folder, folderPageModeTemplate, "")
  1147. }
  1148. }
  1149. func handleWebTemplateFolderPost(w http.ResponseWriter, r *http.Request) {
  1150. r.Body = http.MaxBytesReader(w, r.Body, maxRequestSize)
  1151. templateFolder := vfs.BaseVirtualFolder{}
  1152. err := r.ParseForm()
  1153. if err != nil {
  1154. renderMessagePage(w, r, "Error parsing folders fields", "", http.StatusBadRequest, err, "")
  1155. return
  1156. }
  1157. if err := verifyCSRFToken(r.Form.Get(csrfFormToken)); err != nil {
  1158. renderForbiddenPage(w, r, err.Error())
  1159. return
  1160. }
  1161. templateFolder.MappedPath = r.Form.Get("mapped_path")
  1162. templateFolder.Description = r.Form.Get("description")
  1163. var dump dataprovider.BackupData
  1164. dump.Version = dataprovider.DumpVersion
  1165. foldersFields := getFoldersForTemplate(r)
  1166. for _, tmpl := range foldersFields {
  1167. f := getFolderFromTemplate(templateFolder, tmpl)
  1168. if err := dataprovider.ValidateFolder(&f); err != nil {
  1169. renderMessagePage(w, r, fmt.Sprintf("Error validating folder %#v", f.Name), "", http.StatusBadRequest, err, "")
  1170. return
  1171. }
  1172. dump.Folders = append(dump.Folders, f)
  1173. }
  1174. if len(dump.Folders) == 0 {
  1175. renderMessagePage(w, r, "No folders to export", "No valid folders found, export is not possible", http.StatusBadRequest, nil, "")
  1176. return
  1177. }
  1178. w.Header().Set("Content-Disposition", fmt.Sprintf("attachment; filename=\"sftpgo-%v-folders-from-template.json\"", len(dump.Folders)))
  1179. render.JSON(w, r, dump)
  1180. }
  1181. func handleWebTemplateUserGet(w http.ResponseWriter, r *http.Request) {
  1182. if r.URL.Query().Get("from") != "" {
  1183. username := r.URL.Query().Get("from")
  1184. user, err := dataprovider.UserExists(username)
  1185. if err == nil {
  1186. user.SetEmptySecrets()
  1187. renderUserPage(w, r, &user, userPageModeTemplate, "")
  1188. } else if _, ok := err.(*dataprovider.RecordNotFoundError); ok {
  1189. renderNotFoundPage(w, r, err)
  1190. } else {
  1191. renderInternalServerErrorPage(w, r, err)
  1192. }
  1193. } else {
  1194. user := dataprovider.User{Status: 1}
  1195. renderUserPage(w, r, &user, userPageModeTemplate, "")
  1196. }
  1197. }
  1198. func handleWebTemplateUserPost(w http.ResponseWriter, r *http.Request) {
  1199. r.Body = http.MaxBytesReader(w, r.Body, maxRequestSize)
  1200. templateUser, err := getUserFromPostFields(r)
  1201. if err != nil {
  1202. renderMessagePage(w, r, "Error parsing user fields", "", http.StatusBadRequest, err, "")
  1203. return
  1204. }
  1205. if err := verifyCSRFToken(r.Form.Get(csrfFormToken)); err != nil {
  1206. renderForbiddenPage(w, r, err.Error())
  1207. return
  1208. }
  1209. var dump dataprovider.BackupData
  1210. dump.Version = dataprovider.DumpVersion
  1211. userTmplFields := getUsersForTemplate(r)
  1212. for _, tmpl := range userTmplFields {
  1213. u := getUserFromTemplate(templateUser, tmpl)
  1214. if err := dataprovider.ValidateUser(&u); err != nil {
  1215. renderMessagePage(w, r, fmt.Sprintf("Error validating user %#v", u.Username), "", http.StatusBadRequest, err, "")
  1216. return
  1217. }
  1218. dump.Users = append(dump.Users, u)
  1219. for _, folder := range u.VirtualFolders {
  1220. if !dump.HasFolder(folder.Name) {
  1221. dump.Folders = append(dump.Folders, folder.BaseVirtualFolder)
  1222. }
  1223. }
  1224. }
  1225. if len(dump.Users) == 0 {
  1226. renderMessagePage(w, r, "No users to export", "No valid users found, export is not possible", http.StatusBadRequest, nil, "")
  1227. return
  1228. }
  1229. w.Header().Set("Content-Disposition", fmt.Sprintf("attachment; filename=\"sftpgo-%v-users-from-template.json\"", len(dump.Users)))
  1230. render.JSON(w, r, dump)
  1231. }
  1232. func handleWebAddUserGet(w http.ResponseWriter, r *http.Request) {
  1233. if r.URL.Query().Get("clone-from") != "" {
  1234. username := r.URL.Query().Get("clone-from")
  1235. user, err := dataprovider.UserExists(username)
  1236. if err == nil {
  1237. user.ID = 0
  1238. user.Username = ""
  1239. user.Password = ""
  1240. user.SetEmptySecrets()
  1241. renderUserPage(w, r, &user, userPageModeAdd, "")
  1242. } else if _, ok := err.(*dataprovider.RecordNotFoundError); ok {
  1243. renderNotFoundPage(w, r, err)
  1244. } else {
  1245. renderInternalServerErrorPage(w, r, err)
  1246. }
  1247. } else {
  1248. user := dataprovider.User{Status: 1}
  1249. renderUserPage(w, r, &user, userPageModeAdd, "")
  1250. }
  1251. }
  1252. func handleWebUpdateUserGet(w http.ResponseWriter, r *http.Request) {
  1253. username := getURLParam(r, "username")
  1254. user, err := dataprovider.UserExists(username)
  1255. if err == nil {
  1256. renderUserPage(w, r, &user, userPageModeUpdate, "")
  1257. } else if _, ok := err.(*dataprovider.RecordNotFoundError); ok {
  1258. renderNotFoundPage(w, r, err)
  1259. } else {
  1260. renderInternalServerErrorPage(w, r, err)
  1261. }
  1262. }
  1263. func handleWebAddUserPost(w http.ResponseWriter, r *http.Request) {
  1264. r.Body = http.MaxBytesReader(w, r.Body, maxRequestSize)
  1265. user, err := getUserFromPostFields(r)
  1266. if err != nil {
  1267. renderUserPage(w, r, &user, userPageModeAdd, err.Error())
  1268. return
  1269. }
  1270. if err := verifyCSRFToken(r.Form.Get(csrfFormToken)); err != nil {
  1271. renderForbiddenPage(w, r, err.Error())
  1272. return
  1273. }
  1274. err = dataprovider.AddUser(&user)
  1275. if err == nil {
  1276. http.Redirect(w, r, webUsersPath, http.StatusSeeOther)
  1277. } else {
  1278. renderUserPage(w, r, &user, userPageModeAdd, err.Error())
  1279. }
  1280. }
  1281. func handleWebUpdateUserPost(w http.ResponseWriter, r *http.Request) {
  1282. r.Body = http.MaxBytesReader(w, r.Body, maxRequestSize)
  1283. username := getURLParam(r, "username")
  1284. user, err := dataprovider.UserExists(username)
  1285. if _, ok := err.(*dataprovider.RecordNotFoundError); ok {
  1286. renderNotFoundPage(w, r, err)
  1287. return
  1288. } else if err != nil {
  1289. renderInternalServerErrorPage(w, r, err)
  1290. return
  1291. }
  1292. updatedUser, err := getUserFromPostFields(r)
  1293. if err != nil {
  1294. renderUserPage(w, r, &user, userPageModeUpdate, err.Error())
  1295. return
  1296. }
  1297. if err := verifyCSRFToken(r.Form.Get(csrfFormToken)); err != nil {
  1298. renderForbiddenPage(w, r, err.Error())
  1299. return
  1300. }
  1301. updatedUser.ID = user.ID
  1302. updatedUser.Username = user.Username
  1303. updatedUser.SetEmptySecretsIfNil()
  1304. if updatedUser.Password == redactedSecret {
  1305. updatedUser.Password = user.Password
  1306. }
  1307. updateEncryptedSecrets(&updatedUser, user.FsConfig.S3Config.AccessSecret, user.FsConfig.AzBlobConfig.AccountKey,
  1308. user.FsConfig.GCSConfig.Credentials, user.FsConfig.CryptConfig.Passphrase, user.FsConfig.SFTPConfig.Password,
  1309. user.FsConfig.SFTPConfig.PrivateKey)
  1310. err = dataprovider.UpdateUser(&updatedUser)
  1311. if err == nil {
  1312. if len(r.Form.Get("disconnect")) > 0 {
  1313. disconnectUser(user.Username)
  1314. }
  1315. http.Redirect(w, r, webUsersPath, http.StatusSeeOther)
  1316. } else {
  1317. renderUserPage(w, r, &user, userPageModeUpdate, err.Error())
  1318. }
  1319. }
  1320. func handleWebGetStatus(w http.ResponseWriter, r *http.Request) {
  1321. data := statusPage{
  1322. basePage: getBasePageData(pageStatusTitle, webStatusPath, r),
  1323. Status: getServicesStatus(),
  1324. }
  1325. renderTemplate(w, templateStatus, data)
  1326. }
  1327. func handleWebGetConnections(w http.ResponseWriter, r *http.Request) {
  1328. connectionStats := common.Connections.GetStats()
  1329. data := connectionsPage{
  1330. basePage: getBasePageData(pageConnectionsTitle, webConnectionsPath, r),
  1331. Connections: connectionStats,
  1332. }
  1333. renderTemplate(w, templateConnections, data)
  1334. }
  1335. func handleWebAddFolderGet(w http.ResponseWriter, r *http.Request) {
  1336. renderFolderPage(w, r, vfs.BaseVirtualFolder{}, folderPageModeAdd, "")
  1337. }
  1338. func handleWebAddFolderPost(w http.ResponseWriter, r *http.Request) {
  1339. r.Body = http.MaxBytesReader(w, r.Body, maxRequestSize)
  1340. folder := vfs.BaseVirtualFolder{}
  1341. err := r.ParseForm()
  1342. if err != nil {
  1343. renderFolderPage(w, r, folder, folderPageModeAdd, err.Error())
  1344. return
  1345. }
  1346. if err := verifyCSRFToken(r.Form.Get(csrfFormToken)); err != nil {
  1347. renderForbiddenPage(w, r, err.Error())
  1348. return
  1349. }
  1350. folder.MappedPath = r.Form.Get("mapped_path")
  1351. folder.Name = r.Form.Get("name")
  1352. folder.Description = r.Form.Get("description")
  1353. err = dataprovider.AddFolder(&folder)
  1354. if err == nil {
  1355. http.Redirect(w, r, webFoldersPath, http.StatusSeeOther)
  1356. } else {
  1357. renderFolderPage(w, r, folder, folderPageModeAdd, err.Error())
  1358. }
  1359. }
  1360. func handleWebUpdateFolderGet(w http.ResponseWriter, r *http.Request) {
  1361. name := getURLParam(r, "name")
  1362. folder, err := dataprovider.GetFolderByName(name)
  1363. if err == nil {
  1364. renderFolderPage(w, r, folder, folderPageModeUpdate, "")
  1365. } else if _, ok := err.(*dataprovider.RecordNotFoundError); ok {
  1366. renderNotFoundPage(w, r, err)
  1367. } else {
  1368. renderInternalServerErrorPage(w, r, err)
  1369. }
  1370. }
  1371. func handleWebUpdateFolderPost(w http.ResponseWriter, r *http.Request) {
  1372. r.Body = http.MaxBytesReader(w, r.Body, maxRequestSize)
  1373. name := getURLParam(r, "name")
  1374. folder, err := dataprovider.GetFolderByName(name)
  1375. if _, ok := err.(*dataprovider.RecordNotFoundError); ok {
  1376. renderNotFoundPage(w, r, err)
  1377. return
  1378. } else if err != nil {
  1379. renderInternalServerErrorPage(w, r, err)
  1380. return
  1381. }
  1382. err = r.ParseForm()
  1383. if err != nil {
  1384. renderFolderPage(w, r, folder, folderPageModeUpdate, err.Error())
  1385. return
  1386. }
  1387. if err := verifyCSRFToken(r.Form.Get(csrfFormToken)); err != nil {
  1388. renderForbiddenPage(w, r, err.Error())
  1389. return
  1390. }
  1391. folder.MappedPath = r.Form.Get("mapped_path")
  1392. folder.Description = r.Form.Get("description")
  1393. err = dataprovider.UpdateFolder(&folder)
  1394. if err != nil {
  1395. renderFolderPage(w, r, folder, folderPageModeUpdate, err.Error())
  1396. return
  1397. }
  1398. http.Redirect(w, r, webFoldersPath, http.StatusSeeOther)
  1399. }
  1400. func handleWebGetFolders(w http.ResponseWriter, r *http.Request) {
  1401. limit := defaultQueryLimit
  1402. if _, ok := r.URL.Query()["qlimit"]; ok {
  1403. var err error
  1404. limit, err = strconv.Atoi(r.URL.Query().Get("qlimit"))
  1405. if err != nil {
  1406. limit = defaultQueryLimit
  1407. }
  1408. }
  1409. folders := make([]vfs.BaseVirtualFolder, 0, limit)
  1410. for {
  1411. f, err := dataprovider.GetFolders(limit, len(folders), dataprovider.OrderASC)
  1412. if err != nil {
  1413. renderInternalServerErrorPage(w, r, err)
  1414. return
  1415. }
  1416. folders = append(folders, f...)
  1417. if len(f) < limit {
  1418. break
  1419. }
  1420. }
  1421. data := foldersPage{
  1422. basePage: getBasePageData(pageFoldersTitle, webFoldersPath, r),
  1423. Folders: folders,
  1424. }
  1425. renderTemplate(w, templateFolders, data)
  1426. }