A clean, Markdown-based publishing platform made for writers. Write together, and build a community. https://writefreely.org
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 

1008 lines
28 KiB

  1. /*
  2. * Copyright © 2018-2021 A Bunch Tell LLC.
  3. *
  4. * This file is part of WriteFreely.
  5. *
  6. * WriteFreely is free software: you can redistribute it and/or modify
  7. * it under the terms of the GNU Affero General Public License, included
  8. * in the LICENSE file in this source code package.
  9. */
  10. package writefreely
  11. import (
  12. "fmt"
  13. "html/template"
  14. "net/http"
  15. "net/url"
  16. "runtime/debug"
  17. "strconv"
  18. "strings"
  19. "time"
  20. "git.mills.io/prologic/go-gopher"
  21. "github.com/gorilla/sessions"
  22. "github.com/writeas/impart"
  23. "github.com/writeas/web-core/log"
  24. "github.com/writefreely/writefreely/config"
  25. "github.com/writefreely/writefreely/page"
  26. )
  27. // UserLevel represents the required user level for accessing an endpoint
  28. type UserLevel int
  29. const (
  30. UserLevelNoneType UserLevel = iota // user or not -- ignored
  31. UserLevelOptionalType // user or not -- object fetched if user
  32. UserLevelNoneRequiredType // non-user (required)
  33. UserLevelUserType // user (required)
  34. )
  35. func UserLevelNone(cfg *config.Config) UserLevel {
  36. return UserLevelNoneType
  37. }
  38. func UserLevelOptional(cfg *config.Config) UserLevel {
  39. return UserLevelOptionalType
  40. }
  41. func UserLevelNoneRequired(cfg *config.Config) UserLevel {
  42. return UserLevelNoneRequiredType
  43. }
  44. func UserLevelUser(cfg *config.Config) UserLevel {
  45. return UserLevelUserType
  46. }
  47. // UserLevelReader returns the permission level required for any route where
  48. // users can read published content.
  49. func UserLevelReader(cfg *config.Config) UserLevel {
  50. if cfg.App.Private {
  51. return UserLevelUserType
  52. }
  53. return UserLevelOptionalType
  54. }
  55. type (
  56. handlerFunc func(app *App, w http.ResponseWriter, r *http.Request) error
  57. gopherFunc func(app *App, w gopher.ResponseWriter, r *gopher.Request) error
  58. userHandlerFunc func(app *App, u *User, w http.ResponseWriter, r *http.Request) error
  59. userApperHandlerFunc func(apper Apper, u *User, w http.ResponseWriter, r *http.Request) error
  60. dataHandlerFunc func(app *App, w http.ResponseWriter, r *http.Request) ([]byte, string, error)
  61. authFunc func(app *App, r *http.Request) (*User, error)
  62. UserLevelFunc func(cfg *config.Config) UserLevel
  63. )
  64. type Handler struct {
  65. errors *ErrorPages
  66. sessionStore sessions.Store
  67. app Apper
  68. }
  69. // ErrorPages hold template HTML error pages for displaying errors to the user.
  70. // In each, there should be a defined template named "base".
  71. type ErrorPages struct {
  72. NotFound *template.Template
  73. Gone *template.Template
  74. InternalServerError *template.Template
  75. UnavailableError *template.Template
  76. Blank *template.Template
  77. }
  78. // NewHandler returns a new Handler instance, using the given StaticPage data,
  79. // and saving alias to the application's CookieStore.
  80. func NewHandler(apper Apper) *Handler {
  81. h := &Handler{
  82. errors: &ErrorPages{
  83. NotFound: template.Must(template.New("").Parse("{{define \"base\"}}<html><head><title>404</title></head><body><p>Not found.</p></body></html>{{end}}")),
  84. Gone: template.Must(template.New("").Parse("{{define \"base\"}}<html><head><title>410</title></head><body><p>Gone.</p></body></html>{{end}}")),
  85. InternalServerError: template.Must(template.New("").Parse("{{define \"base\"}}<html><head><title>500</title></head><body><p>Internal server error.</p></body></html>{{end}}")),
  86. UnavailableError: template.Must(template.New("").Parse("{{define \"base\"}}<html><head><title>503</title></head><body><p>Service is temporarily unavailable.</p></body></html>{{end}}")),
  87. Blank: template.Must(template.New("").Parse("{{define \"base\"}}<html><head><title>{{.Title}}</title></head><body><p>{{.Content}}</p></body></html>{{end}}")),
  88. },
  89. sessionStore: apper.App().SessionStore(),
  90. app: apper,
  91. }
  92. return h
  93. }
  94. // NewWFHandler returns a new Handler instance, using WriteFreely template files.
  95. // You MUST call writefreely.InitTemplates() before this.
  96. func NewWFHandler(apper Apper) *Handler {
  97. h := NewHandler(apper)
  98. h.SetErrorPages(&ErrorPages{
  99. NotFound: pages["404-general.tmpl"],
  100. Gone: pages["410.tmpl"],
  101. InternalServerError: pages["500.tmpl"],
  102. UnavailableError: pages["503.tmpl"],
  103. Blank: pages["blank.tmpl"],
  104. })
  105. return h
  106. }
  107. // SetErrorPages sets the given set of ErrorPages as templates for any errors
  108. // that come up.
  109. func (h *Handler) SetErrorPages(e *ErrorPages) {
  110. h.errors = e
  111. }
  112. // User handles requests made in the web application by the authenticated user.
  113. // This provides user-friendly HTML pages and actions that work in the browser.
  114. func (h *Handler) User(f userHandlerFunc) http.HandlerFunc {
  115. return func(w http.ResponseWriter, r *http.Request) {
  116. h.handleHTTPError(w, r, func() error {
  117. var status int
  118. start := time.Now()
  119. defer func() {
  120. if e := recover(); e != nil {
  121. log.Error("%s: %s", e, debug.Stack())
  122. h.errors.InternalServerError.ExecuteTemplate(w, "base", pageForReq(h.app.App(), r))
  123. status = http.StatusInternalServerError
  124. }
  125. log.Info(h.app.ReqLog(r, status, time.Since(start)))
  126. }()
  127. u := getUserSession(h.app.App(), r)
  128. if u == nil {
  129. err := ErrNotLoggedIn
  130. status = err.Status
  131. return err
  132. }
  133. err := f(h.app.App(), u, w, r)
  134. if err == nil {
  135. status = http.StatusOK
  136. } else if err, ok := err.(impart.HTTPError); ok {
  137. status = err.Status
  138. } else {
  139. status = http.StatusInternalServerError
  140. }
  141. return err
  142. }())
  143. }
  144. }
  145. // Admin handles requests on /admin routes
  146. func (h *Handler) Admin(f userHandlerFunc) http.HandlerFunc {
  147. return func(w http.ResponseWriter, r *http.Request) {
  148. h.handleHTTPError(w, r, func() error {
  149. var status int
  150. start := time.Now()
  151. defer func() {
  152. if e := recover(); e != nil {
  153. log.Error("%s: %s", e, debug.Stack())
  154. h.errors.InternalServerError.ExecuteTemplate(w, "base", pageForReq(h.app.App(), r))
  155. status = http.StatusInternalServerError
  156. }
  157. log.Info(h.app.ReqLog(r, status, time.Since(start)))
  158. }()
  159. u := getUserSession(h.app.App(), r)
  160. if u == nil || !u.IsAdmin() {
  161. err := impart.HTTPError{http.StatusNotFound, ""}
  162. status = err.Status
  163. return err
  164. }
  165. err := f(h.app.App(), u, w, r)
  166. if err == nil {
  167. status = http.StatusOK
  168. } else if err, ok := err.(impart.HTTPError); ok {
  169. status = err.Status
  170. } else {
  171. status = http.StatusInternalServerError
  172. }
  173. return err
  174. }())
  175. }
  176. }
  177. // AdminApper handles requests on /admin routes that require an Apper.
  178. func (h *Handler) AdminApper(f userApperHandlerFunc) http.HandlerFunc {
  179. return func(w http.ResponseWriter, r *http.Request) {
  180. h.handleHTTPError(w, r, func() error {
  181. var status int
  182. start := time.Now()
  183. defer func() {
  184. if e := recover(); e != nil {
  185. log.Error("%s: %s", e, debug.Stack())
  186. h.errors.InternalServerError.ExecuteTemplate(w, "base", pageForReq(h.app.App(), r))
  187. status = http.StatusInternalServerError
  188. }
  189. log.Info(h.app.ReqLog(r, status, time.Since(start)))
  190. }()
  191. u := getUserSession(h.app.App(), r)
  192. if u == nil || !u.IsAdmin() {
  193. err := impart.HTTPError{http.StatusNotFound, ""}
  194. status = err.Status
  195. return err
  196. }
  197. err := f(h.app, u, w, r)
  198. if err == nil {
  199. status = http.StatusOK
  200. } else if err, ok := err.(impart.HTTPError); ok {
  201. status = err.Status
  202. } else {
  203. status = http.StatusInternalServerError
  204. }
  205. return err
  206. }())
  207. }
  208. }
  209. func apiAuth(app *App, r *http.Request) (*User, error) {
  210. // Authorize user from Authorization header
  211. t := r.Header.Get("Authorization")
  212. if t == "" {
  213. return nil, ErrNoAccessToken
  214. }
  215. u := &User{ID: app.db.GetUserID(t)}
  216. if u.ID == -1 {
  217. return nil, ErrBadAccessToken
  218. }
  219. return u, nil
  220. }
  221. // optionaAPIAuth is used for endpoints that accept authenticated requests via
  222. // Authorization header or cookie, unlike apiAuth. It returns a different err
  223. // in the case where no Authorization header is present.
  224. func optionalAPIAuth(app *App, r *http.Request) (*User, error) {
  225. // Authorize user from Authorization header
  226. t := r.Header.Get("Authorization")
  227. if t == "" {
  228. return nil, ErrNotLoggedIn
  229. }
  230. u := &User{ID: app.db.GetUserID(t)}
  231. if u.ID == -1 {
  232. return nil, ErrBadAccessToken
  233. }
  234. return u, nil
  235. }
  236. func webAuth(app *App, r *http.Request) (*User, error) {
  237. u := getUserSession(app, r)
  238. if u == nil {
  239. return nil, ErrNotLoggedIn
  240. }
  241. return u, nil
  242. }
  243. // UserAPI handles requests made in the API by the authenticated user.
  244. // This provides user-friendly HTML pages and actions that work in the browser.
  245. func (h *Handler) UserAPI(f userHandlerFunc) http.HandlerFunc {
  246. return h.UserAll(false, f, apiAuth)
  247. }
  248. // UserWebAPI handles endpoints that accept a user authorized either via the web (cookies) or an Authorization header.
  249. func (h *Handler) UserWebAPI(f userHandlerFunc) http.HandlerFunc {
  250. return h.UserAll(false, f, func(app *App, r *http.Request) (*User, error) {
  251. // Authorize user via cookies
  252. u := getUserSession(app, r)
  253. if u != nil {
  254. return u, nil
  255. }
  256. // Fall back to access token, since user isn't logged in via web
  257. var err error
  258. u, err = apiAuth(app, r)
  259. if err != nil {
  260. return nil, err
  261. }
  262. return u, nil
  263. })
  264. }
  265. func (h *Handler) UserAll(web bool, f userHandlerFunc, a authFunc) http.HandlerFunc {
  266. return func(w http.ResponseWriter, r *http.Request) {
  267. handleFunc := func() error {
  268. var status int
  269. start := time.Now()
  270. defer func() {
  271. if e := recover(); e != nil {
  272. log.Error("%s: %s", e, debug.Stack())
  273. impart.WriteError(w, impart.HTTPError{http.StatusInternalServerError, "Something didn't work quite right."})
  274. status = 500
  275. }
  276. log.Info(h.app.ReqLog(r, status, time.Since(start)))
  277. }()
  278. u, err := a(h.app.App(), r)
  279. if err != nil {
  280. if err, ok := err.(impart.HTTPError); ok {
  281. status = err.Status
  282. } else {
  283. status = 500
  284. }
  285. return err
  286. }
  287. err = f(h.app.App(), u, w, r)
  288. if err == nil {
  289. status = 200
  290. } else if err, ok := err.(impart.HTTPError); ok {
  291. status = err.Status
  292. } else {
  293. status = 500
  294. }
  295. return err
  296. }
  297. if web {
  298. h.handleHTTPError(w, r, handleFunc())
  299. } else {
  300. h.handleError(w, r, handleFunc())
  301. }
  302. }
  303. }
  304. func (h *Handler) RedirectOnErr(f handlerFunc, loc string) handlerFunc {
  305. return func(app *App, w http.ResponseWriter, r *http.Request) error {
  306. err := f(app, w, r)
  307. if err != nil {
  308. if ie, ok := err.(impart.HTTPError); ok {
  309. // Override default redirect with returned error's, if it's a
  310. // redirect error.
  311. if ie.Status == http.StatusFound {
  312. return ie
  313. }
  314. }
  315. return impart.HTTPError{http.StatusFound, loc}
  316. }
  317. return nil
  318. }
  319. }
  320. func (h *Handler) Page(n string) http.HandlerFunc {
  321. return h.Web(func(app *App, w http.ResponseWriter, r *http.Request) error {
  322. t, ok := pages[n]
  323. if !ok {
  324. return impart.HTTPError{http.StatusNotFound, "Page not found."}
  325. }
  326. sp := pageForReq(app, r)
  327. err := t.ExecuteTemplate(w, "base", sp)
  328. if err != nil {
  329. log.Error("Unable to render page: %v", err)
  330. }
  331. return err
  332. }, UserLevelOptional)
  333. }
  334. func (h *Handler) WebErrors(f handlerFunc, ul UserLevelFunc) http.HandlerFunc {
  335. return func(w http.ResponseWriter, r *http.Request) {
  336. // TODO: factor out this logic shared with Web()
  337. h.handleHTTPError(w, r, func() error {
  338. var status int
  339. start := time.Now()
  340. defer func() {
  341. if e := recover(); e != nil {
  342. u := getUserSession(h.app.App(), r)
  343. username := "None"
  344. if u != nil {
  345. username = u.Username
  346. }
  347. log.Error("User: %s\n\n%s: %s", username, e, debug.Stack())
  348. h.errors.InternalServerError.ExecuteTemplate(w, "base", pageForReq(h.app.App(), r))
  349. status = 500
  350. }
  351. log.Info(h.app.ReqLog(r, status, time.Since(start)))
  352. }()
  353. var session *sessions.Session
  354. var err error
  355. if ul(h.app.App().cfg) != UserLevelNoneType {
  356. session, err = h.sessionStore.Get(r, cookieName)
  357. if err != nil && (ul(h.app.App().cfg) == UserLevelNoneRequiredType || ul(h.app.App().cfg) == UserLevelUserType) {
  358. // Cookie is required, but we can ignore this error
  359. log.Error("Handler: Unable to get session (for user permission %d); ignoring: %v", ul(h.app.App().cfg), err)
  360. }
  361. _, gotUser := session.Values[cookieUserVal].(*User)
  362. if ul(h.app.App().cfg) == UserLevelNoneRequiredType && gotUser {
  363. to := correctPageFromLoginAttempt(r)
  364. log.Info("Handler: Required NO user, but got one. Redirecting to %s", to)
  365. err := impart.HTTPError{http.StatusFound, to}
  366. status = err.Status
  367. return err
  368. } else if ul(h.app.App().cfg) == UserLevelUserType && !gotUser {
  369. log.Info("Handler: Required a user, but DIDN'T get one. Sending not logged in.")
  370. err := ErrNotLoggedIn
  371. status = err.Status
  372. return err
  373. }
  374. }
  375. // TODO: pass User object to function
  376. err = f(h.app.App(), w, r)
  377. if err == nil {
  378. status = 200
  379. } else if httpErr, ok := err.(impart.HTTPError); ok {
  380. status = httpErr.Status
  381. if status < 300 || status > 399 {
  382. addSessionFlash(h.app.App(), w, r, httpErr.Message, session)
  383. return impart.HTTPError{http.StatusFound, r.Referer()}
  384. }
  385. } else {
  386. e := fmt.Sprintf("[Web handler] 500: %v", err)
  387. if !strings.HasSuffix(e, "write: broken pipe") {
  388. log.Error(e)
  389. } else {
  390. log.Error(e)
  391. }
  392. log.Info("Web handler internal error render")
  393. h.errors.InternalServerError.ExecuteTemplate(w, "base", pageForReq(h.app.App(), r))
  394. status = 500
  395. }
  396. return err
  397. }())
  398. }
  399. }
  400. func (h *Handler) CollectionPostOrStatic(w http.ResponseWriter, r *http.Request) {
  401. if strings.Contains(r.URL.Path, ".") && !isRaw(r) {
  402. start := time.Now()
  403. status := 200
  404. defer func() {
  405. log.Info(h.app.ReqLog(r, status, time.Since(start)))
  406. }()
  407. // Serve static file
  408. h.app.App().shttp.ServeHTTP(w, r)
  409. return
  410. }
  411. h.Web(viewCollectionPost, UserLevelReader)(w, r)
  412. }
  413. // Web handles requests made in the web application. This provides user-
  414. // friendly HTML pages and actions that work in the browser.
  415. func (h *Handler) Web(f handlerFunc, ul UserLevelFunc) http.HandlerFunc {
  416. return func(w http.ResponseWriter, r *http.Request) {
  417. h.handleHTTPError(w, r, func() error {
  418. var status int
  419. start := time.Now()
  420. defer func() {
  421. if e := recover(); e != nil {
  422. u := getUserSession(h.app.App(), r)
  423. username := "None"
  424. if u != nil {
  425. username = u.Username
  426. }
  427. log.Error("User: %s\n\n%s: %s", username, e, debug.Stack())
  428. log.Info("Web deferred internal error render")
  429. h.errors.InternalServerError.ExecuteTemplate(w, "base", pageForReq(h.app.App(), r))
  430. status = 500
  431. }
  432. log.Info(h.app.ReqLog(r, status, time.Since(start)))
  433. }()
  434. if ul(h.app.App().cfg) != UserLevelNoneType {
  435. session, err := h.sessionStore.Get(r, cookieName)
  436. if err != nil && (ul(h.app.App().cfg) == UserLevelNoneRequiredType || ul(h.app.App().cfg) == UserLevelUserType) {
  437. // Cookie is required, but we can ignore this error
  438. log.Error("Handler: Unable to get session (for user permission %d); ignoring: %v", ul(h.app.App().cfg), err)
  439. }
  440. _, gotUser := session.Values[cookieUserVal].(*User)
  441. if ul(h.app.App().cfg) == UserLevelNoneRequiredType && gotUser {
  442. to := correctPageFromLoginAttempt(r)
  443. log.Info("Handler: Required NO user, but got one. Redirecting to %s", to)
  444. err := impart.HTTPError{http.StatusFound, to}
  445. status = err.Status
  446. return err
  447. } else if ul(h.app.App().cfg) == UserLevelUserType && !gotUser {
  448. log.Info("Handler: Required a user, but DIDN'T get one. Sending not logged in.")
  449. err := ErrNotLoggedIn
  450. status = err.Status
  451. return err
  452. }
  453. }
  454. // TODO: pass User object to function
  455. err := f(h.app.App(), w, r)
  456. if err == nil {
  457. status = 200
  458. } else if httpErr, ok := err.(impart.HTTPError); ok {
  459. status = httpErr.Status
  460. } else {
  461. e := fmt.Sprintf("[Web handler] 500: %v", err)
  462. log.Error(e)
  463. log.Info("Web internal error render")
  464. h.errors.InternalServerError.ExecuteTemplate(w, "base", pageForReq(h.app.App(), r))
  465. status = 500
  466. }
  467. return err
  468. }())
  469. }
  470. }
  471. func (h *Handler) All(f handlerFunc) http.HandlerFunc {
  472. return func(w http.ResponseWriter, r *http.Request) {
  473. h.handleError(w, r, func() error {
  474. // TODO: return correct "success" status
  475. status := 200
  476. start := time.Now()
  477. defer func() {
  478. if e := recover(); e != nil {
  479. log.Error("%s:\n%s", e, debug.Stack())
  480. impart.WriteError(w, impart.HTTPError{http.StatusInternalServerError, "Something didn't work quite right."})
  481. status = 500
  482. }
  483. log.Info(h.app.ReqLog(r, status, time.Since(start)))
  484. }()
  485. // TODO: do any needed authentication
  486. err := f(h.app.App(), w, r)
  487. if err != nil {
  488. if err, ok := err.(impart.HTTPError); ok {
  489. status = err.Status
  490. } else {
  491. status = 500
  492. }
  493. }
  494. return err
  495. }())
  496. }
  497. }
  498. func (h *Handler) PlainTextAPI(f handlerFunc) http.HandlerFunc {
  499. return func(w http.ResponseWriter, r *http.Request) {
  500. h.handleTextError(w, r, func() error {
  501. // TODO: return correct "success" status
  502. status := 200
  503. start := time.Now()
  504. defer func() {
  505. if e := recover(); e != nil {
  506. log.Error("%s:\n%s", e, debug.Stack())
  507. status = http.StatusInternalServerError
  508. w.WriteHeader(status)
  509. fmt.Fprintf(w, "Something didn't work quite right. The robots have alerted the humans.")
  510. }
  511. log.Info(fmt.Sprintf("\"%s %s\" %d %s \"%s\" \"%s\"", r.Method, r.RequestURI, status, time.Since(start), r.UserAgent(), r.Host))
  512. }()
  513. err := f(h.app.App(), w, r)
  514. if err != nil {
  515. if err, ok := err.(impart.HTTPError); ok {
  516. status = err.Status
  517. } else {
  518. status = http.StatusInternalServerError
  519. }
  520. }
  521. return err
  522. }())
  523. }
  524. }
  525. func (h *Handler) OAuth(f handlerFunc) http.HandlerFunc {
  526. return func(w http.ResponseWriter, r *http.Request) {
  527. h.handleOAuthError(w, r, func() error {
  528. // TODO: return correct "success" status
  529. status := 200
  530. start := time.Now()
  531. defer func() {
  532. if e := recover(); e != nil {
  533. log.Error("%s:\n%s", e, debug.Stack())
  534. impart.WriteError(w, impart.HTTPError{http.StatusInternalServerError, "Something didn't work quite right."})
  535. status = 500
  536. }
  537. log.Info(h.app.ReqLog(r, status, time.Since(start)))
  538. }()
  539. err := f(h.app.App(), w, r)
  540. if err != nil {
  541. if err, ok := err.(impart.HTTPError); ok {
  542. status = err.Status
  543. } else {
  544. status = 500
  545. }
  546. }
  547. return err
  548. }())
  549. }
  550. }
  551. func (h *Handler) AllReader(f handlerFunc) http.HandlerFunc {
  552. return func(w http.ResponseWriter, r *http.Request) {
  553. h.handleError(w, r, func() error {
  554. status := 200
  555. start := time.Now()
  556. defer func() {
  557. if e := recover(); e != nil {
  558. log.Error("%s:\n%s", e, debug.Stack())
  559. impart.WriteError(w, impart.HTTPError{http.StatusInternalServerError, "Something didn't work quite right."})
  560. status = 500
  561. }
  562. log.Info(h.app.ReqLog(r, status, time.Since(start)))
  563. }()
  564. // Allow any origin, as public endpoints are handled in here
  565. w.Header().Set("Access-Control-Allow-Origin", "*")
  566. if h.app.App().cfg.App.Private {
  567. // This instance is private, so ensure it's being accessed by a valid user
  568. // Check if authenticated with an access token
  569. _, apiErr := optionalAPIAuth(h.app.App(), r)
  570. if apiErr != nil {
  571. if err, ok := apiErr.(impart.HTTPError); ok {
  572. status = err.Status
  573. } else {
  574. status = 500
  575. }
  576. if apiErr == ErrNotLoggedIn {
  577. // Fall back to web auth since there was no access token given
  578. _, err := webAuth(h.app.App(), r)
  579. if err != nil {
  580. if err, ok := apiErr.(impart.HTTPError); ok {
  581. status = err.Status
  582. } else {
  583. status = 500
  584. }
  585. return err
  586. }
  587. } else {
  588. return apiErr
  589. }
  590. }
  591. }
  592. err := f(h.app.App(), w, r)
  593. if err != nil {
  594. if err, ok := err.(impart.HTTPError); ok {
  595. status = err.Status
  596. } else {
  597. status = 500
  598. }
  599. }
  600. return err
  601. }())
  602. }
  603. }
  604. func (h *Handler) Download(f dataHandlerFunc, ul UserLevelFunc) http.HandlerFunc {
  605. return func(w http.ResponseWriter, r *http.Request) {
  606. h.handleHTTPError(w, r, func() error {
  607. var status int
  608. start := time.Now()
  609. defer func() {
  610. if e := recover(); e != nil {
  611. log.Error("%s: %s", e, debug.Stack())
  612. h.errors.InternalServerError.ExecuteTemplate(w, "base", pageForReq(h.app.App(), r))
  613. status = 500
  614. }
  615. log.Info(h.app.ReqLog(r, status, time.Since(start)))
  616. }()
  617. data, filename, err := f(h.app.App(), w, r)
  618. if err != nil {
  619. if err, ok := err.(impart.HTTPError); ok {
  620. status = err.Status
  621. } else {
  622. status = 500
  623. }
  624. return err
  625. }
  626. ext := ".json"
  627. ct := "application/json"
  628. if strings.HasSuffix(r.URL.Path, ".csv") {
  629. ext = ".csv"
  630. ct = "text/csv"
  631. } else if strings.HasSuffix(r.URL.Path, ".zip") {
  632. ext = ".zip"
  633. ct = "application/zip"
  634. }
  635. w.Header().Set("Content-Disposition", fmt.Sprintf("attachment; filename=%s%s", filename, ext))
  636. w.Header().Set("Content-Type", ct)
  637. w.Header().Set("Content-Length", strconv.Itoa(len(data)))
  638. fmt.Fprint(w, string(data))
  639. status = 200
  640. return nil
  641. }())
  642. }
  643. }
  644. func (h *Handler) Redirect(url string, ul UserLevelFunc) http.HandlerFunc {
  645. return func(w http.ResponseWriter, r *http.Request) {
  646. h.handleHTTPError(w, r, func() error {
  647. start := time.Now()
  648. var status int
  649. if ul(h.app.App().cfg) != UserLevelNoneType {
  650. session, err := h.sessionStore.Get(r, cookieName)
  651. if err != nil && (ul(h.app.App().cfg) == UserLevelNoneRequiredType || ul(h.app.App().cfg) == UserLevelUserType) {
  652. // Cookie is required, but we can ignore this error
  653. log.Error("Handler: Unable to get session (for user permission %d); ignoring: %v", ul(h.app.App().cfg), err)
  654. }
  655. _, gotUser := session.Values[cookieUserVal].(*User)
  656. if ul(h.app.App().cfg) == UserLevelNoneRequiredType && gotUser {
  657. to := correctPageFromLoginAttempt(r)
  658. log.Info("Handler: Required NO user, but got one. Redirecting to %s", to)
  659. err := impart.HTTPError{http.StatusFound, to}
  660. status = err.Status
  661. return err
  662. } else if ul(h.app.App().cfg) == UserLevelUserType && !gotUser {
  663. log.Info("Handler: Required a user, but DIDN'T get one. Sending not logged in.")
  664. err := ErrNotLoggedIn
  665. status = err.Status
  666. return err
  667. }
  668. }
  669. status = sendRedirect(w, http.StatusFound, url)
  670. log.Info(h.app.ReqLog(r, status, time.Since(start)))
  671. return nil
  672. }())
  673. }
  674. }
  675. func (h *Handler) handleHTTPError(w http.ResponseWriter, r *http.Request, err error) {
  676. if err == nil {
  677. return
  678. }
  679. if err, ok := err.(impart.HTTPError); ok {
  680. if err.Status >= 300 && err.Status < 400 {
  681. sendRedirect(w, err.Status, err.Message)
  682. return
  683. } else if err.Status == http.StatusUnauthorized {
  684. q := ""
  685. if r.URL.RawQuery != "" {
  686. q = url.QueryEscape("?" + r.URL.RawQuery)
  687. }
  688. sendRedirect(w, http.StatusFound, "/login?to="+r.URL.Path+q)
  689. return
  690. } else if err.Status == http.StatusGone {
  691. w.WriteHeader(err.Status)
  692. p := &struct {
  693. page.StaticPage
  694. Content *template.HTML
  695. }{
  696. StaticPage: pageForReq(h.app.App(), r),
  697. }
  698. if err.Message != "" {
  699. co := template.HTML(err.Message)
  700. p.Content = &co
  701. }
  702. h.errors.Gone.ExecuteTemplate(w, "base", p)
  703. return
  704. } else if err.Status == http.StatusNotFound {
  705. w.WriteHeader(err.Status)
  706. if strings.Contains(r.Header.Get("Accept"), "application/activity+json") {
  707. // This is a fediverse request; simply return the header
  708. return
  709. }
  710. h.errors.NotFound.ExecuteTemplate(w, "base", pageForReq(h.app.App(), r))
  711. return
  712. } else if err.Status == http.StatusInternalServerError {
  713. w.WriteHeader(err.Status)
  714. log.Info("handleHTTPErorr internal error render")
  715. h.errors.InternalServerError.ExecuteTemplate(w, "base", pageForReq(h.app.App(), r))
  716. return
  717. } else if err.Status == http.StatusServiceUnavailable {
  718. w.WriteHeader(err.Status)
  719. h.errors.UnavailableError.ExecuteTemplate(w, "base", pageForReq(h.app.App(), r))
  720. return
  721. } else if err.Status == http.StatusAccepted {
  722. impart.WriteSuccess(w, "", err.Status)
  723. return
  724. } else {
  725. p := &struct {
  726. page.StaticPage
  727. Title string
  728. Content template.HTML
  729. }{
  730. pageForReq(h.app.App(), r),
  731. fmt.Sprintf("Uh oh (%d)", err.Status),
  732. template.HTML(fmt.Sprintf("<p style=\"text-align: center\" class=\"introduction\">%s</p>", err.Message)),
  733. }
  734. h.errors.Blank.ExecuteTemplate(w, "base", p)
  735. return
  736. }
  737. impart.WriteError(w, err)
  738. return
  739. }
  740. impart.WriteError(w, impart.HTTPError{http.StatusInternalServerError, "This is an unhelpful error message for a miscellaneous internal error."})
  741. }
  742. func (h *Handler) handleError(w http.ResponseWriter, r *http.Request, err error) {
  743. if err == nil {
  744. return
  745. }
  746. if err, ok := err.(impart.HTTPError); ok {
  747. if err.Status >= 300 && err.Status < 400 {
  748. sendRedirect(w, err.Status, err.Message)
  749. return
  750. }
  751. // if strings.Contains(r.Header.Get("Accept"), "text/html") {
  752. impart.WriteError(w, err)
  753. // }
  754. return
  755. }
  756. if IsJSON(r) {
  757. impart.WriteError(w, impart.HTTPError{http.StatusInternalServerError, "This is an unhelpful error message for a miscellaneous internal error."})
  758. return
  759. }
  760. h.errors.InternalServerError.ExecuteTemplate(w, "base", pageForReq(h.app.App(), r))
  761. }
  762. func (h *Handler) handleTextError(w http.ResponseWriter, r *http.Request, err error) {
  763. if err == nil {
  764. return
  765. }
  766. if err, ok := err.(impart.HTTPError); ok {
  767. if err.Status >= 300 && err.Status < 400 {
  768. sendRedirect(w, err.Status, err.Message)
  769. return
  770. }
  771. w.WriteHeader(err.Status)
  772. fmt.Fprintf(w, http.StatusText(err.Status))
  773. return
  774. }
  775. w.WriteHeader(http.StatusInternalServerError)
  776. fmt.Fprintf(w, "This is an unhelpful error message for a miscellaneous internal error.")
  777. }
  778. func (h *Handler) handleOAuthError(w http.ResponseWriter, r *http.Request, err error) {
  779. if err == nil {
  780. return
  781. }
  782. if err, ok := err.(impart.HTTPError); ok {
  783. if err.Status >= 300 && err.Status < 400 {
  784. sendRedirect(w, err.Status, err.Message)
  785. return
  786. }
  787. impart.WriteOAuthError(w, err)
  788. return
  789. }
  790. impart.WriteOAuthError(w, impart.HTTPError{http.StatusInternalServerError, "This is an unhelpful error message for a miscellaneous internal error."})
  791. return
  792. }
  793. func correctPageFromLoginAttempt(r *http.Request) string {
  794. to := r.FormValue("to")
  795. if to == "" {
  796. to = "/"
  797. } else if !strings.HasPrefix(to, "/") {
  798. to = "/" + to
  799. }
  800. return to
  801. }
  802. func (h *Handler) LogHandlerFunc(f http.HandlerFunc) http.HandlerFunc {
  803. return func(w http.ResponseWriter, r *http.Request) {
  804. h.handleHTTPError(w, r, func() error {
  805. status := 200
  806. start := time.Now()
  807. defer func() {
  808. if e := recover(); e != nil {
  809. log.Error("Handler.LogHandlerFunc\n\n%s: %s", e, debug.Stack())
  810. h.errors.InternalServerError.ExecuteTemplate(w, "base", pageForReq(h.app.App(), r))
  811. status = 500
  812. }
  813. // TODO: log actual status code returned
  814. log.Info(h.app.ReqLog(r, status, time.Since(start)))
  815. }()
  816. if h.app.App().cfg.App.Private {
  817. // This instance is private, so ensure it's being accessed by a valid user
  818. // Check if authenticated with an access token
  819. _, apiErr := optionalAPIAuth(h.app.App(), r)
  820. if apiErr != nil {
  821. if err, ok := apiErr.(impart.HTTPError); ok {
  822. status = err.Status
  823. } else {
  824. status = 500
  825. }
  826. if apiErr == ErrNotLoggedIn {
  827. // Fall back to web auth since there was no access token given
  828. _, err := webAuth(h.app.App(), r)
  829. if err != nil {
  830. if err, ok := apiErr.(impart.HTTPError); ok {
  831. status = err.Status
  832. } else {
  833. status = 500
  834. }
  835. return err
  836. }
  837. } else {
  838. return apiErr
  839. }
  840. }
  841. }
  842. f(w, r)
  843. return nil
  844. }())
  845. }
  846. }
  847. func (h *Handler) Gopher(f gopherFunc) gopher.HandlerFunc {
  848. return func(w gopher.ResponseWriter, r *gopher.Request) {
  849. defer func() {
  850. if e := recover(); e != nil {
  851. log.Error("%s: %s", e, debug.Stack())
  852. w.WriteError("An internal error occurred")
  853. }
  854. log.Info("gopher: %s", r.Selector)
  855. }()
  856. err := f(h.app.App(), w, r)
  857. if err != nil {
  858. log.Error("failed: %s", err)
  859. w.WriteError("the page failed for some reason (see logs)")
  860. }
  861. }
  862. }
  863. func sendRedirect(w http.ResponseWriter, code int, location string) int {
  864. w.Header().Set("Location", location)
  865. w.WriteHeader(code)
  866. return code
  867. }
  868. func cacheControl(next http.Handler) http.Handler {
  869. return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
  870. w.Header().Set("Cache-Control", "public, max-age=604800, immutable")
  871. next.ServeHTTP(w, r)
  872. })
  873. }