mirror of https://github.com/gophish/gophish
231 lines
6.7 KiB
Go
231 lines
6.7 KiB
Go
package controllers
|
|
|
|
import (
|
|
"encoding/json"
|
|
"fmt"
|
|
"net/http"
|
|
"net/mail"
|
|
"strconv"
|
|
"time"
|
|
|
|
ctx "github.com/gorilla/context"
|
|
"github.com/gorilla/mux"
|
|
"github.com/gorilla/sessions"
|
|
"github.com/jordan-wright/gophish/auth"
|
|
"github.com/jordan-wright/gophish/db"
|
|
"github.com/jordan-wright/gophish/models"
|
|
)
|
|
|
|
const (
|
|
IN_PROGRESS string = "In progress"
|
|
WAITING string = "Waiting"
|
|
COMPLETE string = "Completed"
|
|
ERROR string = "Error"
|
|
)
|
|
|
|
// API (/api) provides access to api documentation
|
|
func API(w http.ResponseWriter, r *http.Request) {
|
|
switch {
|
|
case r.Method == "GET":
|
|
getTemplate(w, "api_doc").ExecuteTemplate(w, "base", nil)
|
|
}
|
|
}
|
|
|
|
// API (/api/reset) resets a user's API key
|
|
func API_Reset(w http.ResponseWriter, r *http.Request) {
|
|
switch {
|
|
case r.Method == "POST":
|
|
u := ctx.Get(r, "user").(models.User)
|
|
u.APIKey = auth.GenerateSecureKey()
|
|
db.Conn.Exec("UPDATE users SET api_key=? WHERE id=?", u.APIKey, u.Id)
|
|
session := ctx.Get(r, "session").(*sessions.Session)
|
|
session.AddFlash(models.Flash{
|
|
Type: "success",
|
|
Message: "API Key Successfully Reset",
|
|
})
|
|
session.Save(r, w)
|
|
http.Redirect(w, r, "/settings", 302)
|
|
}
|
|
}
|
|
|
|
// 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":
|
|
cs := []models.Campaign{}
|
|
_, err := db.Conn.Select(&cs, "SELECT c.id, name, created_date, completed_date, status, template FROM campaigns c, users u WHERE c.uid=u.id AND u.api_key=?", ctx.Get(r, "api_key"))
|
|
if err != nil {
|
|
fmt.Println(err)
|
|
}
|
|
/*for c := range cs {
|
|
_, err := db.Conn.Select(&cs.Results, "SELECT r.id ")
|
|
}*/
|
|
cj, err := json.MarshalIndent(cs, "", " ")
|
|
if checkError(err, w, "Error looking up campaigns") {
|
|
return
|
|
}
|
|
writeJSON(w, cj)
|
|
//POST: Create a new campaign and return it as JSON
|
|
case r.Method == "POST":
|
|
c := models.Campaign{}
|
|
// Put the request into a campaign
|
|
err := json.NewDecoder(r.Body).Decode(&c)
|
|
if checkError(err, w, "Invalid Request") {
|
|
return
|
|
}
|
|
// Fill in the details
|
|
c.CreatedDate = time.Now()
|
|
c.CompletedDate = time.Time{}
|
|
c.Status = IN_PROGRESS
|
|
c.Uid = ctx.Get(r, "user_id").(int64)
|
|
// Insert into the DB
|
|
err = db.Conn.Insert(&c)
|
|
if checkError(err, w, "Cannot insert campaign into database") {
|
|
return
|
|
}
|
|
cj, err := json.MarshalIndent(c, "", " ")
|
|
if checkError(err, w, "Error creating JSON response") {
|
|
return
|
|
}
|
|
writeJSON(w, cj)
|
|
}
|
|
}
|
|
|
|
// 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) {
|
|
vars := mux.Vars(r)
|
|
id, err := strconv.ParseInt(vars["id"], 0, 64)
|
|
if checkError(err, w, "Invalid Int") {
|
|
return
|
|
}
|
|
switch {
|
|
case r.Method == "GET":
|
|
c := models.Campaign{}
|
|
err := db.Conn.SelectOne(&c, "SELECT campaigns.id, name, created_date, completed_date, status, template FROM campaigns, users WHERE campaigns.uid=users.id AND campaigns.id =? AND users.api_key=?", id, ctx.Get(r, "api_key"))
|
|
if checkError(err, w, "No campaign found") {
|
|
return
|
|
}
|
|
cj, err := json.MarshalIndent(c, "", " ")
|
|
if checkError(err, w, "Error creating JSON response") {
|
|
return
|
|
}
|
|
writeJSON(w, cj)
|
|
case r.Method == "DELETE":
|
|
//c := models.Campaign{}
|
|
}
|
|
}
|
|
|
|
func API_Campaigns_Id_Launch(w http.ResponseWriter, r *http.Request) {
|
|
http.Redirect(w, r, "/", 302)
|
|
}
|
|
|
|
// API_Groups returns details about the requested group. If the campaign is not
|
|
// valid, API_Groups returns null.
|
|
// Example:
|
|
/*
|
|
POST /api/groups
|
|
{ "name" : "Test Group",
|
|
"targets" : [
|
|
{
|
|
"email" : "test@example.com"
|
|
},
|
|
{ "email" : test2@example.com"
|
|
}]
|
|
}
|
|
|
|
RESULT { "name" : "Test Group",
|
|
"targets" : ["test@example.com", "test2@example.com"]
|
|
"id" : 1
|
|
}
|
|
*/
|
|
func API_Groups(w http.ResponseWriter, r *http.Request) {
|
|
switch {
|
|
case r.Method == "GET":
|
|
gs := []models.Group{}
|
|
_, err := db.Conn.Select(&gs, "SELECT g.id, g.name, g.modified_date FROM groups g, users u, user_groups ug WHERE ug.uid=u.id AND ug.gid=g.id AND u.api_key=?", ctx.Get(r, "api_key"))
|
|
if err != nil {
|
|
fmt.Println(err)
|
|
}
|
|
for i, _ := range gs {
|
|
_, err := db.Conn.Select(&gs[i].Targets, "SELECT t.id, t.email FROM targets t, groups g, group_targets gt WHERE gt.gid=? AND gt.tid=t.id", gs[i].Id)
|
|
if checkError(err, w, "Error looking up groups") {
|
|
return
|
|
}
|
|
}
|
|
gj, err := json.MarshalIndent(gs, "", " ")
|
|
if checkError(err, w, "Error looking up groups") {
|
|
return
|
|
}
|
|
writeJSON(w, gj)
|
|
//POST: Create a new group and return it as JSON
|
|
case r.Method == "POST":
|
|
g := models.Group{}
|
|
// Put the request into a group
|
|
err := json.NewDecoder(r.Body).Decode(&g)
|
|
if checkError(err, w, "Invalid Request") {
|
|
return
|
|
}
|
|
// Check to make sure targets were specified
|
|
if len(g.Targets) == 0 {
|
|
http.Error(w, "Error: No targets specified", http.StatusInternalServerError)
|
|
return
|
|
}
|
|
g.ModifiedDate = time.Now()
|
|
// Insert into the DB
|
|
err = db.Conn.Insert(&g)
|
|
if checkError(err, w, "Cannot insert group into database") {
|
|
return
|
|
}
|
|
// Let's start a transaction to handle the bulk inserting
|
|
trans, err := db.Conn.Begin()
|
|
if checkError(err, w, "Error starting transaction to insert data") {
|
|
return
|
|
}
|
|
// Now, let's add the user->user_groups->group mapping
|
|
_, err = db.Conn.Exec("INSERT OR IGNORE INTO user_groups VALUES (?,?)", ctx.Get(r, "user_id").(int64), g.Id)
|
|
if err != nil {
|
|
fmt.Printf("Error adding many-many mapping for group %s\n", g.Name)
|
|
}
|
|
// TODO
|
|
for _, t := range g.Targets {
|
|
if _, err = mail.ParseAddress(t.Email); err != nil {
|
|
fmt.Printf("Found invalid email %s\n", t.Email)
|
|
continue
|
|
}
|
|
res, err := db.Conn.Exec("INSERT OR IGNORE INTO targets VALUES (null, ?)", t.Email)
|
|
if err != nil {
|
|
fmt.Printf("Error adding email: %s\n", t.Email)
|
|
}
|
|
t.Id, err = res.LastInsertId()
|
|
if err != nil {
|
|
fmt.Printf("Error getting last insert id for email: %s\n", t.Email)
|
|
}
|
|
_, err = db.Conn.Exec("INSERT OR IGNORE INTO group_targets VALUES (?,?)", g.Id, t.Id)
|
|
if err != nil {
|
|
fmt.Printf("Error adding many-many mapping for %s\n", t.Email)
|
|
}
|
|
}
|
|
if checkError(trans.Commit(), w, "Error committing transaction") {
|
|
return
|
|
}
|
|
gj, err := json.MarshalIndent(g, "", " ")
|
|
if checkError(err, w, "Error creating JSON response") {
|
|
return
|
|
}
|
|
writeJSON(w, gj)
|
|
}
|
|
}
|
|
|
|
// API_Campaigns_Id returns details about the requested campaign. If the campaign is not
|
|
// valid, API_Campaigns_Id returns null.
|
|
func API_Groups_Id(w http.ResponseWriter, r *http.Request) {
|
|
http.Redirect(w, r, "/", 302)
|
|
}
|
|
|
|
func writeJSON(w http.ResponseWriter, c []byte) {
|
|
w.Header().Set("Content-Type", "application/json")
|
|
fmt.Fprintf(w, "%s", c)
|
|
}
|