github.com/jonathaningram/gophish@v0.3.1-0.20170829042651-ac3fe6aeae6c/controllers/route.go (about)

     1  package controllers
     2  
     3  import (
     4  	"fmt"
     5  	"html/template"
     6  	"log"
     7  	"net/http"
     8  	"os"
     9  
    10  	"github.com/gophish/gophish/auth"
    11  	"github.com/gophish/gophish/config"
    12  	ctx "github.com/gophish/gophish/context"
    13  	mid "github.com/gophish/gophish/middleware"
    14  	"github.com/gophish/gophish/models"
    15  	"github.com/gorilla/csrf"
    16  	"github.com/gorilla/mux"
    17  	"github.com/gorilla/sessions"
    18  )
    19  
    20  // Logger is used to send logging messages to stdout.
    21  var Logger = log.New(os.Stdout, " ", log.Ldate|log.Ltime|log.Lshortfile)
    22  
    23  // CreateAdminRouter creates the routes for handling requests to the web interface.
    24  // This function returns an http.Handler to be used in http.ListenAndServe().
    25  func CreateAdminRouter() http.Handler {
    26  	router := mux.NewRouter()
    27  	// Base Front-end routes
    28  	router.HandleFunc("/", Use(Base, mid.RequireLogin))
    29  	router.HandleFunc("/login", Login)
    30  	router.HandleFunc("/logout", Use(Logout, mid.RequireLogin))
    31  	router.HandleFunc("/campaigns", Use(Campaigns, mid.RequireLogin))
    32  	router.HandleFunc("/campaigns/{id:[0-9]+}", Use(CampaignID, mid.RequireLogin))
    33  	router.HandleFunc("/templates", Use(Templates, mid.RequireLogin))
    34  	router.HandleFunc("/users", Use(Users, mid.RequireLogin))
    35  	router.HandleFunc("/landing_pages", Use(LandingPages, mid.RequireLogin))
    36  	router.HandleFunc("/sending_profiles", Use(SendingProfiles, mid.RequireLogin))
    37  	router.HandleFunc("/register", Use(Register, mid.RequireLogin))
    38  	router.HandleFunc("/settings", Use(Settings, mid.RequireLogin))
    39  	// Create the API routes
    40  	api := router.PathPrefix("/api").Subrouter()
    41  	api = api.StrictSlash(true)
    42  	api.HandleFunc("/", Use(API, mid.RequireLogin))
    43  	api.HandleFunc("/reset", Use(API_Reset, mid.RequireLogin))
    44  	api.HandleFunc("/campaigns/", Use(API_Campaigns, mid.RequireAPIKey))
    45  	api.HandleFunc("/campaigns/summary", Use(API_Campaigns_Summary, mid.RequireAPIKey))
    46  	api.HandleFunc("/campaigns/{id:[0-9]+}", Use(API_Campaigns_Id, mid.RequireAPIKey))
    47  	api.HandleFunc("/campaigns/{id:[0-9]+}/results", Use(API_Campaigns_Id_Results, mid.RequireAPIKey))
    48  	api.HandleFunc("/campaigns/{id:[0-9]+}/summary", Use(API_Campaign_Id_Summary, mid.RequireAPIKey))
    49  	api.HandleFunc("/campaigns/{id:[0-9]+}/complete", Use(API_Campaigns_Id_Complete, mid.RequireAPIKey))
    50  	api.HandleFunc("/groups/", Use(API_Groups, mid.RequireAPIKey))
    51  	api.HandleFunc("/groups/summary", Use(API_Groups_Summary, mid.RequireAPIKey))
    52  	api.HandleFunc("/groups/{id:[0-9]+}", Use(API_Groups_Id, mid.RequireAPIKey))
    53  	api.HandleFunc("/groups/{id:[0-9]+}/summary", Use(API_Groups_Id_Summary, mid.RequireAPIKey))
    54  	api.HandleFunc("/templates/", Use(API_Templates, mid.RequireAPIKey))
    55  	api.HandleFunc("/templates/{id:[0-9]+}", Use(API_Templates_Id, mid.RequireAPIKey))
    56  	api.HandleFunc("/pages/", Use(API_Pages, mid.RequireAPIKey))
    57  	api.HandleFunc("/pages/{id:[0-9]+}", Use(API_Pages_Id, mid.RequireAPIKey))
    58  	api.HandleFunc("/smtp/", Use(API_SMTP, mid.RequireAPIKey))
    59  	api.HandleFunc("/smtp/{id:[0-9]+}", Use(API_SMTP_Id, mid.RequireAPIKey))
    60  	api.HandleFunc("/util/send_test_email", Use(API_Send_Test_Email, mid.RequireAPIKey))
    61  	api.HandleFunc("/import/group", API_Import_Group)
    62  	api.HandleFunc("/import/email", API_Import_Email)
    63  	api.HandleFunc("/import/site", API_Import_Site)
    64  
    65  	// Setup static file serving
    66  	router.PathPrefix("/").Handler(http.FileServer(http.Dir("./static/")))
    67  
    68  	// Setup CSRF Protection
    69  	csrfHandler := csrf.Protect([]byte(auth.GenerateSecureKey()),
    70  		csrf.FieldName("csrf_token"),
    71  		csrf.Secure(config.Conf.AdminConf.UseTLS))
    72  	csrfRouter := csrfHandler(router)
    73  	return Use(csrfRouter.ServeHTTP, mid.CSRFExceptions, mid.GetContext)
    74  }
    75  
    76  // Use allows us to stack middleware to process the request
    77  // Example taken from https://github.com/gorilla/mux/pull/36#issuecomment-25849172
    78  func Use(handler http.HandlerFunc, mid ...func(http.Handler) http.HandlerFunc) http.HandlerFunc {
    79  	for _, m := range mid {
    80  		handler = m(handler)
    81  	}
    82  	return handler
    83  }
    84  
    85  // Register creates a new user
    86  func Register(w http.ResponseWriter, r *http.Request) {
    87  	// If it is a post request, attempt to register the account
    88  	// Now that we are all registered, we can log the user in
    89  	params := struct {
    90  		Title   string
    91  		Flashes []interface{}
    92  		User    models.User
    93  		Token   string
    94  	}{Title: "Register", Token: csrf.Token(r)}
    95  	session := ctx.Get(r, "session").(*sessions.Session)
    96  	switch {
    97  	case r.Method == "GET":
    98  		params.Flashes = session.Flashes()
    99  		session.Save(r, w)
   100  		templates := template.New("template")
   101  		_, err := templates.ParseFiles("templates/register.html", "templates/flashes.html")
   102  		if err != nil {
   103  			Logger.Println(err)
   104  		}
   105  		template.Must(templates, err).ExecuteTemplate(w, "base", params)
   106  	case r.Method == "POST":
   107  		//Attempt to register
   108  		succ, err := auth.Register(r)
   109  		//If we've registered, redirect to the login page
   110  		if succ {
   111  			session.AddFlash(models.Flash{
   112  				Type:    "success",
   113  				Message: "Registration successful!.",
   114  			})
   115  			session.Save(r, w)
   116  			http.Redirect(w, r, "/login", 302)
   117  			return
   118  		}
   119  		// Check the error
   120  		m := err.Error()
   121  		Logger.Println(err)
   122  		session.AddFlash(models.Flash{
   123  			Type:    "danger",
   124  			Message: m,
   125  		})
   126  		session.Save(r, w)
   127  		http.Redirect(w, r, "/register", 302)
   128  		return
   129  	}
   130  }
   131  
   132  // Base handles the default path and template execution
   133  func Base(w http.ResponseWriter, r *http.Request) {
   134  	params := struct {
   135  		User    models.User
   136  		Title   string
   137  		Flashes []interface{}
   138  		Token   string
   139  	}{Title: "Dashboard", User: ctx.Get(r, "user").(models.User), Token: csrf.Token(r)}
   140  	getTemplate(w, "dashboard").ExecuteTemplate(w, "base", params)
   141  }
   142  
   143  // Campaigns handles the default path and template execution
   144  func Campaigns(w http.ResponseWriter, r *http.Request) {
   145  	// Example of using session - will be removed.
   146  	params := struct {
   147  		User    models.User
   148  		Title   string
   149  		Flashes []interface{}
   150  		Token   string
   151  	}{Title: "Campaigns", User: ctx.Get(r, "user").(models.User), Token: csrf.Token(r)}
   152  	getTemplate(w, "campaigns").ExecuteTemplate(w, "base", params)
   153  }
   154  
   155  // CampaignID handles the default path and template execution
   156  func CampaignID(w http.ResponseWriter, r *http.Request) {
   157  	// Example of using session - will be removed.
   158  	params := struct {
   159  		User    models.User
   160  		Title   string
   161  		Flashes []interface{}
   162  		Token   string
   163  	}{Title: "Campaign Results", User: ctx.Get(r, "user").(models.User), Token: csrf.Token(r)}
   164  	getTemplate(w, "campaign_results").ExecuteTemplate(w, "base", params)
   165  }
   166  
   167  // Templates handles the default path and template execution
   168  func Templates(w http.ResponseWriter, r *http.Request) {
   169  	// Example of using session - will be removed.
   170  	params := struct {
   171  		User    models.User
   172  		Title   string
   173  		Flashes []interface{}
   174  		Token   string
   175  	}{Title: "Email Templates", User: ctx.Get(r, "user").(models.User), Token: csrf.Token(r)}
   176  	getTemplate(w, "templates").ExecuteTemplate(w, "base", params)
   177  }
   178  
   179  // Users handles the default path and template execution
   180  func Users(w http.ResponseWriter, r *http.Request) {
   181  	// Example of using session - will be removed.
   182  	params := struct {
   183  		User    models.User
   184  		Title   string
   185  		Flashes []interface{}
   186  		Token   string
   187  	}{Title: "Users & Groups", User: ctx.Get(r, "user").(models.User), Token: csrf.Token(r)}
   188  	getTemplate(w, "users").ExecuteTemplate(w, "base", params)
   189  }
   190  
   191  // LandingPages handles the default path and template execution
   192  func LandingPages(w http.ResponseWriter, r *http.Request) {
   193  	// Example of using session - will be removed.
   194  	params := struct {
   195  		User    models.User
   196  		Title   string
   197  		Flashes []interface{}
   198  		Token   string
   199  	}{Title: "Landing Pages", User: ctx.Get(r, "user").(models.User), Token: csrf.Token(r)}
   200  	getTemplate(w, "landing_pages").ExecuteTemplate(w, "base", params)
   201  }
   202  
   203  // SendingProfiles handles the default path and template execution
   204  func SendingProfiles(w http.ResponseWriter, r *http.Request) {
   205  	// Example of using session - will be removed.
   206  	params := struct {
   207  		User    models.User
   208  		Title   string
   209  		Flashes []interface{}
   210  		Token   string
   211  	}{Title: "Sending Profiles", User: ctx.Get(r, "user").(models.User), Token: csrf.Token(r)}
   212  	getTemplate(w, "sending_profiles").ExecuteTemplate(w, "base", params)
   213  }
   214  
   215  // Settings handles the changing of settings
   216  func Settings(w http.ResponseWriter, r *http.Request) {
   217  	switch {
   218  	case r.Method == "GET":
   219  		params := struct {
   220  			User    models.User
   221  			Title   string
   222  			Flashes []interface{}
   223  			Token   string
   224  			Version string
   225  		}{Title: "Settings", Version: config.Version, User: ctx.Get(r, "user").(models.User), Token: csrf.Token(r)}
   226  		getTemplate(w, "settings").ExecuteTemplate(w, "base", params)
   227  	case r.Method == "POST":
   228  		err := auth.ChangePassword(r)
   229  		msg := models.Response{Success: true, Message: "Settings Updated Successfully"}
   230  		if err == auth.ErrInvalidPassword {
   231  			msg.Message = "Invalid Password"
   232  			msg.Success = false
   233  			JSONResponse(w, msg, http.StatusBadRequest)
   234  			return
   235  		}
   236  		if err != nil {
   237  			msg.Message = err.Error()
   238  			msg.Success = false
   239  			JSONResponse(w, msg, http.StatusBadRequest)
   240  			return
   241  		}
   242  		JSONResponse(w, msg, http.StatusOK)
   243  	}
   244  }
   245  
   246  // Login handles the authentication flow for a user. If credentials are valid,
   247  // a session is created
   248  func Login(w http.ResponseWriter, r *http.Request) {
   249  	params := struct {
   250  		User    models.User
   251  		Title   string
   252  		Flashes []interface{}
   253  		Token   string
   254  	}{Title: "Login", Token: csrf.Token(r)}
   255  	session := ctx.Get(r, "session").(*sessions.Session)
   256  	switch {
   257  	case r.Method == "GET":
   258  		params.Flashes = session.Flashes()
   259  		session.Save(r, w)
   260  		templates := template.New("template")
   261  		_, err := templates.ParseFiles("templates/login.html", "templates/flashes.html")
   262  		if err != nil {
   263  			Logger.Println(err)
   264  		}
   265  		template.Must(templates, err).ExecuteTemplate(w, "base", params)
   266  	case r.Method == "POST":
   267  		//Attempt to login
   268  		succ, u, err := auth.Login(r)
   269  		if err != nil {
   270  			Logger.Println(err)
   271  		}
   272  		//If we've logged in, save the session and redirect to the dashboard
   273  		if succ {
   274  			session.Values["id"] = u.Id
   275  			session.Save(r, w)
   276  			http.Redirect(w, r, "/", 302)
   277  		} else {
   278  			Flash(w, r, "danger", "Invalid Username/Password")
   279  			http.Redirect(w, r, "/login", 302)
   280  		}
   281  	}
   282  }
   283  
   284  // Logout destroys the current user session
   285  func Logout(w http.ResponseWriter, r *http.Request) {
   286  	// If it is a post request, attempt to register the account
   287  	// Now that we are all registered, we can log the user in
   288  	session := ctx.Get(r, "session").(*sessions.Session)
   289  	delete(session.Values, "id")
   290  	Flash(w, r, "success", "You have successfully logged out")
   291  	http.Redirect(w, r, "/login", 302)
   292  }
   293  
   294  // Preview allows for the viewing of page html in a separate browser window
   295  func Preview(w http.ResponseWriter, r *http.Request) {
   296  	if r.Method != "POST" {
   297  		http.Error(w, "Method not allowed", http.StatusBadRequest)
   298  		return
   299  	}
   300  	fmt.Fprintf(w, "%s", r.FormValue("html"))
   301  }
   302  
   303  // Clone takes a URL as a POST parameter and returns the site HTML
   304  func Clone(w http.ResponseWriter, r *http.Request) {
   305  	vars := mux.Vars(r)
   306  	if r.Method != "POST" {
   307  		http.Error(w, "Method not allowed", http.StatusBadRequest)
   308  		return
   309  	}
   310  	if url, ok := vars["url"]; ok {
   311  		Logger.Println(url)
   312  	}
   313  	http.Error(w, "No URL given.", http.StatusBadRequest)
   314  }
   315  
   316  func getTemplate(w http.ResponseWriter, tmpl string) *template.Template {
   317  	templates := template.New("template")
   318  	_, err := templates.ParseFiles("templates/base.html", "templates/"+tmpl+".html", "templates/flashes.html")
   319  	if err != nil {
   320  		Logger.Println(err)
   321  	}
   322  	return template.Must(templates, err)
   323  }
   324  
   325  // Flash handles the rendering flash messages
   326  func Flash(w http.ResponseWriter, r *http.Request, t string, m string) {
   327  	session := ctx.Get(r, "session").(*sessions.Session)
   328  	session.AddFlash(models.Flash{
   329  		Type:    t,
   330  		Message: m,
   331  	})
   332  	session.Save(r, w)
   333  }