web.go 45 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539
  1. package httpd
  2. import (
  3. "errors"
  4. "fmt"
  5. "html/template"
  6. "io/ioutil"
  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. ValidSSHLoginMethods []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. ValidSSHLoginMethods: dataprovider.ValidSSHLoginMethods,
  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. return filters
  607. }
  608. func getSecretFromFormField(r *http.Request, field string) *kms.Secret {
  609. secret := kms.NewPlainSecret(r.Form.Get(field))
  610. if strings.TrimSpace(secret.GetPayload()) == redactedSecret {
  611. secret.SetStatus(kms.SecretStatusRedacted)
  612. }
  613. if strings.TrimSpace(secret.GetPayload()) == "" {
  614. secret.SetStatus("")
  615. }
  616. return secret
  617. }
  618. func getS3Config(r *http.Request) (vfs.S3FsConfig, error) {
  619. var err error
  620. config := vfs.S3FsConfig{}
  621. config.Bucket = r.Form.Get("s3_bucket")
  622. config.Region = r.Form.Get("s3_region")
  623. config.AccessKey = r.Form.Get("s3_access_key")
  624. config.AccessSecret = getSecretFromFormField(r, "s3_access_secret")
  625. config.Endpoint = r.Form.Get("s3_endpoint")
  626. config.StorageClass = r.Form.Get("s3_storage_class")
  627. config.KeyPrefix = r.Form.Get("s3_key_prefix")
  628. config.UploadPartSize, err = strconv.ParseInt(r.Form.Get("s3_upload_part_size"), 10, 64)
  629. if err != nil {
  630. return config, err
  631. }
  632. config.UploadConcurrency, err = strconv.Atoi(r.Form.Get("s3_upload_concurrency"))
  633. return config, err
  634. }
  635. func getGCSConfig(r *http.Request) (vfs.GCSFsConfig, error) {
  636. var err error
  637. config := vfs.GCSFsConfig{}
  638. config.Bucket = r.Form.Get("gcs_bucket")
  639. config.StorageClass = r.Form.Get("gcs_storage_class")
  640. config.KeyPrefix = r.Form.Get("gcs_key_prefix")
  641. autoCredentials := r.Form.Get("gcs_auto_credentials")
  642. if autoCredentials != "" {
  643. config.AutomaticCredentials = 1
  644. } else {
  645. config.AutomaticCredentials = 0
  646. }
  647. credentials, _, err := r.FormFile("gcs_credential_file")
  648. if err == http.ErrMissingFile {
  649. return config, nil
  650. }
  651. if err != nil {
  652. return config, err
  653. }
  654. defer credentials.Close()
  655. fileBytes, err := ioutil.ReadAll(credentials)
  656. if err != nil || len(fileBytes) == 0 {
  657. if len(fileBytes) == 0 {
  658. err = errors.New("credentials file size must be greater than 0")
  659. }
  660. return config, err
  661. }
  662. config.Credentials = kms.NewPlainSecret(string(fileBytes))
  663. config.AutomaticCredentials = 0
  664. return config, err
  665. }
  666. func getSFTPConfig(r *http.Request) vfs.SFTPFsConfig {
  667. config := vfs.SFTPFsConfig{}
  668. config.Endpoint = r.Form.Get("sftp_endpoint")
  669. config.Username = r.Form.Get("sftp_username")
  670. config.Password = getSecretFromFormField(r, "sftp_password")
  671. config.PrivateKey = getSecretFromFormField(r, "sftp_private_key")
  672. fingerprintsFormValue := r.Form.Get("sftp_fingerprints")
  673. config.Fingerprints = getSliceFromDelimitedValues(fingerprintsFormValue, "\n")
  674. config.Prefix = r.Form.Get("sftp_prefix")
  675. return config
  676. }
  677. func getAzureConfig(r *http.Request) (vfs.AzBlobFsConfig, error) {
  678. var err error
  679. config := vfs.AzBlobFsConfig{}
  680. config.Container = r.Form.Get("az_container")
  681. config.AccountName = r.Form.Get("az_account_name")
  682. config.AccountKey = getSecretFromFormField(r, "az_account_key")
  683. config.SASURL = r.Form.Get("az_sas_url")
  684. config.Endpoint = r.Form.Get("az_endpoint")
  685. config.KeyPrefix = r.Form.Get("az_key_prefix")
  686. config.AccessTier = r.Form.Get("az_access_tier")
  687. config.UseEmulator = len(r.Form.Get("az_use_emulator")) > 0
  688. config.UploadPartSize, err = strconv.ParseInt(r.Form.Get("az_upload_part_size"), 10, 64)
  689. if err != nil {
  690. return config, err
  691. }
  692. config.UploadConcurrency, err = strconv.Atoi(r.Form.Get("az_upload_concurrency"))
  693. return config, err
  694. }
  695. func getFsConfigFromUserPostFields(r *http.Request) (dataprovider.Filesystem, error) {
  696. var fs dataprovider.Filesystem
  697. provider, err := strconv.Atoi(r.Form.Get("fs_provider"))
  698. if err != nil {
  699. provider = int(dataprovider.LocalFilesystemProvider)
  700. }
  701. fs.Provider = dataprovider.FilesystemProvider(provider)
  702. switch fs.Provider {
  703. case dataprovider.S3FilesystemProvider:
  704. config, err := getS3Config(r)
  705. if err != nil {
  706. return fs, err
  707. }
  708. fs.S3Config = config
  709. case dataprovider.AzureBlobFilesystemProvider:
  710. config, err := getAzureConfig(r)
  711. if err != nil {
  712. return fs, err
  713. }
  714. fs.AzBlobConfig = config
  715. case dataprovider.GCSFilesystemProvider:
  716. config, err := getGCSConfig(r)
  717. if err != nil {
  718. return fs, err
  719. }
  720. fs.GCSConfig = config
  721. case dataprovider.CryptedFilesystemProvider:
  722. fs.CryptConfig.Passphrase = getSecretFromFormField(r, "crypt_passphrase")
  723. case dataprovider.SFTPFilesystemProvider:
  724. fs.SFTPConfig = getSFTPConfig(r)
  725. }
  726. return fs, nil
  727. }
  728. func getAdminFromPostFields(r *http.Request) (dataprovider.Admin, error) {
  729. var admin dataprovider.Admin
  730. err := r.ParseForm()
  731. if err != nil {
  732. return admin, err
  733. }
  734. status, err := strconv.Atoi(r.Form.Get("status"))
  735. if err != nil {
  736. return admin, err
  737. }
  738. admin.Username = r.Form.Get("username")
  739. admin.Password = r.Form.Get("password")
  740. admin.Permissions = r.Form["permissions"]
  741. admin.Email = r.Form.Get("email")
  742. admin.Status = status
  743. admin.Filters.AllowList = getSliceFromDelimitedValues(r.Form.Get("allowed_ip"), ",")
  744. admin.AdditionalInfo = r.Form.Get("additional_info")
  745. return admin, nil
  746. }
  747. func replacePlaceholders(field string, replacements map[string]string) string {
  748. for k, v := range replacements {
  749. field = strings.ReplaceAll(field, k, v)
  750. }
  751. return field
  752. }
  753. func getFolderFromTemplate(folder vfs.BaseVirtualFolder, name string) vfs.BaseVirtualFolder {
  754. folder.Name = name
  755. replacements := make(map[string]string)
  756. replacements["%name%"] = folder.Name
  757. folder.MappedPath = replacePlaceholders(folder.MappedPath, replacements)
  758. return folder
  759. }
  760. func getCryptFsFromTemplate(fsConfig vfs.CryptFsConfig, replacements map[string]string) vfs.CryptFsConfig {
  761. if fsConfig.Passphrase != nil {
  762. if fsConfig.Passphrase.IsPlain() {
  763. payload := replacePlaceholders(fsConfig.Passphrase.GetPayload(), replacements)
  764. fsConfig.Passphrase = kms.NewPlainSecret(payload)
  765. }
  766. }
  767. return fsConfig
  768. }
  769. func getS3FsFromTemplate(fsConfig vfs.S3FsConfig, replacements map[string]string) vfs.S3FsConfig {
  770. fsConfig.KeyPrefix = replacePlaceholders(fsConfig.KeyPrefix, replacements)
  771. fsConfig.AccessKey = replacePlaceholders(fsConfig.AccessKey, replacements)
  772. if fsConfig.AccessSecret != nil && fsConfig.AccessSecret.IsPlain() {
  773. payload := replacePlaceholders(fsConfig.AccessSecret.GetPayload(), replacements)
  774. fsConfig.AccessSecret = kms.NewPlainSecret(payload)
  775. }
  776. return fsConfig
  777. }
  778. func getGCSFsFromTemplate(fsConfig vfs.GCSFsConfig, replacements map[string]string) vfs.GCSFsConfig {
  779. fsConfig.KeyPrefix = replacePlaceholders(fsConfig.KeyPrefix, replacements)
  780. return fsConfig
  781. }
  782. func getAzBlobFsFromTemplate(fsConfig vfs.AzBlobFsConfig, replacements map[string]string) vfs.AzBlobFsConfig {
  783. fsConfig.KeyPrefix = replacePlaceholders(fsConfig.KeyPrefix, replacements)
  784. fsConfig.AccountName = replacePlaceholders(fsConfig.AccountName, replacements)
  785. if fsConfig.AccountKey != nil && fsConfig.AccountKey.IsPlain() {
  786. payload := replacePlaceholders(fsConfig.AccountKey.GetPayload(), replacements)
  787. fsConfig.AccountKey = kms.NewPlainSecret(payload)
  788. }
  789. return fsConfig
  790. }
  791. func getSFTPFsFromTemplate(fsConfig vfs.SFTPFsConfig, replacements map[string]string) vfs.SFTPFsConfig {
  792. fsConfig.Prefix = replacePlaceholders(fsConfig.Prefix, replacements)
  793. fsConfig.Username = replacePlaceholders(fsConfig.Username, replacements)
  794. if fsConfig.Password != nil && fsConfig.Password.IsPlain() {
  795. payload := replacePlaceholders(fsConfig.Password.GetPayload(), replacements)
  796. fsConfig.Password = kms.NewPlainSecret(payload)
  797. }
  798. return fsConfig
  799. }
  800. func getUserFromTemplate(user dataprovider.User, template userTemplateFields) dataprovider.User {
  801. user.Username = template.Username
  802. user.Password = template.Password
  803. user.PublicKeys = nil
  804. if template.PublicKey != "" {
  805. user.PublicKeys = append(user.PublicKeys, template.PublicKey)
  806. }
  807. replacements := make(map[string]string)
  808. replacements["%username%"] = user.Username
  809. user.Password = replacePlaceholders(user.Password, replacements)
  810. replacements["%password%"] = user.Password
  811. user.HomeDir = replacePlaceholders(user.HomeDir, replacements)
  812. var vfolders []vfs.VirtualFolder
  813. for _, vfolder := range user.VirtualFolders {
  814. vfolder.Name = replacePlaceholders(vfolder.Name, replacements)
  815. vfolder.VirtualPath = replacePlaceholders(vfolder.VirtualPath, replacements)
  816. vfolders = append(vfolders, vfolder)
  817. }
  818. user.VirtualFolders = vfolders
  819. user.AdditionalInfo = replacePlaceholders(user.AdditionalInfo, replacements)
  820. switch user.FsConfig.Provider {
  821. case dataprovider.CryptedFilesystemProvider:
  822. user.FsConfig.CryptConfig = getCryptFsFromTemplate(user.FsConfig.CryptConfig, replacements)
  823. case dataprovider.S3FilesystemProvider:
  824. user.FsConfig.S3Config = getS3FsFromTemplate(user.FsConfig.S3Config, replacements)
  825. case dataprovider.GCSFilesystemProvider:
  826. user.FsConfig.GCSConfig = getGCSFsFromTemplate(user.FsConfig.GCSConfig, replacements)
  827. case dataprovider.AzureBlobFilesystemProvider:
  828. user.FsConfig.AzBlobConfig = getAzBlobFsFromTemplate(user.FsConfig.AzBlobConfig, replacements)
  829. case dataprovider.SFTPFilesystemProvider:
  830. user.FsConfig.SFTPConfig = getSFTPFsFromTemplate(user.FsConfig.SFTPConfig, replacements)
  831. }
  832. return user
  833. }
  834. func getUserFromPostFields(r *http.Request) (dataprovider.User, error) {
  835. var user dataprovider.User
  836. err := r.ParseMultipartForm(maxRequestSize)
  837. if err != nil {
  838. return user, err
  839. }
  840. publicKeysFormValue := r.Form.Get("public_keys")
  841. publicKeys := getSliceFromDelimitedValues(publicKeysFormValue, "\n")
  842. uid, err := strconv.Atoi(r.Form.Get("uid"))
  843. if err != nil {
  844. return user, err
  845. }
  846. gid, err := strconv.Atoi(r.Form.Get("gid"))
  847. if err != nil {
  848. return user, err
  849. }
  850. maxSessions, err := strconv.Atoi(r.Form.Get("max_sessions"))
  851. if err != nil {
  852. return user, err
  853. }
  854. quotaSize, err := strconv.ParseInt(r.Form.Get("quota_size"), 10, 64)
  855. if err != nil {
  856. return user, err
  857. }
  858. quotaFiles, err := strconv.Atoi(r.Form.Get("quota_files"))
  859. if err != nil {
  860. return user, err
  861. }
  862. bandwidthUL, err := strconv.ParseInt(r.Form.Get("upload_bandwidth"), 10, 64)
  863. if err != nil {
  864. return user, err
  865. }
  866. bandwidthDL, err := strconv.ParseInt(r.Form.Get("download_bandwidth"), 10, 64)
  867. if err != nil {
  868. return user, err
  869. }
  870. status, err := strconv.Atoi(r.Form.Get("status"))
  871. if err != nil {
  872. return user, err
  873. }
  874. expirationDateMillis := int64(0)
  875. expirationDateString := r.Form.Get("expiration_date")
  876. if len(strings.TrimSpace(expirationDateString)) > 0 {
  877. expirationDate, err := time.Parse(webDateTimeFormat, expirationDateString)
  878. if err != nil {
  879. return user, err
  880. }
  881. expirationDateMillis = utils.GetTimeAsMsSinceEpoch(expirationDate)
  882. }
  883. fsConfig, err := getFsConfigFromUserPostFields(r)
  884. if err != nil {
  885. return user, err
  886. }
  887. user = dataprovider.User{
  888. Username: r.Form.Get("username"),
  889. Password: r.Form.Get("password"),
  890. PublicKeys: publicKeys,
  891. HomeDir: r.Form.Get("home_dir"),
  892. VirtualFolders: getVirtualFoldersFromPostFields(r),
  893. UID: uid,
  894. GID: gid,
  895. Permissions: getUserPermissionsFromPostFields(r),
  896. MaxSessions: maxSessions,
  897. QuotaSize: quotaSize,
  898. QuotaFiles: quotaFiles,
  899. UploadBandwidth: bandwidthUL,
  900. DownloadBandwidth: bandwidthDL,
  901. Status: status,
  902. ExpirationDate: expirationDateMillis,
  903. Filters: getFiltersFromUserPostFields(r),
  904. FsConfig: fsConfig,
  905. AdditionalInfo: r.Form.Get("additional_info"),
  906. }
  907. maxFileSize, err := strconv.ParseInt(r.Form.Get("max_upload_file_size"), 10, 64)
  908. user.Filters.MaxUploadFileSize = maxFileSize
  909. return user, err
  910. }
  911. func renderLoginPage(w http.ResponseWriter, error string) {
  912. data := loginPage{
  913. CurrentURL: webLoginPath,
  914. Version: version.Get().Version,
  915. Error: error,
  916. CSRFToken: createCSRFToken(),
  917. }
  918. renderTemplate(w, templateLogin, data)
  919. }
  920. func handleWebAdminChangePwd(w http.ResponseWriter, r *http.Request) {
  921. renderChangePwdPage(w, r, "")
  922. }
  923. func handleWebAdminChangePwdPost(w http.ResponseWriter, r *http.Request) {
  924. r.Body = http.MaxBytesReader(w, r.Body, maxRequestSize)
  925. err := r.ParseForm()
  926. if err != nil {
  927. renderChangePwdPage(w, r, err.Error())
  928. return
  929. }
  930. if err := verifyCSRFToken(r.Form.Get(csrfFormToken)); err != nil {
  931. renderForbiddenPage(w, r, err.Error())
  932. return
  933. }
  934. err = doChangeAdminPassword(r, r.Form.Get("current_password"), r.Form.Get("new_password1"),
  935. r.Form.Get("new_password2"))
  936. if err != nil {
  937. renderChangePwdPage(w, r, err.Error())
  938. return
  939. }
  940. handleWebLogout(w, r)
  941. }
  942. func handleWebLogout(w http.ResponseWriter, r *http.Request) {
  943. c := jwtTokenClaims{}
  944. c.removeCookie(w, r)
  945. http.Redirect(w, r, webLoginPath, http.StatusFound)
  946. }
  947. func handleWebLogin(w http.ResponseWriter, r *http.Request) {
  948. renderLoginPage(w, "")
  949. }
  950. func handleWebMaintenance(w http.ResponseWriter, r *http.Request) {
  951. renderMaintenancePage(w, r, "")
  952. }
  953. func handleWebRestore(w http.ResponseWriter, r *http.Request) {
  954. err := r.ParseMultipartForm(MaxRestoreSize)
  955. if err != nil {
  956. renderMaintenancePage(w, r, err.Error())
  957. return
  958. }
  959. if err := verifyCSRFToken(r.Form.Get(csrfFormToken)); err != nil {
  960. renderForbiddenPage(w, r, err.Error())
  961. return
  962. }
  963. restoreMode, err := strconv.Atoi(r.Form.Get("mode"))
  964. if err != nil {
  965. renderMaintenancePage(w, r, err.Error())
  966. return
  967. }
  968. scanQuota, err := strconv.Atoi(r.Form.Get("quota"))
  969. if err != nil {
  970. renderMaintenancePage(w, r, err.Error())
  971. return
  972. }
  973. backupFile, _, err := r.FormFile("backup_file")
  974. if err != nil {
  975. renderMaintenancePage(w, r, err.Error())
  976. return
  977. }
  978. defer backupFile.Close()
  979. backupContent, err := ioutil.ReadAll(backupFile)
  980. if err != nil || len(backupContent) == 0 {
  981. if len(backupContent) == 0 {
  982. err = errors.New("backup file size must be greater than 0")
  983. }
  984. renderMaintenancePage(w, r, err.Error())
  985. return
  986. }
  987. if err := restoreBackup(backupContent, "", scanQuota, restoreMode); err != nil {
  988. renderMaintenancePage(w, r, err.Error())
  989. return
  990. }
  991. renderMessagePage(w, r, "Data restored", "", http.StatusOK, nil, "Your backup was successfully restored")
  992. }
  993. func handleGetWebAdmins(w http.ResponseWriter, r *http.Request) {
  994. limit := defaultQueryLimit
  995. if _, ok := r.URL.Query()["qlimit"]; ok {
  996. var err error
  997. limit, err = strconv.Atoi(r.URL.Query().Get("qlimit"))
  998. if err != nil {
  999. limit = defaultQueryLimit
  1000. }
  1001. }
  1002. admins := make([]dataprovider.Admin, 0, limit)
  1003. for {
  1004. a, err := dataprovider.GetAdmins(limit, len(admins), dataprovider.OrderASC)
  1005. if err != nil {
  1006. renderInternalServerErrorPage(w, r, err)
  1007. return
  1008. }
  1009. admins = append(admins, a...)
  1010. if len(a) < limit {
  1011. break
  1012. }
  1013. }
  1014. data := adminsPage{
  1015. basePage: getBasePageData(pageAdminsTitle, webAdminsPath, r),
  1016. Admins: admins,
  1017. }
  1018. renderTemplate(w, templateAdmins, data)
  1019. }
  1020. func handleWebAddAdminGet(w http.ResponseWriter, r *http.Request) {
  1021. admin := &dataprovider.Admin{Status: 1}
  1022. renderAddUpdateAdminPage(w, r, admin, "", true)
  1023. }
  1024. func handleWebUpdateAdminGet(w http.ResponseWriter, r *http.Request) {
  1025. username := getURLParam(r, "username")
  1026. admin, err := dataprovider.AdminExists(username)
  1027. if err == nil {
  1028. renderAddUpdateAdminPage(w, r, &admin, "", false)
  1029. } else if _, ok := err.(*dataprovider.RecordNotFoundError); ok {
  1030. renderNotFoundPage(w, r, err)
  1031. } else {
  1032. renderInternalServerErrorPage(w, r, err)
  1033. }
  1034. }
  1035. func handleWebAddAdminPost(w http.ResponseWriter, r *http.Request) {
  1036. r.Body = http.MaxBytesReader(w, r.Body, maxRequestSize)
  1037. admin, err := getAdminFromPostFields(r)
  1038. if err != nil {
  1039. renderAddUpdateAdminPage(w, r, &admin, err.Error(), true)
  1040. return
  1041. }
  1042. if err := verifyCSRFToken(r.Form.Get(csrfFormToken)); err != nil {
  1043. renderForbiddenPage(w, r, err.Error())
  1044. return
  1045. }
  1046. err = dataprovider.AddAdmin(&admin)
  1047. if err != nil {
  1048. renderAddUpdateAdminPage(w, r, &admin, err.Error(), true)
  1049. return
  1050. }
  1051. http.Redirect(w, r, webAdminsPath, http.StatusSeeOther)
  1052. }
  1053. func handleWebUpdateAdminPost(w http.ResponseWriter, r *http.Request) {
  1054. r.Body = http.MaxBytesReader(w, r.Body, maxRequestSize)
  1055. username := getURLParam(r, "username")
  1056. admin, err := dataprovider.AdminExists(username)
  1057. if _, ok := err.(*dataprovider.RecordNotFoundError); ok {
  1058. renderNotFoundPage(w, r, err)
  1059. return
  1060. } else if err != nil {
  1061. renderInternalServerErrorPage(w, r, err)
  1062. return
  1063. }
  1064. updatedAdmin, err := getAdminFromPostFields(r)
  1065. if err != nil {
  1066. renderAddUpdateAdminPage(w, r, &updatedAdmin, err.Error(), false)
  1067. return
  1068. }
  1069. if err := verifyCSRFToken(r.Form.Get(csrfFormToken)); err != nil {
  1070. renderForbiddenPage(w, r, err.Error())
  1071. return
  1072. }
  1073. updatedAdmin.ID = admin.ID
  1074. updatedAdmin.Username = admin.Username
  1075. if updatedAdmin.Password == "" {
  1076. updatedAdmin.Password = admin.Password
  1077. }
  1078. claims, err := getTokenClaims(r)
  1079. if err != nil || claims.Username == "" {
  1080. renderAddUpdateAdminPage(w, r, &updatedAdmin, fmt.Sprintf("Invalid token claims: %v", err), false)
  1081. return
  1082. }
  1083. if username == claims.Username {
  1084. if claims.isCriticalPermRemoved(updatedAdmin.Permissions) {
  1085. renderAddUpdateAdminPage(w, r, &updatedAdmin, "You cannot remove these permissions to yourself", false)
  1086. return
  1087. }
  1088. if updatedAdmin.Status == 0 {
  1089. renderAddUpdateAdminPage(w, r, &updatedAdmin, "You cannot disable yourself", false)
  1090. return
  1091. }
  1092. }
  1093. err = dataprovider.UpdateAdmin(&updatedAdmin)
  1094. if err != nil {
  1095. renderAddUpdateAdminPage(w, r, &admin, err.Error(), false)
  1096. return
  1097. }
  1098. http.Redirect(w, r, webAdminsPath, http.StatusSeeOther)
  1099. }
  1100. func handleGetWebUsers(w http.ResponseWriter, r *http.Request) {
  1101. limit := defaultQueryLimit
  1102. if _, ok := r.URL.Query()["qlimit"]; ok {
  1103. var err error
  1104. limit, err = strconv.Atoi(r.URL.Query().Get("qlimit"))
  1105. if err != nil {
  1106. limit = defaultQueryLimit
  1107. }
  1108. }
  1109. users := make([]dataprovider.User, 0, limit)
  1110. for {
  1111. u, err := dataprovider.GetUsers(limit, len(users), dataprovider.OrderASC)
  1112. if err != nil {
  1113. renderInternalServerErrorPage(w, r, err)
  1114. return
  1115. }
  1116. users = append(users, u...)
  1117. if len(u) < limit {
  1118. break
  1119. }
  1120. }
  1121. data := usersPage{
  1122. basePage: getBasePageData(pageUsersTitle, webUsersPath, r),
  1123. Users: users,
  1124. }
  1125. renderTemplate(w, templateUsers, data)
  1126. }
  1127. func handleWebTemplateFolderGet(w http.ResponseWriter, r *http.Request) {
  1128. if r.URL.Query().Get("from") != "" {
  1129. name := r.URL.Query().Get("from")
  1130. folder, err := dataprovider.GetFolderByName(name)
  1131. if err == nil {
  1132. renderFolderPage(w, r, folder, folderPageModeTemplate, "")
  1133. } else if _, ok := err.(*dataprovider.RecordNotFoundError); ok {
  1134. renderNotFoundPage(w, r, err)
  1135. } else {
  1136. renderInternalServerErrorPage(w, r, err)
  1137. }
  1138. } else {
  1139. folder := vfs.BaseVirtualFolder{}
  1140. renderFolderPage(w, r, folder, folderPageModeTemplate, "")
  1141. }
  1142. }
  1143. func handleWebTemplateFolderPost(w http.ResponseWriter, r *http.Request) {
  1144. r.Body = http.MaxBytesReader(w, r.Body, maxRequestSize)
  1145. templateFolder := vfs.BaseVirtualFolder{}
  1146. err := r.ParseForm()
  1147. if err != nil {
  1148. renderMessagePage(w, r, "Error parsing folders fields", "", http.StatusBadRequest, err, "")
  1149. return
  1150. }
  1151. if err := verifyCSRFToken(r.Form.Get(csrfFormToken)); err != nil {
  1152. renderForbiddenPage(w, r, err.Error())
  1153. return
  1154. }
  1155. templateFolder.MappedPath = r.Form.Get("mapped_path")
  1156. var dump dataprovider.BackupData
  1157. dump.Version = dataprovider.DumpVersion
  1158. foldersFields := getFoldersForTemplate(r)
  1159. for _, tmpl := range foldersFields {
  1160. f := getFolderFromTemplate(templateFolder, tmpl)
  1161. if err := dataprovider.ValidateFolder(&f); err != nil {
  1162. renderMessagePage(w, r, fmt.Sprintf("Error validating folder %#v", f.Name), "", http.StatusBadRequest, err, "")
  1163. return
  1164. }
  1165. dump.Folders = append(dump.Folders, f)
  1166. }
  1167. if len(dump.Folders) == 0 {
  1168. renderMessagePage(w, r, "No folders to export", "No valid folders found, export is not possible", http.StatusBadRequest, nil, "")
  1169. return
  1170. }
  1171. w.Header().Set("Content-Disposition", fmt.Sprintf("attachment; filename=\"sftpgo-%v-folders-from-template.json\"", len(dump.Folders)))
  1172. render.JSON(w, r, dump)
  1173. }
  1174. func handleWebTemplateUserGet(w http.ResponseWriter, r *http.Request) {
  1175. if r.URL.Query().Get("from") != "" {
  1176. username := r.URL.Query().Get("from")
  1177. user, err := dataprovider.UserExists(username)
  1178. if err == nil {
  1179. user.SetEmptySecrets()
  1180. renderUserPage(w, r, &user, userPageModeTemplate, "")
  1181. } else if _, ok := err.(*dataprovider.RecordNotFoundError); ok {
  1182. renderNotFoundPage(w, r, err)
  1183. } else {
  1184. renderInternalServerErrorPage(w, r, err)
  1185. }
  1186. } else {
  1187. user := dataprovider.User{Status: 1}
  1188. renderUserPage(w, r, &user, userPageModeTemplate, "")
  1189. }
  1190. }
  1191. func handleWebTemplateUserPost(w http.ResponseWriter, r *http.Request) {
  1192. r.Body = http.MaxBytesReader(w, r.Body, maxRequestSize)
  1193. templateUser, err := getUserFromPostFields(r)
  1194. if err != nil {
  1195. renderMessagePage(w, r, "Error parsing user fields", "", http.StatusBadRequest, err, "")
  1196. return
  1197. }
  1198. if err := verifyCSRFToken(r.Form.Get(csrfFormToken)); err != nil {
  1199. renderForbiddenPage(w, r, err.Error())
  1200. return
  1201. }
  1202. var dump dataprovider.BackupData
  1203. dump.Version = dataprovider.DumpVersion
  1204. userTmplFields := getUsersForTemplate(r)
  1205. for _, tmpl := range userTmplFields {
  1206. u := getUserFromTemplate(templateUser, tmpl)
  1207. if err := dataprovider.ValidateUser(&u); err != nil {
  1208. renderMessagePage(w, r, fmt.Sprintf("Error validating user %#v", u.Username), "", http.StatusBadRequest, err, "")
  1209. return
  1210. }
  1211. dump.Users = append(dump.Users, u)
  1212. for _, folder := range u.VirtualFolders {
  1213. if !dump.HasFolder(folder.Name) {
  1214. dump.Folders = append(dump.Folders, folder.BaseVirtualFolder)
  1215. }
  1216. }
  1217. }
  1218. if len(dump.Users) == 0 {
  1219. renderMessagePage(w, r, "No users to export", "No valid users found, export is not possible", http.StatusBadRequest, nil, "")
  1220. return
  1221. }
  1222. w.Header().Set("Content-Disposition", fmt.Sprintf("attachment; filename=\"sftpgo-%v-users-from-template.json\"", len(dump.Users)))
  1223. render.JSON(w, r, dump)
  1224. }
  1225. func handleWebAddUserGet(w http.ResponseWriter, r *http.Request) {
  1226. if r.URL.Query().Get("clone-from") != "" {
  1227. username := r.URL.Query().Get("clone-from")
  1228. user, err := dataprovider.UserExists(username)
  1229. if err == nil {
  1230. user.ID = 0
  1231. user.Username = ""
  1232. user.Password = ""
  1233. user.SetEmptySecrets()
  1234. renderUserPage(w, r, &user, userPageModeAdd, "")
  1235. } else if _, ok := err.(*dataprovider.RecordNotFoundError); ok {
  1236. renderNotFoundPage(w, r, err)
  1237. } else {
  1238. renderInternalServerErrorPage(w, r, err)
  1239. }
  1240. } else {
  1241. user := dataprovider.User{Status: 1}
  1242. renderUserPage(w, r, &user, userPageModeAdd, "")
  1243. }
  1244. }
  1245. func handleWebUpdateUserGet(w http.ResponseWriter, r *http.Request) {
  1246. username := getURLParam(r, "username")
  1247. user, err := dataprovider.UserExists(username)
  1248. if err == nil {
  1249. renderUserPage(w, r, &user, userPageModeUpdate, "")
  1250. } else if _, ok := err.(*dataprovider.RecordNotFoundError); ok {
  1251. renderNotFoundPage(w, r, err)
  1252. } else {
  1253. renderInternalServerErrorPage(w, r, err)
  1254. }
  1255. }
  1256. func handleWebAddUserPost(w http.ResponseWriter, r *http.Request) {
  1257. r.Body = http.MaxBytesReader(w, r.Body, maxRequestSize)
  1258. user, err := getUserFromPostFields(r)
  1259. if err != nil {
  1260. renderUserPage(w, r, &user, userPageModeAdd, err.Error())
  1261. return
  1262. }
  1263. if err := verifyCSRFToken(r.Form.Get(csrfFormToken)); err != nil {
  1264. renderForbiddenPage(w, r, err.Error())
  1265. return
  1266. }
  1267. err = dataprovider.AddUser(&user)
  1268. if err == nil {
  1269. http.Redirect(w, r, webUsersPath, http.StatusSeeOther)
  1270. } else {
  1271. renderUserPage(w, r, &user, userPageModeAdd, err.Error())
  1272. }
  1273. }
  1274. func handleWebUpdateUserPost(w http.ResponseWriter, r *http.Request) {
  1275. r.Body = http.MaxBytesReader(w, r.Body, maxRequestSize)
  1276. username := getURLParam(r, "username")
  1277. user, err := dataprovider.UserExists(username)
  1278. if _, ok := err.(*dataprovider.RecordNotFoundError); ok {
  1279. renderNotFoundPage(w, r, err)
  1280. return
  1281. } else if err != nil {
  1282. renderInternalServerErrorPage(w, r, err)
  1283. return
  1284. }
  1285. updatedUser, err := getUserFromPostFields(r)
  1286. if err != nil {
  1287. renderUserPage(w, r, &user, userPageModeUpdate, err.Error())
  1288. return
  1289. }
  1290. if err := verifyCSRFToken(r.Form.Get(csrfFormToken)); err != nil {
  1291. renderForbiddenPage(w, r, err.Error())
  1292. return
  1293. }
  1294. updatedUser.ID = user.ID
  1295. updatedUser.Username = user.Username
  1296. updatedUser.SetEmptySecretsIfNil()
  1297. if updatedUser.Password == redactedSecret {
  1298. updatedUser.Password = user.Password
  1299. }
  1300. updateEncryptedSecrets(&updatedUser, user.FsConfig.S3Config.AccessSecret, user.FsConfig.AzBlobConfig.AccountKey,
  1301. user.FsConfig.GCSConfig.Credentials, user.FsConfig.CryptConfig.Passphrase, user.FsConfig.SFTPConfig.Password,
  1302. user.FsConfig.SFTPConfig.PrivateKey)
  1303. err = dataprovider.UpdateUser(&updatedUser)
  1304. if err == nil {
  1305. if len(r.Form.Get("disconnect")) > 0 {
  1306. disconnectUser(user.Username)
  1307. }
  1308. http.Redirect(w, r, webUsersPath, http.StatusSeeOther)
  1309. } else {
  1310. renderUserPage(w, r, &user, userPageModeUpdate, err.Error())
  1311. }
  1312. }
  1313. func handleWebGetStatus(w http.ResponseWriter, r *http.Request) {
  1314. data := statusPage{
  1315. basePage: getBasePageData(pageStatusTitle, webStatusPath, r),
  1316. Status: getServicesStatus(),
  1317. }
  1318. renderTemplate(w, templateStatus, data)
  1319. }
  1320. func handleWebGetConnections(w http.ResponseWriter, r *http.Request) {
  1321. connectionStats := common.Connections.GetStats()
  1322. data := connectionsPage{
  1323. basePage: getBasePageData(pageConnectionsTitle, webConnectionsPath, r),
  1324. Connections: connectionStats,
  1325. }
  1326. renderTemplate(w, templateConnections, data)
  1327. }
  1328. func handleWebAddFolderGet(w http.ResponseWriter, r *http.Request) {
  1329. renderFolderPage(w, r, vfs.BaseVirtualFolder{}, folderPageModeAdd, "")
  1330. }
  1331. func handleWebAddFolderPost(w http.ResponseWriter, r *http.Request) {
  1332. r.Body = http.MaxBytesReader(w, r.Body, maxRequestSize)
  1333. folder := vfs.BaseVirtualFolder{}
  1334. err := r.ParseForm()
  1335. if err != nil {
  1336. renderFolderPage(w, r, folder, folderPageModeAdd, err.Error())
  1337. return
  1338. }
  1339. if err := verifyCSRFToken(r.Form.Get(csrfFormToken)); err != nil {
  1340. renderForbiddenPage(w, r, err.Error())
  1341. return
  1342. }
  1343. folder.MappedPath = r.Form.Get("mapped_path")
  1344. folder.Name = r.Form.Get("name")
  1345. err = dataprovider.AddFolder(&folder)
  1346. if err == nil {
  1347. http.Redirect(w, r, webFoldersPath, http.StatusSeeOther)
  1348. } else {
  1349. renderFolderPage(w, r, folder, folderPageModeAdd, err.Error())
  1350. }
  1351. }
  1352. func handleWebUpdateFolderGet(w http.ResponseWriter, r *http.Request) {
  1353. name := getURLParam(r, "name")
  1354. folder, err := dataprovider.GetFolderByName(name)
  1355. if err == nil {
  1356. renderFolderPage(w, r, folder, folderPageModeUpdate, "")
  1357. } else if _, ok := err.(*dataprovider.RecordNotFoundError); ok {
  1358. renderNotFoundPage(w, r, err)
  1359. } else {
  1360. renderInternalServerErrorPage(w, r, err)
  1361. }
  1362. }
  1363. func handleWebUpdateFolderPost(w http.ResponseWriter, r *http.Request) {
  1364. r.Body = http.MaxBytesReader(w, r.Body, maxRequestSize)
  1365. name := getURLParam(r, "name")
  1366. folder, err := dataprovider.GetFolderByName(name)
  1367. if _, ok := err.(*dataprovider.RecordNotFoundError); ok {
  1368. renderNotFoundPage(w, r, err)
  1369. return
  1370. } else if err != nil {
  1371. renderInternalServerErrorPage(w, r, err)
  1372. return
  1373. }
  1374. err = r.ParseForm()
  1375. if err != nil {
  1376. renderFolderPage(w, r, folder, folderPageModeUpdate, err.Error())
  1377. return
  1378. }
  1379. if err := verifyCSRFToken(r.Form.Get(csrfFormToken)); err != nil {
  1380. renderForbiddenPage(w, r, err.Error())
  1381. return
  1382. }
  1383. folder.MappedPath = r.Form.Get("mapped_path")
  1384. err = dataprovider.UpdateFolder(&folder)
  1385. if err != nil {
  1386. renderFolderPage(w, r, folder, folderPageModeUpdate, err.Error())
  1387. return
  1388. }
  1389. http.Redirect(w, r, webFoldersPath, http.StatusSeeOther)
  1390. }
  1391. func handleWebGetFolders(w http.ResponseWriter, r *http.Request) {
  1392. limit := defaultQueryLimit
  1393. if _, ok := r.URL.Query()["qlimit"]; ok {
  1394. var err error
  1395. limit, err = strconv.Atoi(r.URL.Query().Get("qlimit"))
  1396. if err != nil {
  1397. limit = defaultQueryLimit
  1398. }
  1399. }
  1400. folders := make([]vfs.BaseVirtualFolder, 0, limit)
  1401. for {
  1402. f, err := dataprovider.GetFolders(limit, len(folders), dataprovider.OrderASC)
  1403. if err != nil {
  1404. renderInternalServerErrorPage(w, r, err)
  1405. return
  1406. }
  1407. folders = append(folders, f...)
  1408. if len(f) < limit {
  1409. break
  1410. }
  1411. }
  1412. data := foldersPage{
  1413. basePage: getBasePageData(pageFoldersTitle, webFoldersPath, r),
  1414. Folders: folders,
  1415. }
  1416. renderTemplate(w, templateFolders, data)
  1417. }