A clean, Markdown-based publishing platform made for writers. Write together, and build a community. https://writefreely.org
25'ten fazla konu seçemezsiniz Konular bir harf veya rakamla başlamalı, kısa çizgiler ('-') içerebilir ve en fazla 35 karakter uzunluğunda olabilir.
 
 
 
 
 

936 satır
26 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. "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/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. func (h *Handler) UserAll(web bool, f userHandlerFunc, a authFunc) http.HandlerFunc {
  249. return func(w http.ResponseWriter, r *http.Request) {
  250. handleFunc := func() error {
  251. var status int
  252. start := time.Now()
  253. defer func() {
  254. if e := recover(); e != nil {
  255. log.Error("%s: %s", e, debug.Stack())
  256. impart.WriteError(w, impart.HTTPError{http.StatusInternalServerError, "Something didn't work quite right."})
  257. status = 500
  258. }
  259. log.Info(h.app.ReqLog(r, status, time.Since(start)))
  260. }()
  261. u, err := a(h.app.App(), r)
  262. if err != nil {
  263. if err, ok := err.(impart.HTTPError); ok {
  264. status = err.Status
  265. } else {
  266. status = 500
  267. }
  268. return err
  269. }
  270. err = f(h.app.App(), u, w, r)
  271. if err == nil {
  272. status = 200
  273. } else if err, ok := err.(impart.HTTPError); ok {
  274. status = err.Status
  275. } else {
  276. status = 500
  277. }
  278. return err
  279. }
  280. if web {
  281. h.handleHTTPError(w, r, handleFunc())
  282. } else {
  283. h.handleError(w, r, handleFunc())
  284. }
  285. }
  286. }
  287. func (h *Handler) RedirectOnErr(f handlerFunc, loc string) handlerFunc {
  288. return func(app *App, w http.ResponseWriter, r *http.Request) error {
  289. err := f(app, w, r)
  290. if err != nil {
  291. if ie, ok := err.(impart.HTTPError); ok {
  292. // Override default redirect with returned error's, if it's a
  293. // redirect error.
  294. if ie.Status == http.StatusFound {
  295. return ie
  296. }
  297. }
  298. return impart.HTTPError{http.StatusFound, loc}
  299. }
  300. return nil
  301. }
  302. }
  303. func (h *Handler) Page(n string) http.HandlerFunc {
  304. return h.Web(func(app *App, w http.ResponseWriter, r *http.Request) error {
  305. t, ok := pages[n]
  306. if !ok {
  307. return impart.HTTPError{http.StatusNotFound, "Page not found."}
  308. }
  309. sp := pageForReq(app, r)
  310. err := t.ExecuteTemplate(w, "base", sp)
  311. if err != nil {
  312. log.Error("Unable to render page: %v", err)
  313. }
  314. return err
  315. }, UserLevelOptional)
  316. }
  317. func (h *Handler) WebErrors(f handlerFunc, ul UserLevelFunc) http.HandlerFunc {
  318. return func(w http.ResponseWriter, r *http.Request) {
  319. // TODO: factor out this logic shared with Web()
  320. h.handleHTTPError(w, r, func() error {
  321. var status int
  322. start := time.Now()
  323. defer func() {
  324. if e := recover(); e != nil {
  325. u := getUserSession(h.app.App(), r)
  326. username := "None"
  327. if u != nil {
  328. username = u.Username
  329. }
  330. log.Error("User: %s\n\n%s: %s", username, e, debug.Stack())
  331. h.errors.InternalServerError.ExecuteTemplate(w, "base", pageForReq(h.app.App(), r))
  332. status = 500
  333. }
  334. log.Info(h.app.ReqLog(r, status, time.Since(start)))
  335. }()
  336. var session *sessions.Session
  337. var err error
  338. if ul(h.app.App().cfg) != UserLevelNoneType {
  339. session, err = h.sessionStore.Get(r, cookieName)
  340. if err != nil && (ul(h.app.App().cfg) == UserLevelNoneRequiredType || ul(h.app.App().cfg) == UserLevelUserType) {
  341. // Cookie is required, but we can ignore this error
  342. log.Error("Handler: Unable to get session (for user permission %d); ignoring: %v", ul(h.app.App().cfg), err)
  343. }
  344. _, gotUser := session.Values[cookieUserVal].(*User)
  345. if ul(h.app.App().cfg) == UserLevelNoneRequiredType && gotUser {
  346. to := correctPageFromLoginAttempt(r)
  347. log.Info("Handler: Required NO user, but got one. Redirecting to %s", to)
  348. err := impart.HTTPError{http.StatusFound, to}
  349. status = err.Status
  350. return err
  351. } else if ul(h.app.App().cfg) == UserLevelUserType && !gotUser {
  352. log.Info("Handler: Required a user, but DIDN'T get one. Sending not logged in.")
  353. err := ErrNotLoggedIn
  354. status = err.Status
  355. return err
  356. }
  357. }
  358. // TODO: pass User object to function
  359. err = f(h.app.App(), w, r)
  360. if err == nil {
  361. status = 200
  362. } else if httpErr, ok := err.(impart.HTTPError); ok {
  363. status = httpErr.Status
  364. if status < 300 || status > 399 {
  365. addSessionFlash(h.app.App(), w, r, httpErr.Message, session)
  366. return impart.HTTPError{http.StatusFound, r.Referer()}
  367. }
  368. } else {
  369. e := fmt.Sprintf("[Web handler] 500: %v", err)
  370. if !strings.HasSuffix(e, "write: broken pipe") {
  371. log.Error(e)
  372. } else {
  373. log.Error(e)
  374. }
  375. log.Info("Web handler internal error render")
  376. h.errors.InternalServerError.ExecuteTemplate(w, "base", pageForReq(h.app.App(), r))
  377. status = 500
  378. }
  379. return err
  380. }())
  381. }
  382. }
  383. func (h *Handler) CollectionPostOrStatic(w http.ResponseWriter, r *http.Request) {
  384. if strings.Contains(r.URL.Path, ".") && !isRaw(r) {
  385. start := time.Now()
  386. status := 200
  387. defer func() {
  388. log.Info(h.app.ReqLog(r, status, time.Since(start)))
  389. }()
  390. // Serve static file
  391. h.app.App().shttp.ServeHTTP(w, r)
  392. return
  393. }
  394. h.Web(viewCollectionPost, UserLevelReader)(w, r)
  395. }
  396. // Web handles requests made in the web application. This provides user-
  397. // friendly HTML pages and actions that work in the browser.
  398. func (h *Handler) Web(f handlerFunc, ul UserLevelFunc) http.HandlerFunc {
  399. return func(w http.ResponseWriter, r *http.Request) {
  400. h.handleHTTPError(w, r, func() error {
  401. var status int
  402. start := time.Now()
  403. defer func() {
  404. if e := recover(); e != nil {
  405. u := getUserSession(h.app.App(), r)
  406. username := "None"
  407. if u != nil {
  408. username = u.Username
  409. }
  410. log.Error("User: %s\n\n%s: %s", username, e, debug.Stack())
  411. log.Info("Web deferred internal error render")
  412. h.errors.InternalServerError.ExecuteTemplate(w, "base", pageForReq(h.app.App(), r))
  413. status = 500
  414. }
  415. log.Info(h.app.ReqLog(r, status, time.Since(start)))
  416. }()
  417. if ul(h.app.App().cfg) != UserLevelNoneType {
  418. session, err := h.sessionStore.Get(r, cookieName)
  419. if err != nil && (ul(h.app.App().cfg) == UserLevelNoneRequiredType || ul(h.app.App().cfg) == UserLevelUserType) {
  420. // Cookie is required, but we can ignore this error
  421. log.Error("Handler: Unable to get session (for user permission %d); ignoring: %v", ul(h.app.App().cfg), err)
  422. }
  423. _, gotUser := session.Values[cookieUserVal].(*User)
  424. if ul(h.app.App().cfg) == UserLevelNoneRequiredType && gotUser {
  425. to := correctPageFromLoginAttempt(r)
  426. log.Info("Handler: Required NO user, but got one. Redirecting to %s", to)
  427. err := impart.HTTPError{http.StatusFound, to}
  428. status = err.Status
  429. return err
  430. } else if ul(h.app.App().cfg) == UserLevelUserType && !gotUser {
  431. log.Info("Handler: Required a user, but DIDN'T get one. Sending not logged in.")
  432. err := ErrNotLoggedIn
  433. status = err.Status
  434. return err
  435. }
  436. }
  437. // TODO: pass User object to function
  438. err := f(h.app.App(), w, r)
  439. if err == nil {
  440. status = 200
  441. } else if httpErr, ok := err.(impart.HTTPError); ok {
  442. status = httpErr.Status
  443. } else {
  444. e := fmt.Sprintf("[Web handler] 500: %v", err)
  445. log.Error(e)
  446. log.Info("Web internal error render")
  447. h.errors.InternalServerError.ExecuteTemplate(w, "base", pageForReq(h.app.App(), r))
  448. status = 500
  449. }
  450. return err
  451. }())
  452. }
  453. }
  454. func (h *Handler) All(f handlerFunc) http.HandlerFunc {
  455. return func(w http.ResponseWriter, r *http.Request) {
  456. h.handleError(w, r, func() error {
  457. // TODO: return correct "success" status
  458. status := 200
  459. start := time.Now()
  460. defer func() {
  461. if e := recover(); e != nil {
  462. log.Error("%s:\n%s", e, debug.Stack())
  463. impart.WriteError(w, impart.HTTPError{http.StatusInternalServerError, "Something didn't work quite right."})
  464. status = 500
  465. }
  466. log.Info(h.app.ReqLog(r, status, time.Since(start)))
  467. }()
  468. // TODO: do any needed authentication
  469. err := f(h.app.App(), w, r)
  470. if err != nil {
  471. if err, ok := err.(impart.HTTPError); ok {
  472. status = err.Status
  473. } else {
  474. status = 500
  475. }
  476. }
  477. return err
  478. }())
  479. }
  480. }
  481. func (h *Handler) OAuth(f handlerFunc) http.HandlerFunc {
  482. return func(w http.ResponseWriter, r *http.Request) {
  483. h.handleOAuthError(w, r, func() error {
  484. // TODO: return correct "success" status
  485. status := 200
  486. start := time.Now()
  487. defer func() {
  488. if e := recover(); e != nil {
  489. log.Error("%s:\n%s", e, debug.Stack())
  490. impart.WriteError(w, impart.HTTPError{http.StatusInternalServerError, "Something didn't work quite right."})
  491. status = 500
  492. }
  493. log.Info(h.app.ReqLog(r, status, time.Since(start)))
  494. }()
  495. err := f(h.app.App(), w, r)
  496. if err != nil {
  497. if err, ok := err.(impart.HTTPError); ok {
  498. status = err.Status
  499. } else {
  500. status = 500
  501. }
  502. }
  503. return err
  504. }())
  505. }
  506. }
  507. func (h *Handler) AllReader(f handlerFunc) http.HandlerFunc {
  508. return func(w http.ResponseWriter, r *http.Request) {
  509. h.handleError(w, r, func() error {
  510. status := 200
  511. start := time.Now()
  512. defer func() {
  513. if e := recover(); e != nil {
  514. log.Error("%s:\n%s", e, debug.Stack())
  515. impart.WriteError(w, impart.HTTPError{http.StatusInternalServerError, "Something didn't work quite right."})
  516. status = 500
  517. }
  518. log.Info(h.app.ReqLog(r, status, time.Since(start)))
  519. }()
  520. // Allow any origin, as public endpoints are handled in here
  521. w.Header().Set("Access-Control-Allow-Origin", "*")
  522. if h.app.App().cfg.App.Private {
  523. // This instance is private, so ensure it's being accessed by a valid user
  524. // Check if authenticated with an access token
  525. _, apiErr := optionalAPIAuth(h.app.App(), r)
  526. if apiErr != nil {
  527. if err, ok := apiErr.(impart.HTTPError); ok {
  528. status = err.Status
  529. } else {
  530. status = 500
  531. }
  532. if apiErr == ErrNotLoggedIn {
  533. // Fall back to web auth since there was no access token given
  534. _, err := webAuth(h.app.App(), r)
  535. if err != nil {
  536. if err, ok := apiErr.(impart.HTTPError); ok {
  537. status = err.Status
  538. } else {
  539. status = 500
  540. }
  541. return err
  542. }
  543. } else {
  544. return apiErr
  545. }
  546. }
  547. }
  548. err := f(h.app.App(), w, r)
  549. if err != nil {
  550. if err, ok := err.(impart.HTTPError); ok {
  551. status = err.Status
  552. } else {
  553. status = 500
  554. }
  555. }
  556. return err
  557. }())
  558. }
  559. }
  560. func (h *Handler) Download(f dataHandlerFunc, ul UserLevelFunc) http.HandlerFunc {
  561. return func(w http.ResponseWriter, r *http.Request) {
  562. h.handleHTTPError(w, r, func() error {
  563. var status int
  564. start := time.Now()
  565. defer func() {
  566. if e := recover(); e != nil {
  567. log.Error("%s: %s", e, debug.Stack())
  568. h.errors.InternalServerError.ExecuteTemplate(w, "base", pageForReq(h.app.App(), r))
  569. status = 500
  570. }
  571. log.Info(h.app.ReqLog(r, status, time.Since(start)))
  572. }()
  573. data, filename, err := f(h.app.App(), w, r)
  574. if err != nil {
  575. if err, ok := err.(impart.HTTPError); ok {
  576. status = err.Status
  577. } else {
  578. status = 500
  579. }
  580. return err
  581. }
  582. ext := ".json"
  583. ct := "application/json"
  584. if strings.HasSuffix(r.URL.Path, ".csv") {
  585. ext = ".csv"
  586. ct = "text/csv"
  587. } else if strings.HasSuffix(r.URL.Path, ".zip") {
  588. ext = ".zip"
  589. ct = "application/zip"
  590. }
  591. w.Header().Set("Content-Disposition", fmt.Sprintf("attachment; filename=%s%s", filename, ext))
  592. w.Header().Set("Content-Type", ct)
  593. w.Header().Set("Content-Length", strconv.Itoa(len(data)))
  594. fmt.Fprint(w, string(data))
  595. status = 200
  596. return nil
  597. }())
  598. }
  599. }
  600. func (h *Handler) Redirect(url string, ul UserLevelFunc) http.HandlerFunc {
  601. return func(w http.ResponseWriter, r *http.Request) {
  602. h.handleHTTPError(w, r, func() error {
  603. start := time.Now()
  604. var status int
  605. if ul(h.app.App().cfg) != UserLevelNoneType {
  606. session, err := h.sessionStore.Get(r, cookieName)
  607. if err != nil && (ul(h.app.App().cfg) == UserLevelNoneRequiredType || ul(h.app.App().cfg) == UserLevelUserType) {
  608. // Cookie is required, but we can ignore this error
  609. log.Error("Handler: Unable to get session (for user permission %d); ignoring: %v", ul(h.app.App().cfg), err)
  610. }
  611. _, gotUser := session.Values[cookieUserVal].(*User)
  612. if ul(h.app.App().cfg) == UserLevelNoneRequiredType && gotUser {
  613. to := correctPageFromLoginAttempt(r)
  614. log.Info("Handler: Required NO user, but got one. Redirecting to %s", to)
  615. err := impart.HTTPError{http.StatusFound, to}
  616. status = err.Status
  617. return err
  618. } else if ul(h.app.App().cfg) == UserLevelUserType && !gotUser {
  619. log.Info("Handler: Required a user, but DIDN'T get one. Sending not logged in.")
  620. err := ErrNotLoggedIn
  621. status = err.Status
  622. return err
  623. }
  624. }
  625. status = sendRedirect(w, http.StatusFound, url)
  626. log.Info(h.app.ReqLog(r, status, time.Since(start)))
  627. return nil
  628. }())
  629. }
  630. }
  631. func (h *Handler) handleHTTPError(w http.ResponseWriter, r *http.Request, err error) {
  632. if err == nil {
  633. return
  634. }
  635. if err, ok := err.(impart.HTTPError); ok {
  636. if err.Status >= 300 && err.Status < 400 {
  637. sendRedirect(w, err.Status, err.Message)
  638. return
  639. } else if err.Status == http.StatusUnauthorized {
  640. q := ""
  641. if r.URL.RawQuery != "" {
  642. q = url.QueryEscape("?" + r.URL.RawQuery)
  643. }
  644. sendRedirect(w, http.StatusFound, "/login?to="+r.URL.Path+q)
  645. return
  646. } else if err.Status == http.StatusGone {
  647. w.WriteHeader(err.Status)
  648. p := &struct {
  649. page.StaticPage
  650. Content *template.HTML
  651. }{
  652. StaticPage: pageForReq(h.app.App(), r),
  653. }
  654. if err.Message != "" {
  655. co := template.HTML(err.Message)
  656. p.Content = &co
  657. }
  658. h.errors.Gone.ExecuteTemplate(w, "base", p)
  659. return
  660. } else if err.Status == http.StatusNotFound {
  661. w.WriteHeader(err.Status)
  662. if strings.Contains(r.Header.Get("Accept"), "application/activity+json") {
  663. // This is a fediverse request; simply return the header
  664. return
  665. }
  666. h.errors.NotFound.ExecuteTemplate(w, "base", pageForReq(h.app.App(), r))
  667. return
  668. } else if err.Status == http.StatusInternalServerError {
  669. w.WriteHeader(err.Status)
  670. log.Info("handleHTTPErorr internal error render")
  671. h.errors.InternalServerError.ExecuteTemplate(w, "base", pageForReq(h.app.App(), r))
  672. return
  673. } else if err.Status == http.StatusServiceUnavailable {
  674. w.WriteHeader(err.Status)
  675. h.errors.UnavailableError.ExecuteTemplate(w, "base", pageForReq(h.app.App(), r))
  676. return
  677. } else if err.Status == http.StatusAccepted {
  678. impart.WriteSuccess(w, "", err.Status)
  679. return
  680. } else {
  681. p := &struct {
  682. page.StaticPage
  683. Title string
  684. Content template.HTML
  685. }{
  686. pageForReq(h.app.App(), r),
  687. fmt.Sprintf("Uh oh (%d)", err.Status),
  688. template.HTML(fmt.Sprintf("<p style=\"text-align: center\" class=\"introduction\">%s</p>", err.Message)),
  689. }
  690. h.errors.Blank.ExecuteTemplate(w, "base", p)
  691. return
  692. }
  693. impart.WriteError(w, err)
  694. return
  695. }
  696. impart.WriteError(w, impart.HTTPError{http.StatusInternalServerError, "This is an unhelpful error message for a miscellaneous internal error."})
  697. }
  698. func (h *Handler) handleError(w http.ResponseWriter, r *http.Request, err error) {
  699. if err == nil {
  700. return
  701. }
  702. if err, ok := err.(impart.HTTPError); ok {
  703. if err.Status >= 300 && err.Status < 400 {
  704. sendRedirect(w, err.Status, err.Message)
  705. return
  706. }
  707. // if strings.Contains(r.Header.Get("Accept"), "text/html") {
  708. impart.WriteError(w, err)
  709. // }
  710. return
  711. }
  712. if IsJSON(r) {
  713. impart.WriteError(w, impart.HTTPError{http.StatusInternalServerError, "This is an unhelpful error message for a miscellaneous internal error."})
  714. return
  715. }
  716. h.errors.InternalServerError.ExecuteTemplate(w, "base", pageForReq(h.app.App(), r))
  717. }
  718. func (h *Handler) handleOAuthError(w http.ResponseWriter, r *http.Request, err error) {
  719. if err == nil {
  720. return
  721. }
  722. if err, ok := err.(impart.HTTPError); ok {
  723. if err.Status >= 300 && err.Status < 400 {
  724. sendRedirect(w, err.Status, err.Message)
  725. return
  726. }
  727. impart.WriteOAuthError(w, err)
  728. return
  729. }
  730. impart.WriteOAuthError(w, impart.HTTPError{http.StatusInternalServerError, "This is an unhelpful error message for a miscellaneous internal error."})
  731. return
  732. }
  733. func correctPageFromLoginAttempt(r *http.Request) string {
  734. to := r.FormValue("to")
  735. if to == "" {
  736. to = "/"
  737. } else if !strings.HasPrefix(to, "/") {
  738. to = "/" + to
  739. }
  740. return to
  741. }
  742. func (h *Handler) LogHandlerFunc(f http.HandlerFunc) http.HandlerFunc {
  743. return func(w http.ResponseWriter, r *http.Request) {
  744. h.handleHTTPError(w, r, func() error {
  745. status := 200
  746. start := time.Now()
  747. defer func() {
  748. if e := recover(); e != nil {
  749. log.Error("Handler.LogHandlerFunc\n\n%s: %s", e, debug.Stack())
  750. h.errors.InternalServerError.ExecuteTemplate(w, "base", pageForReq(h.app.App(), r))
  751. status = 500
  752. }
  753. // TODO: log actual status code returned
  754. log.Info(h.app.ReqLog(r, status, time.Since(start)))
  755. }()
  756. if h.app.App().cfg.App.Private {
  757. // This instance is private, so ensure it's being accessed by a valid user
  758. // Check if authenticated with an access token
  759. _, apiErr := optionalAPIAuth(h.app.App(), r)
  760. if apiErr != nil {
  761. if err, ok := apiErr.(impart.HTTPError); ok {
  762. status = err.Status
  763. } else {
  764. status = 500
  765. }
  766. if apiErr == ErrNotLoggedIn {
  767. // Fall back to web auth since there was no access token given
  768. _, err := webAuth(h.app.App(), r)
  769. if err != nil {
  770. if err, ok := apiErr.(impart.HTTPError); ok {
  771. status = err.Status
  772. } else {
  773. status = 500
  774. }
  775. return err
  776. }
  777. } else {
  778. return apiErr
  779. }
  780. }
  781. }
  782. f(w, r)
  783. return nil
  784. }())
  785. }
  786. }
  787. func (h *Handler) Gopher(f gopherFunc) gopher.HandlerFunc {
  788. return func(w gopher.ResponseWriter, r *gopher.Request) {
  789. defer func() {
  790. if e := recover(); e != nil {
  791. log.Error("%s: %s", e, debug.Stack())
  792. w.WriteError("An internal error occurred")
  793. }
  794. log.Info("gopher: %s", r.Selector)
  795. }()
  796. err := f(h.app.App(), w, r)
  797. if err != nil {
  798. log.Error("failed: %s", err)
  799. w.WriteError("the page failed for some reason (see logs)")
  800. }
  801. }
  802. }
  803. func sendRedirect(w http.ResponseWriter, code int, location string) int {
  804. w.Header().Set("Location", location)
  805. w.WriteHeader(code)
  806. return code
  807. }
  808. func cacheControl(next http.Handler) http.Handler {
  809. return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
  810. w.Header().Set("Cache-Control", "public, max-age=604800, immutable")
  811. next.ServeHTTP(w, r)
  812. })
  813. }