github.com/Ne0nd0g/gophish@v0.7.1-0.20190220040016-11493024a07d/controllers/route.go (about)

     1  package controllers
     2  
     3  import (
     4  	"compress/gzip"
     5  	"context"
     6  	"html/template"
     7  	"net/http"
     8  	"net/url"
     9  	"time"
    10  
    11  	"github.com/NYTimes/gziphandler"
    12  	"github.com/gophish/gophish/auth"
    13  	"github.com/gophish/gophish/config"
    14  	ctx "github.com/gophish/gophish/context"
    15  	log "github.com/gophish/gophish/logger"
    16  	mid "github.com/gophish/gophish/middleware"
    17  	"github.com/gophish/gophish/models"
    18  	"github.com/gophish/gophish/util"
    19  	"github.com/gophish/gophish/worker"
    20  	"github.com/gorilla/csrf"
    21  	"github.com/gorilla/handlers"
    22  	"github.com/gorilla/mux"
    23  	"github.com/gorilla/sessions"
    24  	"github.com/jordan-wright/unindexed"
    25  )
    26  
    27  // AdminServerOption is a functional option that is used to configure the
    28  // admin server
    29  type AdminServerOption func(*AdminServer)
    30  
    31  // AdminServer is an HTTP server that implements the administrative Gophish
    32  // handlers, including the dashboard and REST API.
    33  type AdminServer struct {
    34  	server *http.Server
    35  	worker worker.Worker
    36  	config config.AdminServer
    37  }
    38  
    39  // WithWorker is an option that sets the background worker.
    40  func WithWorker(w worker.Worker) AdminServerOption {
    41  	return func(as *AdminServer) {
    42  		as.worker = w
    43  	}
    44  }
    45  
    46  // NewAdminServer returns a new instance of the AdminServer with the
    47  // provided config and options applied.
    48  func NewAdminServer(config config.AdminServer, options ...AdminServerOption) *AdminServer {
    49  	defaultWorker, _ := worker.New()
    50  	defaultServer := &http.Server{
    51  		ReadTimeout: 10 * time.Second,
    52  		Addr:        config.ListenURL,
    53  	}
    54  	as := &AdminServer{
    55  		worker: defaultWorker,
    56  		server: defaultServer,
    57  		config: config,
    58  	}
    59  	for _, opt := range options {
    60  		opt(as)
    61  	}
    62  	as.registerRoutes()
    63  	return as
    64  }
    65  
    66  // Start launches the admin server, listening on the configured address.
    67  func (as *AdminServer) Start() error {
    68  	if as.worker != nil {
    69  		go as.worker.Start()
    70  	}
    71  	if as.config.UseTLS {
    72  		err := util.CheckAndCreateSSL(as.config.CertPath, as.config.KeyPath)
    73  		if err != nil {
    74  			log.Fatal(err)
    75  			return err
    76  		}
    77  		log.Infof("Starting admin server at https://%s", as.config.ListenURL)
    78  		return as.server.ListenAndServeTLS(as.config.CertPath, as.config.KeyPath)
    79  	}
    80  	// If TLS isn't configured, just listen on HTTP
    81  	log.Infof("Starting admin server at http://%s", as.config.ListenURL)
    82  	return as.server.ListenAndServe()
    83  }
    84  
    85  // Shutdown attempts to gracefully shutdown the server.
    86  func (as *AdminServer) Shutdown() error {
    87  	ctx, cancel := context.WithTimeout(context.Background(), time.Second*10)
    88  	defer cancel()
    89  	return as.server.Shutdown(ctx)
    90  }
    91  
    92  // SetupAdminRoutes creates the routes for handling requests to the web interface.
    93  // This function returns an http.Handler to be used in http.ListenAndServe().
    94  func (as *AdminServer) registerRoutes() {
    95  	router := mux.NewRouter()
    96  	// Base Front-end routes
    97  	router.HandleFunc("/", Use(as.Base, mid.RequireLogin))
    98  	router.HandleFunc("/login", as.Login)
    99  	router.HandleFunc("/logout", Use(as.Logout, mid.RequireLogin))
   100  	router.HandleFunc("/campaigns", Use(as.Campaigns, mid.RequireLogin))
   101  	router.HandleFunc("/campaigns/{id:[0-9]+}", Use(as.CampaignID, mid.RequireLogin))
   102  	router.HandleFunc("/templates", Use(as.Templates, mid.RequireLogin))
   103  	router.HandleFunc("/users", Use(as.Users, mid.RequireLogin))
   104  	router.HandleFunc("/landing_pages", Use(as.LandingPages, mid.RequireLogin))
   105  	router.HandleFunc("/sending_profiles", Use(as.SendingProfiles, mid.RequireLogin))
   106  	router.HandleFunc("/settings", Use(as.Settings, mid.RequireLogin))
   107  	router.HandleFunc("/register", Use(as.Register, mid.RequireLogin, mid.RequirePermission(models.PermissionModifySystem)))
   108  	// Create the API routes
   109  	api := router.PathPrefix("/api").Subrouter()
   110  	api = api.StrictSlash(true)
   111  	api.Use(mid.RequireAPIKey)
   112  	api.Use(mid.EnforceViewOnly)
   113  	api.HandleFunc("/reset", as.APIReset)
   114  	api.HandleFunc("/campaigns/", as.APICampaigns)
   115  	api.HandleFunc("/campaigns/summary", as.APICampaignsSummary)
   116  	api.HandleFunc("/campaigns/{id:[0-9]+}", as.APICampaign)
   117  	api.HandleFunc("/campaigns/{id:[0-9]+}/results", as.APICampaignResults)
   118  	api.HandleFunc("/campaigns/{id:[0-9]+}/summary", as.APICampaignSummary)
   119  	api.HandleFunc("/campaigns/{id:[0-9]+}/complete", as.APICampaignComplete)
   120  	api.HandleFunc("/groups/", as.APIGroups)
   121  	api.HandleFunc("/groups/summary", as.APIGroupsSummary)
   122  	api.HandleFunc("/groups/{id:[0-9]+}", as.APIGroup)
   123  	api.HandleFunc("/groups/{id:[0-9]+}/summary", as.APIGroupSummary)
   124  	api.HandleFunc("/templates/", as.APITemplates)
   125  	api.HandleFunc("/templates/{id:[0-9]+}", as.APITemplate)
   126  	api.HandleFunc("/pages/", as.APIPages)
   127  	api.HandleFunc("/pages/{id:[0-9]+}", as.APIPage)
   128  	api.HandleFunc("/smtp/", as.APISendingProfiles)
   129  	api.HandleFunc("/smtp/{id:[0-9]+}", as.APISendingProfile)
   130  	api.HandleFunc("/util/send_test_email", as.APISendTestEmail)
   131  	api.HandleFunc("/import/group", as.APIImportGroup)
   132  	api.HandleFunc("/import/email", as.APIImportEmail)
   133  	api.HandleFunc("/import/site", as.APIImportSite)
   134  
   135  	// Setup static file serving
   136  	router.PathPrefix("/").Handler(http.FileServer(unindexed.Dir("./static/")))
   137  
   138  	// Setup CSRF Protection
   139  	csrfHandler := csrf.Protect([]byte(auth.GenerateSecureKey()),
   140  		csrf.FieldName("csrf_token"),
   141  		csrf.Secure(as.config.UseTLS))
   142  	adminHandler := csrfHandler(router)
   143  	adminHandler = Use(adminHandler.ServeHTTP, mid.CSRFExceptions, mid.GetContext)
   144  
   145  	// Setup GZIP compression
   146  	gzipWrapper, _ := gziphandler.NewGzipLevelHandler(gzip.BestCompression)
   147  	adminHandler = gzipWrapper(adminHandler)
   148  
   149  	// Setup logging
   150  	adminHandler = handlers.CombinedLoggingHandler(log.Writer(), adminHandler)
   151  	as.server.Handler = adminHandler
   152  }
   153  
   154  // Use allows us to stack middleware to process the request
   155  // Example taken from https://github.com/gorilla/mux/pull/36#issuecomment-25849172
   156  func Use(handler http.HandlerFunc, mid ...func(http.Handler) http.HandlerFunc) http.HandlerFunc {
   157  	for _, m := range mid {
   158  		handler = m(handler)
   159  	}
   160  	return handler
   161  }
   162  
   163  type templateParams struct {
   164  	Title        string
   165  	Flashes      []interface{}
   166  	User         models.User
   167  	Token        string
   168  	Version      string
   169  	ModifySystem bool
   170  }
   171  
   172  // newTemplateParams returns the default template parameters for a user and
   173  // the CSRF token.
   174  func newTemplateParams(r *http.Request) templateParams {
   175  	user := ctx.Get(r, "user").(models.User)
   176  	modifySystem, _ := user.HasPermission(models.PermissionModifySystem)
   177  	return templateParams{
   178  		Token:        csrf.Token(r),
   179  		User:         user,
   180  		ModifySystem: modifySystem,
   181  		Version:      config.Version,
   182  	}
   183  }
   184  
   185  // Register creates a new user
   186  func (as *AdminServer) Register(w http.ResponseWriter, r *http.Request) {
   187  	// If it is a post request, attempt to register the account
   188  	// Now that we are all registered, we can log the user in
   189  	params := templateParams{Title: "Register", Token: csrf.Token(r)}
   190  	session := ctx.Get(r, "session").(*sessions.Session)
   191  	switch {
   192  	case r.Method == "GET":
   193  		params.Flashes = session.Flashes()
   194  		session.Save(r, w)
   195  		templates := template.New("template")
   196  		_, err := templates.ParseFiles("templates/register.html", "templates/flashes.html")
   197  		if err != nil {
   198  			log.Error(err)
   199  		}
   200  		template.Must(templates, err).ExecuteTemplate(w, "base", params)
   201  	case r.Method == "POST":
   202  		//Attempt to register
   203  		succ, err := auth.Register(r)
   204  		//If we've registered, redirect to the login page
   205  		if succ {
   206  			Flash(w, r, "success", "Registration successful!")
   207  			session.Save(r, w)
   208  			http.Redirect(w, r, "/login", 302)
   209  			return
   210  		}
   211  		// Check the error
   212  		m := err.Error()
   213  		log.Error(err)
   214  		Flash(w, r, "danger", m)
   215  		session.Save(r, w)
   216  		http.Redirect(w, r, "/register", 302)
   217  		return
   218  	}
   219  }
   220  
   221  // Base handles the default path and template execution
   222  func (as *AdminServer) Base(w http.ResponseWriter, r *http.Request) {
   223  	params := newTemplateParams(r)
   224  	params.Title = "Dashboard"
   225  	getTemplate(w, "dashboard").ExecuteTemplate(w, "base", params)
   226  }
   227  
   228  // Campaigns handles the default path and template execution
   229  func (as *AdminServer) Campaigns(w http.ResponseWriter, r *http.Request) {
   230  	params := newTemplateParams(r)
   231  	params.Title = "Campaigns"
   232  	getTemplate(w, "campaigns").ExecuteTemplate(w, "base", params)
   233  }
   234  
   235  // CampaignID handles the default path and template execution
   236  func (as *AdminServer) CampaignID(w http.ResponseWriter, r *http.Request) {
   237  	params := newTemplateParams(r)
   238  	params.Title = "Campaign Results"
   239  	getTemplate(w, "campaign_results").ExecuteTemplate(w, "base", params)
   240  }
   241  
   242  // Templates handles the default path and template execution
   243  func (as *AdminServer) Templates(w http.ResponseWriter, r *http.Request) {
   244  	params := newTemplateParams(r)
   245  	params.Title = "Email Templates"
   246  	getTemplate(w, "templates").ExecuteTemplate(w, "base", params)
   247  }
   248  
   249  // Users handles the default path and template execution
   250  func (as *AdminServer) Users(w http.ResponseWriter, r *http.Request) {
   251  	params := newTemplateParams(r)
   252  	params.Title = "Users & Groups"
   253  	getTemplate(w, "users").ExecuteTemplate(w, "base", params)
   254  }
   255  
   256  // LandingPages handles the default path and template execution
   257  func (as *AdminServer) LandingPages(w http.ResponseWriter, r *http.Request) {
   258  	params := newTemplateParams(r)
   259  	params.Title = "Landing Pages"
   260  	getTemplate(w, "landing_pages").ExecuteTemplate(w, "base", params)
   261  }
   262  
   263  // SendingProfiles handles the default path and template execution
   264  func (as *AdminServer) SendingProfiles(w http.ResponseWriter, r *http.Request) {
   265  	params := newTemplateParams(r)
   266  	params.Title = "Sending Profiles"
   267  	getTemplate(w, "sending_profiles").ExecuteTemplate(w, "base", params)
   268  }
   269  
   270  // Settings handles the changing of settings
   271  func (as *AdminServer) Settings(w http.ResponseWriter, r *http.Request) {
   272  	switch {
   273  	case r.Method == "GET":
   274  		params := newTemplateParams(r)
   275  		params.Title = "Settings"
   276  		getTemplate(w, "settings").ExecuteTemplate(w, "base", params)
   277  	case r.Method == "POST":
   278  		err := auth.ChangePassword(r)
   279  		msg := models.Response{Success: true, Message: "Settings Updated Successfully"}
   280  		if err == auth.ErrInvalidPassword {
   281  			msg.Message = "Invalid Password"
   282  			msg.Success = false
   283  			JSONResponse(w, msg, http.StatusBadRequest)
   284  			return
   285  		}
   286  		if err != nil {
   287  			msg.Message = err.Error()
   288  			msg.Success = false
   289  			JSONResponse(w, msg, http.StatusBadRequest)
   290  			return
   291  		}
   292  		JSONResponse(w, msg, http.StatusOK)
   293  	}
   294  }
   295  
   296  // Login handles the authentication flow for a user. If credentials are valid,
   297  // a session is created
   298  func (as *AdminServer) Login(w http.ResponseWriter, r *http.Request) {
   299  	params := struct {
   300  		User    models.User
   301  		Title   string
   302  		Flashes []interface{}
   303  		Token   string
   304  	}{Title: "Login", Token: csrf.Token(r)}
   305  	session := ctx.Get(r, "session").(*sessions.Session)
   306  	switch {
   307  	case r.Method == "GET":
   308  		params.Flashes = session.Flashes()
   309  		session.Save(r, w)
   310  		templates := template.New("template")
   311  		_, err := templates.ParseFiles("templates/login.html", "templates/flashes.html")
   312  		if err != nil {
   313  			log.Error(err)
   314  		}
   315  		template.Must(templates, err).ExecuteTemplate(w, "base", params)
   316  	case r.Method == "POST":
   317  		//Attempt to login
   318  		succ, u, err := auth.Login(r)
   319  		if err != nil {
   320  			log.Error(err)
   321  		}
   322  		//If we've logged in, save the session and redirect to the dashboard
   323  		if succ {
   324  			session.Values["id"] = u.Id
   325  			session.Save(r, w)
   326  			next := "/"
   327  			url, err := url.Parse(r.FormValue("next"))
   328  			if err == nil {
   329  				path := url.Path
   330  				if path != "" {
   331  					next = path
   332  				}
   333  			}
   334  			http.Redirect(w, r, next, 302)
   335  		} else {
   336  			Flash(w, r, "danger", "Invalid Username/Password")
   337  			params.Flashes = session.Flashes()
   338  			session.Save(r, w)
   339  			templates := template.New("template")
   340  			_, err := templates.ParseFiles("templates/login.html", "templates/flashes.html")
   341  			if err != nil {
   342  				log.Error(err)
   343  			}
   344  			w.Header().Set("Content-Type", "text/html; charset=utf-8")
   345  			w.WriteHeader(http.StatusUnauthorized)
   346  			template.Must(templates, err).ExecuteTemplate(w, "base", params)
   347  		}
   348  	}
   349  }
   350  
   351  // Logout destroys the current user session
   352  func (as *AdminServer) Logout(w http.ResponseWriter, r *http.Request) {
   353  	session := ctx.Get(r, "session").(*sessions.Session)
   354  	delete(session.Values, "id")
   355  	Flash(w, r, "success", "You have successfully logged out")
   356  	session.Save(r, w)
   357  	http.Redirect(w, r, "/login", 302)
   358  }
   359  
   360  func getTemplate(w http.ResponseWriter, tmpl string) *template.Template {
   361  	templates := template.New("template")
   362  	_, err := templates.ParseFiles("templates/base.html", "templates/nav.html", "templates/"+tmpl+".html", "templates/flashes.html")
   363  	if err != nil {
   364  		log.Error(err)
   365  	}
   366  	return template.Must(templates, err)
   367  }
   368  
   369  // Flash handles the rendering flash messages
   370  func Flash(w http.ResponseWriter, r *http.Request, t string, m string) {
   371  	session := ctx.Get(r, "session").(*sessions.Session)
   372  	session.AddFlash(models.Flash{
   373  		Type:    t,
   374  		Message: m,
   375  	})
   376  }