From 7f084760f94cb3de21b1ce60ed7f1599592418e0 Mon Sep 17 00:00:00 2001 From: Jordan Date: Thu, 9 Jan 2014 00:42:05 -0600 Subject: [PATCH] Major refactoring - created auth, config, models, controllers, and middleware packages. Should help provide modularity and a clean architecture. Added doc.go for each package --- auth/auth.go | 53 ++++++++++++++++++++++++++++++++ lib/middleware.go => auth/doc.go | 16 ++-------- config/config.go | 22 +++++++++++++ lib/auth.go => config/doc.go | 46 ++------------------------- controllers/api.go | 37 ++++++++++++++++++++++ controllers/doc.go | 28 +++++++++++++++++ route.go => controllers/route.go | 17 +++++----- gophish.go | 28 ++++------------- lib/mailer.go | 16 ---------- middleware/doc.go | 29 +++++++++++++++++ middleware/middleware.go | 34 ++++++++++++++++++++ models/doc.go | 28 +++++++++++++++++ models.go => models/models.go | 2 +- setup.go | 24 +++++++++++---- 14 files changed, 267 insertions(+), 113 deletions(-) create mode 100644 auth/auth.go rename lib/middleware.go => auth/doc.go (74%) create mode 100644 config/config.go rename lib/auth.go => config/doc.go (51%) create mode 100644 controllers/api.go create mode 100644 controllers/doc.go rename route.go => controllers/route.go (90%) delete mode 100644 lib/mailer.go create mode 100644 middleware/doc.go create mode 100644 middleware/middleware.go create mode 100644 models/doc.go rename models.go => models/models.go (95%) diff --git a/auth/auth.go b/auth/auth.go new file mode 100644 index 00000000..6de92229 --- /dev/null +++ b/auth/auth.go @@ -0,0 +1,53 @@ +package auth + +import ( + "database/sql" + "net/http" + + "code.google.com/p/go.crypto/bcrypt" + ctx "github.com/gorilla/context" + "github.com/gorilla/securecookie" + "github.com/gorilla/sessions" + "github.com/jordan-wright/gophish/models" +) + +var Store = sessions.NewCookieStore([]byte(securecookie.GenerateRandomKey(64))) + +// CheckLogin attempts to request a SQL record with the given username. +// If successful, it then compares the received bcrypt hash. +// If all checks pass, this function sets the session id for later use. +func CheckLogin(r *http.Request) (bool, error) { + username, password := r.FormValue("username"), r.FormValue("password") + session, _ := Store.Get(r, "gophish") + stmt, err := db.Prepare("SELECT * FROM Users WHERE username=?") + if err != nil { + return false, err + } + hash, err := bcrypt.GenerateFromPassword(password, bcrypt.DefaultCost) + if err != nil { + return false, err + } + u := models.User{} + err = stmt.QueryRow(username).Scan(&u.Id, &u.Username, &u.Hash, &u.APIKey) + if err == sql.ErrNoRows { + return false, err + } + //If we've made it here, we should have a valid user stored in u + //Let's check the password + err = bcrypt.CompareHashAndPassword(u.Hash, hash) + if err != nil { + ctx.Set(r, User, nil) + //Return false, but don't return an error + return false, nil + } + ctx.Set(r, models.User, u) + session.Values["id"] = GetUser(r).Id + return true, nil +} + +func GetUser(r *http.Request) User { + if rv := ctx.Get(r, models.User); rv != nil { + return rv.(models.User) + } + return nil +} diff --git a/lib/middleware.go b/auth/doc.go similarity index 74% rename from lib/middleware.go rename to auth/doc.go index e15ac836..356116ba 100644 --- a/lib/middleware.go +++ b/auth/doc.go @@ -1,5 +1,3 @@ -package main - /* gophish - Open-Source Phishing Framework @@ -26,15 +24,5 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -import "net/http" - -//Use allows us to stack middleware to process the request -//Example taken from https://github.com/gorilla/mux/pull/36#issuecomment-25849172 -func Use(handler http.Handler, middleware ...func(http.Handler) http.Handler) http.Handler { - for _, m := range middleware { - handler = m(handler) - } - return handler -} - -//TODO: Add RequireLogin() Middleware +// Package auth implements the authentication in use for gophish. +package auth diff --git a/config/config.go b/config/config.go new file mode 100644 index 00000000..21e6f701 --- /dev/null +++ b/config/config.go @@ -0,0 +1,22 @@ +package config + +import ( + "encoding/json" + "fmt" + "io/ioutil" + "os" + + "github.com/jordan-wright/gophish/models" +) + +var Conf models.Config + +func init() { + // Get the config file + config_file, err := ioutil.ReadFile("./config.json") + if err != nil { + fmt.Printf("File error: %v\n", err) + os.Exit(1) + } + json.Unmarshal(config_file, &Conf) +} diff --git a/lib/auth.go b/config/doc.go similarity index 51% rename from lib/auth.go rename to config/doc.go index d02ebe9b..56b9a0cb 100644 --- a/lib/auth.go +++ b/config/doc.go @@ -1,5 +1,3 @@ -package main - /* gophish - Open-Source Phishing Framework @@ -26,45 +24,5 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -import ( - "database/sql" - "net/http" - - "code.google.com/p/go.crypto/bcrypt" - ctx "github.com/gorilla/context" -) - -func CheckLogin(r *http.Request) (bool, error) { - username, password := r.FormValue("username"), r.FormValue("password") - session, _ := store.Get(r, "gophish") - stmt, err := db.Prepare("SELECT * FROM Users WHERE username=?") - if err != nil { - return false, err - } - hash, err := bcrypt.GenerateFromPassword(password, bcrypt.DefaultCost) - if err != nil { - return false, err - } - err = stmt.QueryRow(username).Scan(&u.Id, &u.Username, &u.Hash, &u.APIKey) - if err == sql.ErrNoRows { - return false, err - } - //If we've made it here, we should have a valid user stored in u - //Let's check the password - err = bcrypt.CompareHashAndPassword(u.Hash, hash) - if err != nil { - ctx.Set(r, User, nil) - //Return false, but don't return an error - return false, nil - } - ctx.Set(r, User, u) - session.Values["id"] = GetUser(r).Id - return true, nil -} - -func GetUser(r *http.Request) User { - if rv := ctx.Get(r, User); rv != nil { - return rv.(User) - } - return nil -} +// Package config implements a global configuration to be used with gophish. +package config diff --git a/controllers/api.go b/controllers/api.go new file mode 100644 index 00000000..c63cb897 --- /dev/null +++ b/controllers/api.go @@ -0,0 +1,37 @@ +package controllers + +import ( + "fmt" + "net/http" + + "github.com/gorilla/mux" +) + +func API(w http.ResponseWriter, r *http.Request) { + fmt.Fprintf(w, "Hello api") +} + +//API_Campaigns returns a list of campaigns if requested via GET. +//If requested via POST, API_Campaigns creates a new campaign and returns a reference to it. +func API_Campaigns(w http.ResponseWriter, r *http.Request) { + switch { + case r.Method == "GET": + + case r.Method == "POST": + fmt.Fprintf(w, "Hello POST!") + } + fmt.Fprintf(w, "Hello api") +} + +//API_Campaigns_Id returns details about the requested campaign. If the campaign is not +//valid, API_Campaigns_Id returns null. +func API_Campaigns_Id(w http.ResponseWriter, r *http.Request) { + w.Header().Set("Content-Type", "application/json") + vars := mux.Vars(r) + fmt.Fprintf(w, "{\"method\" : \""+r.Method+"\", \"id\" : "+vars["id"]+"}") +} + +//API_Doc renders a template describing the API documentation. +func API_Doc(w http.ResponseWriter, r *http.Request) { + renderTemplate(w, "api_doc") +} diff --git a/controllers/doc.go b/controllers/doc.go new file mode 100644 index 00000000..6cb3d41d --- /dev/null +++ b/controllers/doc.go @@ -0,0 +1,28 @@ +/* +gophish - Open-Source Phishing Framework + +The MIT License (MIT) + +Copyright (c) 2013 Jordan Wright + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ + +// Package controllers is responsible for setting up the routing and controllers (http.Handlers) for gophish. +package controllers diff --git a/route.go b/controllers/route.go similarity index 90% rename from route.go rename to controllers/route.go index 6ec3d3f3..30507bb9 100644 --- a/route.go +++ b/controllers/route.go @@ -1,4 +1,4 @@ -package main +package controllers /* gophish - Open-Source Phishing Framework @@ -31,13 +31,10 @@ import ( "net/http" "github.com/gorilla/mux" - "github.com/gorilla/securecookie" - "github.com/gorilla/sessions" + "github.com/jordan-wright/gophish/auth" ) -var store = sessions.NewCookieStore([]byte(securecookie.GenerateRandomKey(64))) - -func createRouter() http.Handler { +func CreateRouter() http.Handler { router := mux.NewRouter() // Base Front-end routes router.HandleFunc("/", Base) @@ -66,7 +63,7 @@ func Register(w http.ResponseWriter, r *http.Request) { } func Base(w http.ResponseWriter, r *http.Request) { - session, _ := store.Get(r, "gophish") + session, _ := auth.Store.Get(r, "gophish") // Example of using session - will be removed. session.Save(r, w) renderTemplate(w, "dashboard") @@ -81,7 +78,7 @@ func Settings(w http.ResponseWriter, r *http.Request) { } func Base_Campaigns(w http.ResponseWriter, r *http.Request) { - //session, _ := store.Get(r, "gophish") + //session, _ := auth.Store.Get(r, "gophish") renderTemplate(w, "dashboard") } @@ -90,12 +87,12 @@ func Login(w http.ResponseWriter, r *http.Request) { case r.Method == "GET": renderTemplate(w, "login") case r.Method == "POST": - session, _ := store.Get(r, "gophish") + session, _ := auth.Store.Get(r, "gophish") //Attempt to login if err := r.ParseForm(); err != nil { http.Error(w, "Error parsing request", http.StatusInternalServerError) } - succ, err := login(r) + succ, err := auth.CheckLogin(r) if err != nil { http.Error(w, "Error logging in", http.StatusInternalServerError) } diff --git a/gophish.go b/gophish.go index d98b584a..86a8cfce 100644 --- a/gophish.go +++ b/gophish.go @@ -26,39 +26,23 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ import ( - "database/sql" - "encoding/gob" - "encoding/json" "flag" "fmt" - "io/ioutil" "net/http" - "os" + + "github.com/jordan-wright/gophish/controllers" + "github.com/jordan-wright/gophish/middleware" ) -var config Config -var db sql.DB var setupFlag = flag.Bool("setup", false, "Starts the initial setup process for Gophish") -//init registers the necessary models to be saved in the session later -func init() { - gob.Register(&User{}) -} - func main() { - // Get the config file - config_file, err := ioutil.ReadFile("./config.json") - defer db.Close() - if err != nil { - fmt.Printf("File error: %v\n", err) - os.Exit(1) - } - json.Unmarshal(config_file, &config) + //Setup the global variables and settings _, err = Setup() if err != nil { fmt.Println(err) } - fmt.Printf("Gophish server started at http://%s\n", config.URL) - http.Handle("/", createRouter()) + fmt.Printf("Gophish server started at http://%s\n", config.Conf.URL) + http.Handle("/", middleware.Use(controllers.CreateRouter(), middleware.GetContext)) http.ListenAndServe(config.URL, nil) } diff --git a/lib/mailer.go b/lib/mailer.go deleted file mode 100644 index b4aacfe5..00000000 --- a/lib/mailer.go +++ /dev/null @@ -1,16 +0,0 @@ -package main - -import ( - "net/smtp" -) - -//Send sends an Email using a connection to Server. -//If a Username and Password are set for the Server, authentication will be attempted -//However, to support open-relays, authentication is optional. -func Send(email Email, server Server) { - auth := nil - if server.User != nil && server.Password != nil { - auth := smtp.PlainAuth("", server.User, server.Password, server.Host) - } - smtp.SendMail(server.Host, auth, email.From, email.To, Email.Body) -} diff --git a/middleware/doc.go b/middleware/doc.go new file mode 100644 index 00000000..1e33ca37 --- /dev/null +++ b/middleware/doc.go @@ -0,0 +1,29 @@ +/* +gophish - Open-Source Phishing Framework + +The MIT License (MIT) + +Copyright (c) 2013 Jordan Wright + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ + +// Package middleware is responsible for the definition/implementation of middleware functionality. +// This package will also handle maintaining request Context and Session. +package middleware diff --git a/middleware/middleware.go b/middleware/middleware.go new file mode 100644 index 00000000..b5b648fc --- /dev/null +++ b/middleware/middleware.go @@ -0,0 +1,34 @@ +package middleware + +import ( + "fmt" + "net/http" +) + +// Use allows us to stack middleware to process the request +// Example taken from https://github.com/gorilla/mux/pull/36#issuecomment-25849172 +func Use(handler http.Handler, middleware ...func(http.Handler) http.Handler) http.Handler { + for _, m := range middleware { + handler = m(handler) + } + return handler +} + +// GetContext wraps each request in a function which fills in the context for a given request. +// This includes setting the User and Session keys and values as necessary for use in later functions. +func GetContext(handler http.Handler) http.Handler { + // Set the context here + return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + fmt.Println("Get context called!") + handler.ServeHTTP(w, r) + }) +} + +// RequireLogin is a simple middleware which checks to see if the user is currently logged in. +// If not, the function returns a 302 redirect to the login page. +func RequireLogin(handler http.Handler) http.Handler { + return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + fmt.Println("RequireLogin called!!") + handler.ServeHTTP(w, r) + }) +} diff --git a/models/doc.go b/models/doc.go new file mode 100644 index 00000000..55ec82ce --- /dev/null +++ b/models/doc.go @@ -0,0 +1,28 @@ +/* +gophish - Open-Source Phishing Framework + +The MIT License (MIT) + +Copyright (c) 2013 Jordan Wright + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ + +// Package models implements the types and structs needed in gophish. +package models diff --git a/models.go b/models/models.go similarity index 95% rename from models.go rename to models/models.go index e9ff21e2..0e383d18 100644 --- a/models.go +++ b/models/models.go @@ -1,4 +1,4 @@ -package main +package models type SMTPServer struct { Host string `json:"host"` diff --git a/setup.go b/setup.go index 2d60e0c6..5c4c124a 100644 --- a/setup.go +++ b/setup.go @@ -2,20 +2,32 @@ package main import ( "database/sql" + "encoding/gob" "fmt" "os" + "github.com/jordan-wright/gophish/config" + "github.com/jordan-wright/gophish/models" _ "github.com/mattn/go-sqlite3" ) -//Setup creates and returns the database needed by Gophish -func Setup() (*sql.DB, error) { +var Db sql.DB + +//init registers the necessary models to be saved in the session later +func init() { + gob.Register(&models.User{}) + Setup() +} + +// Setup creates and returns the database needed by Gophish. +// It also populates the Gophish Config object +func Setup() { //If the file already exists, delete it and recreate it - if _, err := os.Stat(config.DBPath); err == nil { - os.Remove(config.DBPath) + if _, err := os.Stat(config.Conf.DBPath); err == nil { + os.Remove(Conf.DBPath) } - fmt.Println("Creating db at " + config.DBPath) - db, err := sql.Open("sqlite3", config.DBPath) + fmt.Println("Creating db at " + config.Conf.DBPath) + db, err := sql.Open("sqlite3", config.Conf.DBPath) if err != nil { return nil, err }