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 }