gophish/controllers/api/server.go
Jordan Wright bb7de8df3e
Initial Implementation of a Password Policy (#1867)
This PR adds the initial work to implement a password policy as defined in #1538.

Specifically, this implements the following

* Rate limiting for the login handler
* Implementing the ability for system admins to require a user to reset their password
* Implementing a password policy that requires passwords to be a minimum of 8 characters
* Removes the default password (gophish) for admin users to instead have the password randomly generated when Gophish first starts up
* Adds a password strength meter when choosing a new password

Fixes #1538
2020-06-19 22:03:51 -05:00

94 lines
3.3 KiB
Go

package api
import (
"net/http"
mid "github.com/gophish/gophish/middleware"
"github.com/gophish/gophish/middleware/ratelimit"
"github.com/gophish/gophish/models"
"github.com/gophish/gophish/worker"
"github.com/gorilla/mux"
)
// ServerOption is an option to apply to the API server.
type ServerOption func(*Server)
// Server represents the routes and functionality of the Gophish API.
// It's not a server in the traditional sense, in that it isn't started and
// stopped. Rather, it's meant to be used as an http.Handler in the
// AdminServer.
type Server struct {
handler http.Handler
worker worker.Worker
limiter *ratelimit.PostLimiter
}
// NewServer returns a new instance of the API handler with the provided
// options applied.
func NewServer(options ...ServerOption) *Server {
defaultWorker, _ := worker.New()
defaultLimiter := ratelimit.NewPostLimiter()
as := &Server{
worker: defaultWorker,
limiter: defaultLimiter,
}
for _, opt := range options {
opt(as)
}
as.registerRoutes()
return as
}
// WithWorker is an option that sets the background worker.
func WithWorker(w worker.Worker) ServerOption {
return func(as *Server) {
as.worker = w
}
}
func WithLimiter(limiter *ratelimit.PostLimiter) ServerOption {
return func(as *Server) {
as.limiter = limiter
}
}
func (as *Server) registerRoutes() {
root := mux.NewRouter()
root = root.StrictSlash(true)
router := root.PathPrefix("/api/").Subrouter()
router.Use(mid.RequireAPIKey)
router.Use(mid.EnforceViewOnly)
router.HandleFunc("/imap/", as.IMAPServer)
router.HandleFunc("/imap/validate", as.IMAPServerValidate)
router.HandleFunc("/reset", as.Reset)
router.HandleFunc("/campaigns/", as.Campaigns)
router.HandleFunc("/campaigns/summary", as.CampaignsSummary)
router.HandleFunc("/campaigns/{id:[0-9]+}", as.Campaign)
router.HandleFunc("/campaigns/{id:[0-9]+}/results", as.CampaignResults)
router.HandleFunc("/campaigns/{id:[0-9]+}/summary", as.CampaignSummary)
router.HandleFunc("/campaigns/{id:[0-9]+}/complete", as.CampaignComplete)
router.HandleFunc("/groups/", as.Groups)
router.HandleFunc("/groups/summary", as.GroupsSummary)
router.HandleFunc("/groups/{id:[0-9]+}", as.Group)
router.HandleFunc("/groups/{id:[0-9]+}/summary", as.GroupSummary)
router.HandleFunc("/templates/", as.Templates)
router.HandleFunc("/templates/{id:[0-9]+}", as.Template)
router.HandleFunc("/pages/", as.Pages)
router.HandleFunc("/pages/{id:[0-9]+}", as.Page)
router.HandleFunc("/smtp/", as.SendingProfiles)
router.HandleFunc("/smtp/{id:[0-9]+}", as.SendingProfile)
router.HandleFunc("/users/", mid.Use(as.Users, mid.RequirePermission(models.PermissionModifySystem)))
router.HandleFunc("/users/{id:[0-9]+}", mid.Use(as.User))
router.HandleFunc("/util/send_test_email", as.SendTestEmail)
router.HandleFunc("/import/group", as.ImportGroup)
router.HandleFunc("/import/email", as.ImportEmail)
router.HandleFunc("/import/site", as.ImportSite)
router.HandleFunc("/webhooks/", mid.Use(as.Webhooks, mid.RequirePermission(models.PermissionModifySystem)))
router.HandleFunc("/webhooks/{id:[0-9]+}/validate", mid.Use(as.ValidateWebhook, mid.RequirePermission(models.PermissionModifySystem)))
router.HandleFunc("/webhooks/{id:[0-9]+}", mid.Use(as.Webhook, mid.RequirePermission(models.PermissionModifySystem)))
as.handler = router
}
func (as *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) {
as.handler.ServeHTTP(w, r)
}