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.
 
 
 
 
 

899 lines
25 KiB

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