🎣 Open-Source Phishing Toolkit
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.

186 lines
5.9 KiB

  1. package middleware
  2. import (
  3. "encoding/json"
  4. "fmt"
  5. "net/http"
  6. "strings"
  7. ctx "github.com/gophish/gophish/context"
  8. "github.com/gophish/gophish/models"
  9. "github.com/gorilla/csrf"
  10. )
  11. // CSRFExemptPrefixes are a list of routes that are exempt from CSRF protection
  12. var CSRFExemptPrefixes = []string{
  13. "/api",
  14. }
  15. // CSRFExceptions is a middleware that prevents CSRF checks on routes listed in
  16. // CSRFExemptPrefixes.
  17. func CSRFExceptions(handler http.Handler) http.HandlerFunc {
  18. return func(w http.ResponseWriter, r *http.Request) {
  19. for _, prefix := range CSRFExemptPrefixes {
  20. if strings.HasPrefix(r.URL.Path, prefix) {
  21. r = csrf.UnsafeSkipCheck(r)
  22. break
  23. }
  24. }
  25. handler.ServeHTTP(w, r)
  26. }
  27. }
  28. // Use allows us to stack middleware to process the request
  29. // Example taken from https://github.com/gorilla/mux/pull/36#issuecomment-25849172
  30. func Use(handler http.HandlerFunc, mid ...func(http.Handler) http.HandlerFunc) http.HandlerFunc {
  31. for _, m := range mid {
  32. handler = m(handler)
  33. }
  34. return handler
  35. }
  36. // GetContext wraps each request in a function which fills in the context for a given request.
  37. // This includes setting the User and Session keys and values as necessary for use in later functions.
  38. func GetContext(handler http.Handler) http.HandlerFunc {
  39. // Set the context here
  40. return func(w http.ResponseWriter, r *http.Request) {
  41. // Parse the request form
  42. err := r.ParseForm()
  43. if err != nil {
  44. http.Error(w, "Error parsing request", http.StatusInternalServerError)
  45. }
  46. // Set the context appropriately here.
  47. // Set the session
  48. session, _ := Store.Get(r, "gophish")
  49. // Put the session in the context so that we can
  50. // reuse the values in different handlers
  51. r = ctx.Set(r, "session", session)
  52. if id, ok := session.Values["id"]; ok {
  53. u, err := models.GetUser(id.(int64))
  54. if err != nil {
  55. r = ctx.Set(r, "user", nil)
  56. } else {
  57. r = ctx.Set(r, "user", u)
  58. }
  59. } else {
  60. r = ctx.Set(r, "user", nil)
  61. }
  62. handler.ServeHTTP(w, r)
  63. // Remove context contents
  64. ctx.Clear(r)
  65. }
  66. }
  67. // RequireAPIKey ensures that a valid API key is set as either the api_key GET
  68. // parameter, or a Bearer token.
  69. func RequireAPIKey(handler http.Handler) http.Handler {
  70. return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
  71. w.Header().Set("Access-Control-Allow-Origin", "*")
  72. if r.Method == "OPTIONS" {
  73. w.Header().Set("Access-Control-Allow-Methods", "POST, GET, OPTIONS")
  74. w.Header().Set("Access-Control-Max-Age", "1000")
  75. w.Header().Set("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept")
  76. return
  77. }
  78. r.ParseForm()
  79. ak := r.Form.Get("api_key")
  80. // If we can't get the API key, we'll also check for the
  81. // Authorization Bearer token
  82. if ak == "" {
  83. tokens, ok := r.Header["Authorization"]
  84. if ok && len(tokens) >= 1 {
  85. ak = tokens[0]
  86. ak = strings.TrimPrefix(ak, "Bearer ")
  87. }
  88. }
  89. if ak == "" {
  90. JSONError(w, http.StatusUnauthorized, "API Key not set")
  91. return
  92. }
  93. u, err := models.GetUserByAPIKey(ak)
  94. if err != nil {
  95. JSONError(w, http.StatusUnauthorized, "Invalid API Key")
  96. return
  97. }
  98. r = ctx.Set(r, "user", u)
  99. r = ctx.Set(r, "user_id", u.Id)
  100. r = ctx.Set(r, "api_key", ak)
  101. handler.ServeHTTP(w, r)
  102. })
  103. }
  104. // RequireLogin checks to see if the user is currently logged in.
  105. // If not, the function returns a 302 redirect to the login page.
  106. func RequireLogin(handler http.Handler) http.HandlerFunc {
  107. return func(w http.ResponseWriter, r *http.Request) {
  108. if u := ctx.Get(r, "user"); u != nil {
  109. // If a password change is required for the user, then redirect them
  110. // to the login page
  111. currentUser := u.(models.User)
  112. if currentUser.PasswordChangeRequired && r.URL.Path != "/reset_password" {
  113. q := r.URL.Query()
  114. q.Set("next", r.URL.Path)
  115. http.Redirect(w, r, fmt.Sprintf("/reset_password?%s", q.Encode()), http.StatusTemporaryRedirect)
  116. return
  117. }
  118. handler.ServeHTTP(w, r)
  119. return
  120. }
  121. q := r.URL.Query()
  122. q.Set("next", r.URL.Path)
  123. http.Redirect(w, r, fmt.Sprintf("/login?%s", q.Encode()), http.StatusTemporaryRedirect)
  124. }
  125. }
  126. // EnforceViewOnly is a global middleware that limits the ability to edit
  127. // objects to accounts with the PermissionModifyObjects permission.
  128. func EnforceViewOnly(next http.Handler) http.Handler {
  129. return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
  130. // If the request is for any non-GET HTTP method, e.g. POST, PUT,
  131. // or DELETE, we need to ensure the user has the appropriate
  132. // permission.
  133. if r.Method != http.MethodGet && r.Method != http.MethodHead && r.Method != http.MethodOptions {
  134. user := ctx.Get(r, "user").(models.User)
  135. access, err := user.HasPermission(models.PermissionModifyObjects)
  136. if err != nil {
  137. http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
  138. return
  139. }
  140. if !access {
  141. http.Error(w, http.StatusText(http.StatusForbidden), http.StatusForbidden)
  142. return
  143. }
  144. }
  145. next.ServeHTTP(w, r)
  146. })
  147. }
  148. // RequirePermission checks to see if the user has the requested permission
  149. // before executing the handler. If the request is unauthorized, a JSONError
  150. // is returned.
  151. func RequirePermission(perm string) func(http.Handler) http.HandlerFunc {
  152. return func(next http.Handler) http.HandlerFunc {
  153. return func(w http.ResponseWriter, r *http.Request) {
  154. user := ctx.Get(r, "user").(models.User)
  155. access, err := user.HasPermission(perm)
  156. if err != nil {
  157. JSONError(w, http.StatusInternalServerError, err.Error())
  158. return
  159. }
  160. if !access {
  161. JSONError(w, http.StatusForbidden, http.StatusText(http.StatusForbidden))
  162. return
  163. }
  164. next.ServeHTTP(w, r)
  165. }
  166. }
  167. }
  168. // JSONError returns an error in JSON format with the given
  169. // status code and message
  170. func JSONError(w http.ResponseWriter, c int, m string) {
  171. cj, _ := json.MarshalIndent(models.Response{Success: false, Message: m}, "", " ")
  172. w.Header().Set("Content-Type", "application/json")
  173. w.WriteHeader(c)
  174. fmt.Fprintf(w, "%s", cj)
  175. }