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

     1  package controllers
     2  
     3  import (
     4  	"bytes"
     5  	"crypto/tls"
     6  	"encoding/json"
     7  	"errors"
     8  	"fmt"
     9  	"net/http"
    10  	"strconv"
    11  	"strings"
    12  	"text/template"
    13  	"time"
    14  
    15  	"github.com/PuerkitoBio/goquery"
    16  	"github.com/gophish/gophish/auth"
    17  	ctx "github.com/gophish/gophish/context"
    18  	"github.com/gophish/gophish/models"
    19  	"github.com/gophish/gophish/util"
    20  	"github.com/gophish/gophish/worker"
    21  	"github.com/gorilla/mux"
    22  	"github.com/jinzhu/gorm"
    23  	"github.com/jordan-wright/email"
    24  )
    25  
    26  // Worker is the worker that processes phishing events and updates campaigns.
    27  var Worker *worker.Worker
    28  
    29  func init() {
    30  	Worker = worker.New()
    31  	go Worker.Start()
    32  }
    33  
    34  // API (/api) provides access to api documentation
    35  func API(w http.ResponseWriter, r *http.Request) {
    36  	switch {
    37  	case r.Method == "GET":
    38  		templates := template.New("template")
    39  		_, err := templates.ParseFiles("templates/docs.html")
    40  		if err != nil {
    41  			Logger.Println(err)
    42  		}
    43  		template.Must(templates, err).ExecuteTemplate(w, "base", nil)
    44  	}
    45  }
    46  
    47  // API (/api/reset) resets a user's API key
    48  func API_Reset(w http.ResponseWriter, r *http.Request) {
    49  	switch {
    50  	case r.Method == "POST":
    51  		u := ctx.Get(r, "user").(models.User)
    52  		u.ApiKey = auth.GenerateSecureKey()
    53  		err := models.PutUser(&u)
    54  		if err != nil {
    55  			http.Error(w, "Error setting API Key", http.StatusInternalServerError)
    56  		} else {
    57  			JSONResponse(w, models.Response{Success: true, Message: "API Key successfully reset!", Data: u.ApiKey}, http.StatusOK)
    58  		}
    59  	}
    60  }
    61  
    62  // API_Campaigns returns a list of campaigns if requested via GET.
    63  // If requested via POST, API_Campaigns creates a new campaign and returns a reference to it.
    64  func API_Campaigns(w http.ResponseWriter, r *http.Request) {
    65  	switch {
    66  	case r.Method == "GET":
    67  		cs, err := models.GetCampaigns(ctx.Get(r, "user_id").(int64))
    68  		if err != nil {
    69  			Logger.Println(err)
    70  		}
    71  		JSONResponse(w, cs, http.StatusOK)
    72  	//POST: Create a new campaign and return it as JSON
    73  	case r.Method == "POST":
    74  		c := models.Campaign{}
    75  		// Put the request into a campaign
    76  		err := json.NewDecoder(r.Body).Decode(&c)
    77  		if err != nil {
    78  			JSONResponse(w, models.Response{Success: false, Message: "Invalid JSON structure"}, http.StatusBadRequest)
    79  			return
    80  		}
    81  		err = models.PostCampaign(&c, ctx.Get(r, "user_id").(int64))
    82  		if err != nil {
    83  			JSONResponse(w, models.Response{Success: false, Message: err.Error()}, http.StatusBadRequest)
    84  			return
    85  		}
    86  		JSONResponse(w, c, http.StatusCreated)
    87  	}
    88  }
    89  
    90  // API_Campaigns_Summary returns the summary for the current user's campaigns
    91  func API_Campaigns_Summary(w http.ResponseWriter, r *http.Request) {
    92  	switch {
    93  	case r.Method == "GET":
    94  		cs, err := models.GetCampaignSummaries(ctx.Get(r, "user_id").(int64))
    95  		if err != nil {
    96  			Logger.Println(err)
    97  			JSONResponse(w, models.Response{Success: false, Message: err.Error()}, http.StatusInternalServerError)
    98  			return
    99  		}
   100  		JSONResponse(w, cs, http.StatusOK)
   101  	}
   102  }
   103  
   104  // API_Campaigns_Id returns details about the requested campaign. If the campaign is not
   105  // valid, API_Campaigns_Id returns null.
   106  func API_Campaigns_Id(w http.ResponseWriter, r *http.Request) {
   107  	vars := mux.Vars(r)
   108  	id, _ := strconv.ParseInt(vars["id"], 0, 64)
   109  	c, err := models.GetCampaign(id, ctx.Get(r, "user_id").(int64))
   110  	if err != nil {
   111  		Logger.Println(err)
   112  		JSONResponse(w, models.Response{Success: false, Message: "Campaign not found"}, http.StatusNotFound)
   113  		return
   114  	}
   115  	switch {
   116  	case r.Method == "GET":
   117  		JSONResponse(w, c, http.StatusOK)
   118  	case r.Method == "DELETE":
   119  		err = models.DeleteCampaign(id)
   120  		if err != nil {
   121  			JSONResponse(w, models.Response{Success: false, Message: "Error deleting campaign"}, http.StatusInternalServerError)
   122  			return
   123  		}
   124  		JSONResponse(w, models.Response{Success: true, Message: "Campaign deleted successfully!"}, http.StatusOK)
   125  	}
   126  }
   127  
   128  // API_Campaigns_Id_Results returns just the results for a given campaign to
   129  // significantly reduce the information returned.
   130  func API_Campaigns_Id_Results(w http.ResponseWriter, r *http.Request) {
   131  	vars := mux.Vars(r)
   132  	id, _ := strconv.ParseInt(vars["id"], 0, 64)
   133  	cr, err := models.GetCampaignResults(id, ctx.Get(r, "user_id").(int64))
   134  	if err != nil {
   135  		Logger.Println(err)
   136  		JSONResponse(w, models.Response{Success: false, Message: "Campaign not found"}, http.StatusNotFound)
   137  		return
   138  	}
   139  	if r.Method == "GET" {
   140  		JSONResponse(w, cr, http.StatusOK)
   141  		return
   142  	}
   143  }
   144  
   145  // API_Campaigns_Id_Summary returns just the summary for a given campaign.
   146  func API_Campaign_Id_Summary(w http.ResponseWriter, r *http.Request) {
   147  	vars := mux.Vars(r)
   148  	id, _ := strconv.ParseInt(vars["id"], 0, 64)
   149  	switch {
   150  	case r.Method == "GET":
   151  		cs, err := models.GetCampaignSummary(id, ctx.Get(r, "user_id").(int64))
   152  		if err != nil {
   153  			if err == gorm.ErrRecordNotFound {
   154  				JSONResponse(w, models.Response{Success: false, Message: "Campaign not found"}, http.StatusNotFound)
   155  			} else {
   156  				JSONResponse(w, models.Response{Success: false, Message: err.Error()}, http.StatusInternalServerError)
   157  			}
   158  			Logger.Println(err)
   159  			return
   160  		}
   161  		JSONResponse(w, cs, http.StatusOK)
   162  	}
   163  }
   164  
   165  // API_Campaigns_Id_Complete effectively "ends" a campaign.
   166  // Future phishing emails clicked will return a simple "404" page.
   167  func API_Campaigns_Id_Complete(w http.ResponseWriter, r *http.Request) {
   168  	vars := mux.Vars(r)
   169  	id, _ := strconv.ParseInt(vars["id"], 0, 64)
   170  	switch {
   171  	case r.Method == "GET":
   172  		err := models.CompleteCampaign(id, ctx.Get(r, "user_id").(int64))
   173  		if err != nil {
   174  			JSONResponse(w, models.Response{Success: false, Message: "Error completing campaign"}, http.StatusInternalServerError)
   175  			return
   176  		}
   177  		JSONResponse(w, models.Response{Success: true, Message: "Campaign completed successfully!"}, http.StatusOK)
   178  	}
   179  }
   180  
   181  // API_Groups returns a list of groups if requested via GET.
   182  // If requested via POST, API_Groups creates a new group and returns a reference to it.
   183  func API_Groups(w http.ResponseWriter, r *http.Request) {
   184  	switch {
   185  	case r.Method == "GET":
   186  		gs, err := models.GetGroups(ctx.Get(r, "user_id").(int64))
   187  		if err != nil {
   188  			JSONResponse(w, models.Response{Success: false, Message: "No groups found"}, http.StatusNotFound)
   189  			return
   190  		}
   191  		JSONResponse(w, gs, http.StatusOK)
   192  	//POST: Create a new group and return it as JSON
   193  	case r.Method == "POST":
   194  		g := models.Group{}
   195  		// Put the request into a group
   196  		err := json.NewDecoder(r.Body).Decode(&g)
   197  		if err != nil {
   198  			JSONResponse(w, models.Response{Success: false, Message: "Invalid JSON structure"}, http.StatusBadRequest)
   199  			return
   200  		}
   201  		_, err = models.GetGroupByName(g.Name, ctx.Get(r, "user_id").(int64))
   202  		if err != gorm.ErrRecordNotFound {
   203  			JSONResponse(w, models.Response{Success: false, Message: "Group name already in use"}, http.StatusConflict)
   204  			return
   205  		}
   206  		g.ModifiedDate = time.Now().UTC()
   207  		g.UserId = ctx.Get(r, "user_id").(int64)
   208  		err = models.PostGroup(&g)
   209  		if err != nil {
   210  			JSONResponse(w, models.Response{Success: false, Message: err.Error()}, http.StatusBadRequest)
   211  			return
   212  		}
   213  		JSONResponse(w, g, http.StatusCreated)
   214  	}
   215  }
   216  
   217  // API_Groups_Summary returns a summary of the groups owned by the current user.
   218  func API_Groups_Summary(w http.ResponseWriter, r *http.Request) {
   219  	switch {
   220  	case r.Method == "GET":
   221  		gs, err := models.GetGroupSummaries(ctx.Get(r, "user_id").(int64))
   222  		if err != nil {
   223  			Logger.Println(err)
   224  			JSONResponse(w, models.Response{Success: false, Message: err.Error()}, http.StatusInternalServerError)
   225  			return
   226  		}
   227  		JSONResponse(w, gs, http.StatusOK)
   228  	}
   229  }
   230  
   231  // API_Groups_Id returns details about the requested group.
   232  // If the group is not valid, API_Groups_Id returns null.
   233  func API_Groups_Id(w http.ResponseWriter, r *http.Request) {
   234  	vars := mux.Vars(r)
   235  	id, _ := strconv.ParseInt(vars["id"], 0, 64)
   236  	g, err := models.GetGroup(id, ctx.Get(r, "user_id").(int64))
   237  	if err != nil {
   238  		JSONResponse(w, models.Response{Success: false, Message: "Group not found"}, http.StatusNotFound)
   239  		return
   240  	}
   241  	switch {
   242  	case r.Method == "GET":
   243  		JSONResponse(w, g, http.StatusOK)
   244  	case r.Method == "DELETE":
   245  		err = models.DeleteGroup(&g)
   246  		if err != nil {
   247  			JSONResponse(w, models.Response{Success: false, Message: "Error deleting group"}, http.StatusInternalServerError)
   248  			return
   249  		}
   250  		JSONResponse(w, models.Response{Success: true, Message: "Group deleted successfully!"}, http.StatusOK)
   251  	case r.Method == "PUT":
   252  		// Change this to get from URL and uid (don't bother with id in r.Body)
   253  		g = models.Group{}
   254  		err = json.NewDecoder(r.Body).Decode(&g)
   255  		if g.Id != id {
   256  			JSONResponse(w, models.Response{Success: false, Message: "Error: /:id and group_id mismatch"}, http.StatusInternalServerError)
   257  			return
   258  		}
   259  		g.ModifiedDate = time.Now().UTC()
   260  		g.UserId = ctx.Get(r, "user_id").(int64)
   261  		err = models.PutGroup(&g)
   262  		if err != nil {
   263  			JSONResponse(w, models.Response{Success: false, Message: err.Error()}, http.StatusBadRequest)
   264  			return
   265  		}
   266  		JSONResponse(w, g, http.StatusOK)
   267  	}
   268  }
   269  
   270  // API_Groups_Id_Summary returns a summary of the groups owned by the current user.
   271  func API_Groups_Id_Summary(w http.ResponseWriter, r *http.Request) {
   272  	switch {
   273  	case r.Method == "GET":
   274  		vars := mux.Vars(r)
   275  		id, _ := strconv.ParseInt(vars["id"], 0, 64)
   276  		g, err := models.GetGroupSummary(id, ctx.Get(r, "user_id").(int64))
   277  		if err != nil {
   278  			JSONResponse(w, models.Response{Success: false, Message: "Group not found"}, http.StatusNotFound)
   279  			return
   280  		}
   281  		JSONResponse(w, g, http.StatusOK)
   282  	}
   283  }
   284  
   285  // API_Templates handles the functionality for the /api/templates endpoint
   286  func API_Templates(w http.ResponseWriter, r *http.Request) {
   287  	switch {
   288  	case r.Method == "GET":
   289  		ts, err := models.GetTemplates(ctx.Get(r, "user_id").(int64))
   290  		if err != nil {
   291  			Logger.Println(err)
   292  		}
   293  		JSONResponse(w, ts, http.StatusOK)
   294  	//POST: Create a new template and return it as JSON
   295  	case r.Method == "POST":
   296  		t := models.Template{}
   297  		// Put the request into a template
   298  		err := json.NewDecoder(r.Body).Decode(&t)
   299  		if err != nil {
   300  			JSONResponse(w, models.Response{Success: false, Message: "Invalid JSON structure"}, http.StatusBadRequest)
   301  			return
   302  		}
   303  		_, err = models.GetTemplateByName(t.Name, ctx.Get(r, "user_id").(int64))
   304  		if err != gorm.ErrRecordNotFound {
   305  			JSONResponse(w, models.Response{Success: false, Message: "Template name already in use"}, http.StatusConflict)
   306  			return
   307  		}
   308  		t.ModifiedDate = time.Now().UTC()
   309  		t.UserId = ctx.Get(r, "user_id").(int64)
   310  		err = models.PostTemplate(&t)
   311  		if err == models.ErrTemplateNameNotSpecified {
   312  			JSONResponse(w, models.Response{Success: false, Message: err.Error()}, http.StatusBadRequest)
   313  			return
   314  		}
   315  		if err == models.ErrTemplateMissingParameter {
   316  			JSONResponse(w, models.Response{Success: false, Message: err.Error()}, http.StatusBadRequest)
   317  			return
   318  		}
   319  		if err != nil {
   320  			JSONResponse(w, models.Response{Success: false, Message: "Error inserting template into database"}, http.StatusInternalServerError)
   321  			Logger.Println(err)
   322  			return
   323  		}
   324  		JSONResponse(w, t, http.StatusCreated)
   325  	}
   326  }
   327  
   328  // API_Templates_Id handles the functions for the /api/templates/:id endpoint
   329  func API_Templates_Id(w http.ResponseWriter, r *http.Request) {
   330  	vars := mux.Vars(r)
   331  	id, _ := strconv.ParseInt(vars["id"], 0, 64)
   332  	t, err := models.GetTemplate(id, ctx.Get(r, "user_id").(int64))
   333  	if err != nil {
   334  		JSONResponse(w, models.Response{Success: false, Message: "Template not found"}, http.StatusNotFound)
   335  		return
   336  	}
   337  	switch {
   338  	case r.Method == "GET":
   339  		JSONResponse(w, t, http.StatusOK)
   340  	case r.Method == "DELETE":
   341  		err = models.DeleteTemplate(id, ctx.Get(r, "user_id").(int64))
   342  		if err != nil {
   343  			JSONResponse(w, models.Response{Success: false, Message: "Error deleting template"}, http.StatusInternalServerError)
   344  			return
   345  		}
   346  		JSONResponse(w, models.Response{Success: true, Message: "Template deleted successfully!"}, http.StatusOK)
   347  	case r.Method == "PUT":
   348  		t = models.Template{}
   349  		err = json.NewDecoder(r.Body).Decode(&t)
   350  		if err != nil {
   351  			Logger.Println(err)
   352  		}
   353  		if t.Id != id {
   354  			JSONResponse(w, models.Response{Success: false, Message: "Error: /:id and template_id mismatch"}, http.StatusBadRequest)
   355  			return
   356  		}
   357  		t.ModifiedDate = time.Now().UTC()
   358  		t.UserId = ctx.Get(r, "user_id").(int64)
   359  		err = models.PutTemplate(&t)
   360  		if err != nil {
   361  			JSONResponse(w, models.Response{Success: false, Message: err.Error()}, http.StatusBadRequest)
   362  			return
   363  		}
   364  		JSONResponse(w, t, http.StatusOK)
   365  	}
   366  }
   367  
   368  // API_Pages handles requests for the /api/pages/ endpoint
   369  func API_Pages(w http.ResponseWriter, r *http.Request) {
   370  	switch {
   371  	case r.Method == "GET":
   372  		ps, err := models.GetPages(ctx.Get(r, "user_id").(int64))
   373  		if err != nil {
   374  			Logger.Println(err)
   375  		}
   376  		JSONResponse(w, ps, http.StatusOK)
   377  	//POST: Create a new page and return it as JSON
   378  	case r.Method == "POST":
   379  		p := models.Page{}
   380  		// Put the request into a page
   381  		err := json.NewDecoder(r.Body).Decode(&p)
   382  		if err != nil {
   383  			JSONResponse(w, models.Response{Success: false, Message: "Invalid request"}, http.StatusBadRequest)
   384  			return
   385  		}
   386  		// Check to make sure the name is unique
   387  		_, err = models.GetPageByName(p.Name, ctx.Get(r, "user_id").(int64))
   388  		if err != gorm.ErrRecordNotFound {
   389  			JSONResponse(w, models.Response{Success: false, Message: "Page name already in use"}, http.StatusConflict)
   390  			Logger.Println(err)
   391  			return
   392  		}
   393  		p.ModifiedDate = time.Now().UTC()
   394  		p.UserId = ctx.Get(r, "user_id").(int64)
   395  		err = models.PostPage(&p)
   396  		if err != nil {
   397  			JSONResponse(w, models.Response{Success: false, Message: err.Error()}, http.StatusInternalServerError)
   398  			return
   399  		}
   400  		JSONResponse(w, p, http.StatusCreated)
   401  	}
   402  }
   403  
   404  // API_Pages_Id contains functions to handle the GET'ing, DELETE'ing, and PUT'ing
   405  // of a Page object
   406  func API_Pages_Id(w http.ResponseWriter, r *http.Request) {
   407  	vars := mux.Vars(r)
   408  	id, _ := strconv.ParseInt(vars["id"], 0, 64)
   409  	p, err := models.GetPage(id, ctx.Get(r, "user_id").(int64))
   410  	if err != nil {
   411  		JSONResponse(w, models.Response{Success: false, Message: "Page not found"}, http.StatusNotFound)
   412  		return
   413  	}
   414  	switch {
   415  	case r.Method == "GET":
   416  		JSONResponse(w, p, http.StatusOK)
   417  	case r.Method == "DELETE":
   418  		err = models.DeletePage(id, ctx.Get(r, "user_id").(int64))
   419  		if err != nil {
   420  			JSONResponse(w, models.Response{Success: false, Message: "Error deleting page"}, http.StatusInternalServerError)
   421  			return
   422  		}
   423  		JSONResponse(w, models.Response{Success: true, Message: "Page Deleted Successfully"}, http.StatusOK)
   424  	case r.Method == "PUT":
   425  		p = models.Page{}
   426  		err = json.NewDecoder(r.Body).Decode(&p)
   427  		if err != nil {
   428  			Logger.Println(err)
   429  		}
   430  		if p.Id != id {
   431  			JSONResponse(w, models.Response{Success: false, Message: "/:id and /:page_id mismatch"}, http.StatusBadRequest)
   432  			return
   433  		}
   434  		p.ModifiedDate = time.Now().UTC()
   435  		p.UserId = ctx.Get(r, "user_id").(int64)
   436  		err = models.PutPage(&p)
   437  		if err != nil {
   438  			JSONResponse(w, models.Response{Success: false, Message: "Error updating page: " + err.Error()}, http.StatusInternalServerError)
   439  			return
   440  		}
   441  		JSONResponse(w, p, http.StatusOK)
   442  	}
   443  }
   444  
   445  // API_SMTP handles requests for the /api/smtp/ endpoint
   446  func API_SMTP(w http.ResponseWriter, r *http.Request) {
   447  	switch {
   448  	case r.Method == "GET":
   449  		ss, err := models.GetSMTPs(ctx.Get(r, "user_id").(int64))
   450  		if err != nil {
   451  			Logger.Println(err)
   452  		}
   453  		JSONResponse(w, ss, http.StatusOK)
   454  	//POST: Create a new SMTP and return it as JSON
   455  	case r.Method == "POST":
   456  		s := models.SMTP{}
   457  		// Put the request into a page
   458  		err := json.NewDecoder(r.Body).Decode(&s)
   459  		if err != nil {
   460  			JSONResponse(w, models.Response{Success: false, Message: "Invalid request"}, http.StatusBadRequest)
   461  			return
   462  		}
   463  		// Check to make sure the name is unique
   464  		_, err = models.GetSMTPByName(s.Name, ctx.Get(r, "user_id").(int64))
   465  		if err != gorm.ErrRecordNotFound {
   466  			JSONResponse(w, models.Response{Success: false, Message: "SMTP name already in use"}, http.StatusConflict)
   467  			Logger.Println(err)
   468  			return
   469  		}
   470  		s.ModifiedDate = time.Now().UTC()
   471  		s.UserId = ctx.Get(r, "user_id").(int64)
   472  		err = models.PostSMTP(&s)
   473  		if err != nil {
   474  			JSONResponse(w, models.Response{Success: false, Message: err.Error()}, http.StatusInternalServerError)
   475  			return
   476  		}
   477  		JSONResponse(w, s, http.StatusCreated)
   478  	}
   479  }
   480  
   481  // API_SMTP_Id contains functions to handle the GET'ing, DELETE'ing, and PUT'ing
   482  // of a SMTP object
   483  func API_SMTP_Id(w http.ResponseWriter, r *http.Request) {
   484  	vars := mux.Vars(r)
   485  	id, _ := strconv.ParseInt(vars["id"], 0, 64)
   486  	s, err := models.GetSMTP(id, ctx.Get(r, "user_id").(int64))
   487  	if err != nil {
   488  		JSONResponse(w, models.Response{Success: false, Message: "SMTP not found"}, http.StatusNotFound)
   489  		return
   490  	}
   491  	switch {
   492  	case r.Method == "GET":
   493  		JSONResponse(w, s, http.StatusOK)
   494  	case r.Method == "DELETE":
   495  		err = models.DeleteSMTP(id, ctx.Get(r, "user_id").(int64))
   496  		if err != nil {
   497  			JSONResponse(w, models.Response{Success: false, Message: "Error deleting SMTP"}, http.StatusInternalServerError)
   498  			return
   499  		}
   500  		JSONResponse(w, models.Response{Success: true, Message: "SMTP Deleted Successfully"}, http.StatusOK)
   501  	case r.Method == "PUT":
   502  		s = models.SMTP{}
   503  		err = json.NewDecoder(r.Body).Decode(&s)
   504  		if err != nil {
   505  			Logger.Println(err)
   506  		}
   507  		if s.Id != id {
   508  			JSONResponse(w, models.Response{Success: false, Message: "/:id and /:smtp_id mismatch"}, http.StatusBadRequest)
   509  			return
   510  		}
   511  		err = s.Validate()
   512  		if err != nil {
   513  			JSONResponse(w, models.Response{Success: false, Message: err.Error()}, http.StatusBadRequest)
   514  			return
   515  		}
   516  		s.ModifiedDate = time.Now().UTC()
   517  		s.UserId = ctx.Get(r, "user_id").(int64)
   518  		err = models.PutSMTP(&s)
   519  		if err != nil {
   520  			JSONResponse(w, models.Response{Success: false, Message: "Error updating page"}, http.StatusInternalServerError)
   521  			return
   522  		}
   523  		JSONResponse(w, s, http.StatusOK)
   524  	}
   525  }
   526  
   527  // API_Import_Group imports a CSV of group members
   528  func API_Import_Group(w http.ResponseWriter, r *http.Request) {
   529  	ts, err := util.ParseCSV(r)
   530  	if err != nil {
   531  		JSONResponse(w, models.Response{Success: false, Message: "Error parsing CSV"}, http.StatusInternalServerError)
   532  		return
   533  	}
   534  	JSONResponse(w, ts, http.StatusOK)
   535  	return
   536  }
   537  
   538  // API_Import_Email allows for the importing of email.
   539  // Returns a Message object
   540  func API_Import_Email(w http.ResponseWriter, r *http.Request) {
   541  	if r.Method != "POST" {
   542  		JSONResponse(w, models.Response{Success: false, Message: "Method not allowed"}, http.StatusBadRequest)
   543  		return
   544  	}
   545  	ir := struct {
   546  		Content      string `json:"content"`
   547  		ConvertLinks bool   `json:"convert_links"`
   548  	}{}
   549  	err := json.NewDecoder(r.Body).Decode(&ir)
   550  	if err != nil {
   551  		JSONResponse(w, models.Response{Success: false, Message: "Error decoding JSON Request"}, http.StatusBadRequest)
   552  		return
   553  	}
   554  	e, err := email.NewEmailFromReader(strings.NewReader(ir.Content))
   555  	if err != nil {
   556  		Logger.Println(err)
   557  	}
   558  	// If the user wants to convert links to point to
   559  	// the landing page, let's make it happen by changing up
   560  	// e.HTML
   561  	if ir.ConvertLinks {
   562  		d, err := goquery.NewDocumentFromReader(bytes.NewReader(e.HTML))
   563  		if err != nil {
   564  			JSONResponse(w, models.Response{Success: false, Message: err.Error()}, http.StatusBadRequest)
   565  			return
   566  		}
   567  		d.Find("a").Each(func(i int, a *goquery.Selection) {
   568  			a.SetAttr("href", "{{.URL}}")
   569  		})
   570  		h, err := d.Html()
   571  		if err != nil {
   572  			JSONResponse(w, models.Response{Success: false, Message: err.Error()}, http.StatusInternalServerError)
   573  			return
   574  		}
   575  		e.HTML = []byte(h)
   576  	}
   577  	er := emailResponse{
   578  		Subject: e.Subject,
   579  		Text:    string(e.Text),
   580  		HTML:    string(e.HTML),
   581  	}
   582  	JSONResponse(w, er, http.StatusOK)
   583  	return
   584  }
   585  
   586  // API_Import_Site allows for the importing of HTML from a website
   587  // Without "include_resources" set, it will merely place a "base" tag
   588  // so that all resources can be loaded relative to the given URL.
   589  func API_Import_Site(w http.ResponseWriter, r *http.Request) {
   590  	cr := cloneRequest{}
   591  	if r.Method != "POST" {
   592  		JSONResponse(w, models.Response{Success: false, Message: "Method not allowed"}, http.StatusBadRequest)
   593  		return
   594  	}
   595  	err := json.NewDecoder(r.Body).Decode(&cr)
   596  	if err != nil {
   597  		JSONResponse(w, models.Response{Success: false, Message: "Error decoding JSON Request"}, http.StatusBadRequest)
   598  		return
   599  	}
   600  	if err = cr.validate(); err != nil {
   601  		JSONResponse(w, models.Response{Success: false, Message: err.Error()}, http.StatusBadRequest)
   602  		return
   603  	}
   604  	tr := &http.Transport{
   605  		TLSClientConfig: &tls.Config{
   606  			InsecureSkipVerify: true,
   607  		},
   608  	}
   609  	client := &http.Client{Transport: tr}
   610  	resp, err := client.Get(cr.URL)
   611  	if err != nil {
   612  		JSONResponse(w, models.Response{Success: false, Message: err.Error()}, http.StatusBadRequest)
   613  		return
   614  	}
   615  	// Insert the base href tag to better handle relative resources
   616  	d, err := goquery.NewDocumentFromResponse(resp)
   617  	if err != nil {
   618  		JSONResponse(w, models.Response{Success: false, Message: err.Error()}, http.StatusBadRequest)
   619  		return
   620  	}
   621  	// Assuming we don't want to include resources, we'll need a base href
   622  	if d.Find("head base").Length() == 0 {
   623  		d.Find("head").PrependHtml(fmt.Sprintf("<base href=\"%s\">", cr.URL))
   624  	}
   625  	forms := d.Find("form")
   626  	forms.Each(func(i int, f *goquery.Selection) {
   627  		// We'll want to store where we got the form from
   628  		// (the current URL)
   629  		url := f.AttrOr("action", cr.URL)
   630  		if !strings.HasPrefix(url, "http") {
   631  			url = fmt.Sprintf("%s%s", cr.URL, url)
   632  		}
   633  		f.PrependHtml(fmt.Sprintf("<input type=\"hidden\" name=\"__original_url\" value=\"%s\"/>", url))
   634  	})
   635  	h, err := d.Html()
   636  	if err != nil {
   637  		JSONResponse(w, models.Response{Success: false, Message: err.Error()}, http.StatusInternalServerError)
   638  		return
   639  	}
   640  	cs := cloneResponse{HTML: h}
   641  	JSONResponse(w, cs, http.StatusOK)
   642  	return
   643  }
   644  
   645  // API_Send_Test_Email sends a test email using the template name
   646  // and Target given.
   647  func API_Send_Test_Email(w http.ResponseWriter, r *http.Request) {
   648  	s := &models.SendTestEmailRequest{}
   649  	if r.Method != "POST" {
   650  		JSONResponse(w, models.Response{Success: false, Message: "Method not allowed"}, http.StatusBadRequest)
   651  		return
   652  	}
   653  	err := json.NewDecoder(r.Body).Decode(s)
   654  	if err != nil {
   655  		JSONResponse(w, models.Response{Success: false, Message: "Error decoding JSON Request"}, http.StatusBadRequest)
   656  		return
   657  	}
   658  	// Validate the given request
   659  	if err = s.Validate(); err != nil {
   660  		JSONResponse(w, models.Response{Success: false, Message: err.Error()}, http.StatusBadRequest)
   661  		return
   662  	}
   663  
   664  	// If a Template is not specified use a default
   665  	if s.Template.Name == "" {
   666  		//default message body
   667  		text := "It works!\n\nThis is an email letting you know that your gophish\nconfiguration was successful.\n" +
   668  			"Here are the details:\n\nWho you sent from: {{.From}}\n\nWho you sent to: \n" +
   669  			"{{if .FirstName}} First Name: {{.FirstName}}\n{{end}}" +
   670  			"{{if .LastName}} Last Name: {{.LastName}}\n{{end}}" +
   671  			"{{if .Position}} Position: {{.Position}}\n{{end}}" +
   672  			"{{if .TrackingURL}} Tracking URL: {{.TrackingURL}}\n{{end}}" +
   673  			"\nNow go send some phish!"
   674  		t := models.Template{
   675  			Subject: "Default Email from Gophish",
   676  			Text:    text,
   677  		}
   678  		s.Template = t
   679  		// Try to lookup the Template by name
   680  	} else {
   681  		// Get the Template requested by name
   682  		s.Template, err = models.GetTemplateByName(s.Template.Name, ctx.Get(r, "user_id").(int64))
   683  		if err == gorm.ErrRecordNotFound {
   684  			Logger.Printf("Error - Template %s does not exist", s.Template.Name)
   685  			JSONResponse(w, models.Response{Success: false, Message: models.ErrTemplateNotFound.Error()}, http.StatusBadRequest)
   686  		} else if err != nil {
   687  			Logger.Println(err)
   688  			JSONResponse(w, models.Response{Success: false, Message: err.Error()}, http.StatusBadRequest)
   689  			return
   690  		}
   691  	}
   692  
   693  	// If a complete sending profile is provided use it
   694  	if err := s.SMTP.Validate(); err != nil {
   695  		// Otherwise get the SMTP requested by name
   696  		s.SMTP, err = models.GetSMTPByName(s.SMTP.Name, ctx.Get(r, "user_id").(int64))
   697  		if err == gorm.ErrRecordNotFound {
   698  			Logger.Printf("Error - Sending profile %s does not exist", s.SMTP.Name)
   699  			JSONResponse(w, models.Response{Success: false, Message: models.ErrSMTPNotFound.Error()}, http.StatusBadRequest)
   700  		} else if err != nil {
   701  			Logger.Println(err)
   702  			JSONResponse(w, models.Response{Success: false, Message: err.Error()}, http.StatusBadRequest)
   703  			return
   704  		}
   705  	}
   706  
   707  	// Send the test email
   708  	err = worker.SendTestEmail(s)
   709  	if err != nil {
   710  		JSONResponse(w, models.Response{Success: false, Message: err.Error()}, http.StatusInternalServerError)
   711  		return
   712  	}
   713  	JSONResponse(w, models.Response{Success: true, Message: "Email Sent"}, http.StatusOK)
   714  	return
   715  }
   716  
   717  // JSONResponse attempts to set the status code, c, and marshal the given interface, d, into a response that
   718  // is written to the given ResponseWriter.
   719  func JSONResponse(w http.ResponseWriter, d interface{}, c int) {
   720  	dj, err := json.MarshalIndent(d, "", "  ")
   721  	if err != nil {
   722  		http.Error(w, "Error creating JSON response", http.StatusInternalServerError)
   723  		Logger.Println(err)
   724  	}
   725  	w.Header().Set("Content-Type", "application/json")
   726  	w.WriteHeader(c)
   727  	fmt.Fprintf(w, "%s", dj)
   728  }
   729  
   730  type cloneRequest struct {
   731  	URL              string `json:"url"`
   732  	IncludeResources bool   `json:"include_resources"`
   733  }
   734  
   735  func (cr *cloneRequest) validate() error {
   736  	if cr.URL == "" {
   737  		return errors.New("No URL Specified")
   738  	}
   739  	return nil
   740  }
   741  
   742  type cloneResponse struct {
   743  	HTML string `json:"html"`
   744  }
   745  
   746  type emailResponse struct {
   747  	Text    string `json:"text"`
   748  	HTML    string `json:"html"`
   749  	Subject string `json:"subject"`
   750  }