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.
 
 
 
 
 

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