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.
 
 
 
 
 

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