Localization base features development (Golang & JS), further need is definieng the localization string both in golang translation file and html pages.

pull/539/head
Alen BOHCELYAN 2017-02-13 12:07:08 +00:00 committed by Alen BOHCELYAN
parent dbadac3eca
commit 563368d64c
24 changed files with 395 additions and 359 deletions

View File

@ -1,7 +1,7 @@
{
"admin_server" : {
"listen_url" : "127.0.0.1:3333",
"use_tls" : true,
"listen_url" : "0.0.0.0:3333",
"use_tls" : false,
"cert_path" : "gophish_admin.crt",
"key_path" : "gophish_admin.key"
},

View File

@ -16,11 +16,11 @@ import (
"github.com/gophish/gophish/auth"
ctx "github.com/gophish/gophish/context"
"github.com/gophish/gophish/models"
"github.com/gophish/gophish/util"
"github.com/gophish/gophish/worker"
"github.com/gorilla/mux"
"github.com/jinzhu/gorm"
"github.com/jordan-wright/email"
"../util"
)
// Worker is the worker that processes phishing events and updates campaigns.
@ -52,9 +52,9 @@ func API_Reset(w http.ResponseWriter, r *http.Request) {
u.ApiKey = auth.GenerateSecureKey()
err := models.PutUser(&u)
if err != nil {
http.Error(w, "Error setting API Key", http.StatusInternalServerError)
http.Error(w, util.T("Error setting API Key"), http.StatusInternalServerError)
} else {
JSONResponse(w, models.Response{Success: true, Message: "API Key successfully reset!", Data: u.ApiKey}, http.StatusOK)
JSONResponse(w, models.Response{Success: true, Message: util.T("API Key successfully reset!"), Data: u.ApiKey}, http.StatusOK)
}
}
}
@ -109,7 +109,7 @@ func API_Campaigns_Id(w http.ResponseWriter, r *http.Request) {
c, err := models.GetCampaign(id, ctx.Get(r, "user_id").(int64))
if err != nil {
Logger.Println(err)
JSONResponse(w, models.Response{Success: false, Message: "Campaign not found"}, http.StatusNotFound)
JSONResponse(w, models.Response{Success: false, Message: util.T("Campaign not found")}, http.StatusNotFound)
return
}
switch {
@ -118,10 +118,10 @@ func API_Campaigns_Id(w http.ResponseWriter, r *http.Request) {
case r.Method == "DELETE":
err = models.DeleteCampaign(id)
if err != nil {
JSONResponse(w, models.Response{Success: false, Message: "Error deleting campaign"}, http.StatusInternalServerError)
JSONResponse(w, models.Response{Success: false, Message: util.T("Error deleting campaign")}, http.StatusInternalServerError)
return
}
JSONResponse(w, models.Response{Success: true, Message: "Campaign deleted successfully!"}, http.StatusOK)
JSONResponse(w, models.Response{Success: true, Message: util.T("Campaign deleted successfully!")}, http.StatusOK)
}
}
@ -133,7 +133,7 @@ func API_Campaigns_Id_Results(w http.ResponseWriter, r *http.Request) {
cr, err := models.GetCampaignResults(id, ctx.Get(r, "user_id").(int64))
if err != nil {
Logger.Println(err)
JSONResponse(w, models.Response{Success: false, Message: "Campaign not found"}, http.StatusNotFound)
JSONResponse(w, models.Response{Success: false, Message: util.T("Campaign not found")}, http.StatusNotFound)
return
}
if r.Method == "GET" {
@ -151,9 +151,9 @@ func API_Campaign_Id_Summary(w http.ResponseWriter, r *http.Request) {
cs, err := models.GetCampaignSummary(id, ctx.Get(r, "user_id").(int64))
if err != nil {
if err == gorm.ErrRecordNotFound {
JSONResponse(w, models.Response{Success: false, Message: "Campaign not found"}, http.StatusNotFound)
JSONResponse(w, models.Response{Success: false, Message: util.T("Campaign not found")}, http.StatusNotFound)
} else {
JSONResponse(w, models.Response{Success: false, Message: err.Error()}, http.StatusInternalServerError)
JSONResponse(w, models.Response{Success: false, Message: util.T(err.Error())}, http.StatusInternalServerError)
}
Logger.Println(err)
return
@ -171,10 +171,10 @@ func API_Campaigns_Id_Complete(w http.ResponseWriter, r *http.Request) {
case r.Method == "GET":
err := models.CompleteCampaign(id, ctx.Get(r, "user_id").(int64))
if err != nil {
JSONResponse(w, models.Response{Success: false, Message: "Error completing campaign"}, http.StatusInternalServerError)
JSONResponse(w, models.Response{Success: false, Message: util.T("Error completing campaign")}, http.StatusInternalServerError)
return
}
JSONResponse(w, models.Response{Success: true, Message: "Campaign completed successfully!"}, http.StatusOK)
JSONResponse(w, models.Response{Success: true, Message: util.T("Campaign completed successfully!")}, http.StatusOK)
}
}
@ -185,7 +185,7 @@ func API_Groups(w http.ResponseWriter, r *http.Request) {
case r.Method == "GET":
gs, err := models.GetGroups(ctx.Get(r, "user_id").(int64))
if err != nil {
JSONResponse(w, models.Response{Success: false, Message: "No groups found"}, http.StatusNotFound)
JSONResponse(w, models.Response{Success: false, Message: util.T("No groups found")}, http.StatusNotFound)
return
}
JSONResponse(w, gs, http.StatusOK)
@ -195,12 +195,12 @@ func API_Groups(w http.ResponseWriter, r *http.Request) {
// Put the request into a group
err := json.NewDecoder(r.Body).Decode(&g)
if err != nil {
JSONResponse(w, models.Response{Success: false, Message: "Invalid JSON structure"}, http.StatusBadRequest)
JSONResponse(w, models.Response{Success: false, Message: util.T("Invalid JSON structure")}, http.StatusBadRequest)
return
}
_, err = models.GetGroupByName(g.Name, ctx.Get(r, "user_id").(int64))
if err != gorm.ErrRecordNotFound {
JSONResponse(w, models.Response{Success: false, Message: "Group name already in use"}, http.StatusConflict)
JSONResponse(w, models.Response{Success: false, Message: util.T("Group name already in use")}, http.StatusConflict)
return
}
g.ModifiedDate = time.Now()
@ -235,7 +235,7 @@ func API_Groups_Id(w http.ResponseWriter, r *http.Request) {
id, _ := strconv.ParseInt(vars["id"], 0, 64)
g, err := models.GetGroup(id, ctx.Get(r, "user_id").(int64))
if err != nil {
JSONResponse(w, models.Response{Success: false, Message: "Group not found"}, http.StatusNotFound)
JSONResponse(w, models.Response{Success: false, Message: util.T("Group not found")}, http.StatusNotFound)
return
}
switch {
@ -244,23 +244,23 @@ func API_Groups_Id(w http.ResponseWriter, r *http.Request) {
case r.Method == "DELETE":
err = models.DeleteGroup(&g)
if err != nil {
JSONResponse(w, models.Response{Success: false, Message: "Error deleting group"}, http.StatusInternalServerError)
JSONResponse(w, models.Response{Success: false, Message: util.T("Error deleting group")}, http.StatusInternalServerError)
return
}
JSONResponse(w, models.Response{Success: true, Message: "Group deleted successfully!"}, http.StatusOK)
JSONResponse(w, models.Response{Success: true, Message: util.T("Group deleted successfully!")}, http.StatusOK)
case r.Method == "PUT":
// Change this to get from URL and uid (don't bother with id in r.Body)
g = models.Group{}
err = json.NewDecoder(r.Body).Decode(&g)
if g.Id != id {
JSONResponse(w, models.Response{Success: false, Message: "Error: /:id and group_id mismatch"}, http.StatusInternalServerError)
JSONResponse(w, models.Response{Success: false, Message: util.T("Error: /:id and group_id mismatch")}, http.StatusInternalServerError)
return
}
g.ModifiedDate = time.Now()
g.UserId = ctx.Get(r, "user_id").(int64)
err = models.PutGroup(&g)
if err != nil {
JSONResponse(w, models.Response{Success: false, Message: err.Error()}, http.StatusBadRequest)
JSONResponse(w, models.Response{Success: false, Message: util.T(err.Error())}, http.StatusBadRequest)
return
}
JSONResponse(w, g, http.StatusOK)
@ -275,7 +275,7 @@ func API_Groups_Id_Summary(w http.ResponseWriter, r *http.Request) {
id, _ := strconv.ParseInt(vars["id"], 0, 64)
g, err := models.GetGroupSummary(id, ctx.Get(r, "user_id").(int64))
if err != nil {
JSONResponse(w, models.Response{Success: false, Message: "Group not found"}, http.StatusNotFound)
JSONResponse(w, models.Response{Success: false, Message: util.T("Group not found")}, http.StatusNotFound)
return
}
JSONResponse(w, g, http.StatusOK)
@ -297,27 +297,27 @@ func API_Templates(w http.ResponseWriter, r *http.Request) {
// Put the request into a template
err := json.NewDecoder(r.Body).Decode(&t)
if err != nil {
JSONResponse(w, models.Response{Success: false, Message: "Invalid JSON structure"}, http.StatusBadRequest)
JSONResponse(w, models.Response{Success: false, Message: util.T("Invalid JSON structure")}, http.StatusBadRequest)
return
}
_, err = models.GetTemplateByName(t.Name, ctx.Get(r, "user_id").(int64))
if err != gorm.ErrRecordNotFound {
JSONResponse(w, models.Response{Success: false, Message: "Template name already in use"}, http.StatusConflict)
JSONResponse(w, models.Response{Success: false, Message: util.T("Template name already in use")}, http.StatusConflict)
return
}
t.ModifiedDate = time.Now()
t.UserId = ctx.Get(r, "user_id").(int64)
err = models.PostTemplate(&t)
if err == models.ErrTemplateNameNotSpecified {
JSONResponse(w, models.Response{Success: false, Message: err.Error()}, http.StatusBadRequest)
JSONResponse(w, models.Response{Success: false, Message: util.T(err.Error())}, http.StatusBadRequest)
return
}
if err == models.ErrTemplateMissingParameter {
JSONResponse(w, models.Response{Success: false, Message: err.Error()}, http.StatusBadRequest)
JSONResponse(w, models.Response{Success: false, Message: util.T(err.Error())}, http.StatusBadRequest)
return
}
if err != nil {
JSONResponse(w, models.Response{Success: false, Message: "Error inserting template into database"}, http.StatusInternalServerError)
JSONResponse(w, models.Response{Success: false, Message: util.T("Error inserting template into database")}, http.StatusInternalServerError)
Logger.Println(err)
return
}
@ -331,7 +331,7 @@ func API_Templates_Id(w http.ResponseWriter, r *http.Request) {
id, _ := strconv.ParseInt(vars["id"], 0, 64)
t, err := models.GetTemplate(id, ctx.Get(r, "user_id").(int64))
if err != nil {
JSONResponse(w, models.Response{Success: false, Message: "Template not found"}, http.StatusNotFound)
JSONResponse(w, models.Response{Success: false, Message: util.T("Template not found")}, http.StatusNotFound)
return
}
switch {
@ -340,10 +340,10 @@ func API_Templates_Id(w http.ResponseWriter, r *http.Request) {
case r.Method == "DELETE":
err = models.DeleteTemplate(id, ctx.Get(r, "user_id").(int64))
if err != nil {
JSONResponse(w, models.Response{Success: false, Message: "Error deleting template"}, http.StatusInternalServerError)
JSONResponse(w, models.Response{Success: false, Message: util.T("Error deleting template")}, http.StatusInternalServerError)
return
}
JSONResponse(w, models.Response{Success: true, Message: "Template deleted successfully!"}, http.StatusOK)
JSONResponse(w, models.Response{Success: true, Message: util.T("Template deleted successfully!")}, http.StatusOK)
case r.Method == "PUT":
t = models.Template{}
err = json.NewDecoder(r.Body).Decode(&t)
@ -351,14 +351,14 @@ func API_Templates_Id(w http.ResponseWriter, r *http.Request) {
Logger.Println(err)
}
if t.Id != id {
JSONResponse(w, models.Response{Success: false, Message: "Error: /:id and template_id mismatch"}, http.StatusBadRequest)
JSONResponse(w, models.Response{Success: false, Message: util.T("Error: /:id and template_id mismatch")}, http.StatusBadRequest)
return
}
t.ModifiedDate = time.Now()
t.UserId = ctx.Get(r, "user_id").(int64)
err = models.PutTemplate(&t)
if err != nil {
JSONResponse(w, models.Response{Success: false, Message: err.Error()}, http.StatusBadRequest)
JSONResponse(w, models.Response{Success: false, Message: util.T(err.Error())}, http.StatusBadRequest)
return
}
JSONResponse(w, t, http.StatusOK)
@ -380,13 +380,13 @@ func API_Pages(w http.ResponseWriter, r *http.Request) {
// Put the request into a page
err := json.NewDecoder(r.Body).Decode(&p)
if err != nil {
JSONResponse(w, models.Response{Success: false, Message: "Invalid request"}, http.StatusBadRequest)
JSONResponse(w, models.Response{Success: false, Message: util.T("Invalid request")}, http.StatusBadRequest)
return
}
// Check to make sure the name is unique
_, err = models.GetPageByName(p.Name, ctx.Get(r, "user_id").(int64))
if err != gorm.ErrRecordNotFound {
JSONResponse(w, models.Response{Success: false, Message: "Page name already in use"}, http.StatusConflict)
JSONResponse(w, models.Response{Success: false, Message: util.T("Page name already in use")}, http.StatusConflict)
Logger.Println(err)
return
}
@ -394,7 +394,7 @@ func API_Pages(w http.ResponseWriter, r *http.Request) {
p.UserId = ctx.Get(r, "user_id").(int64)
err = models.PostPage(&p)
if err != nil {
JSONResponse(w, models.Response{Success: false, Message: err.Error()}, http.StatusInternalServerError)
JSONResponse(w, models.Response{Success: false, Message: util.T(err.Error())}, http.StatusInternalServerError)
return
}
JSONResponse(w, p, http.StatusCreated)
@ -408,7 +408,7 @@ func API_Pages_Id(w http.ResponseWriter, r *http.Request) {
id, _ := strconv.ParseInt(vars["id"], 0, 64)
p, err := models.GetPage(id, ctx.Get(r, "user_id").(int64))
if err != nil {
JSONResponse(w, models.Response{Success: false, Message: "Page not found"}, http.StatusNotFound)
JSONResponse(w, models.Response{Success: false, Message: util.T("Page not found")}, http.StatusNotFound)
return
}
switch {
@ -417,10 +417,10 @@ func API_Pages_Id(w http.ResponseWriter, r *http.Request) {
case r.Method == "DELETE":
err = models.DeletePage(id, ctx.Get(r, "user_id").(int64))
if err != nil {
JSONResponse(w, models.Response{Success: false, Message: "Error deleting page"}, http.StatusInternalServerError)
JSONResponse(w, models.Response{Success: false, Message: util.T("Error deleting page")}, http.StatusInternalServerError)
return
}
JSONResponse(w, models.Response{Success: true, Message: "Page Deleted Successfully"}, http.StatusOK)
JSONResponse(w, models.Response{Success: true, Message: util.T("Page Deleted Successfully")}, http.StatusOK)
case r.Method == "PUT":
p = models.Page{}
err = json.NewDecoder(r.Body).Decode(&p)
@ -428,14 +428,14 @@ func API_Pages_Id(w http.ResponseWriter, r *http.Request) {
Logger.Println(err)
}
if p.Id != id {
JSONResponse(w, models.Response{Success: false, Message: "/:id and /:page_id mismatch"}, http.StatusBadRequest)
JSONResponse(w, models.Response{Success: false, Message: util.T("/:id and /:page_id mismatch")}, http.StatusBadRequest)
return
}
p.ModifiedDate = time.Now()
p.UserId = ctx.Get(r, "user_id").(int64)
err = models.PutPage(&p)
if err != nil {
JSONResponse(w, models.Response{Success: false, Message: "Error updating page: " + err.Error()}, http.StatusInternalServerError)
JSONResponse(w, models.Response{Success: false, Message: util.T("Error updating page: " + err.Error())}, http.StatusInternalServerError)
return
}
JSONResponse(w, p, http.StatusOK)
@ -457,13 +457,13 @@ func API_SMTP(w http.ResponseWriter, r *http.Request) {
// Put the request into a page
err := json.NewDecoder(r.Body).Decode(&s)
if err != nil {
JSONResponse(w, models.Response{Success: false, Message: "Invalid request"}, http.StatusBadRequest)
JSONResponse(w, models.Response{Success: false, Message: util.T("Invalid request")}, http.StatusBadRequest)
return
}
// Check to make sure the name is unique
_, err = models.GetSMTPByName(s.Name, ctx.Get(r, "user_id").(int64))
if err != gorm.ErrRecordNotFound {
JSONResponse(w, models.Response{Success: false, Message: "SMTP name already in use"}, http.StatusConflict)
JSONResponse(w, models.Response{Success: false, Message: util.T("SMTP name already in use")}, http.StatusConflict)
Logger.Println(err)
return
}
@ -471,7 +471,7 @@ func API_SMTP(w http.ResponseWriter, r *http.Request) {
s.UserId = ctx.Get(r, "user_id").(int64)
err = models.PostSMTP(&s)
if err != nil {
JSONResponse(w, models.Response{Success: false, Message: err.Error()}, http.StatusInternalServerError)
JSONResponse(w, models.Response{Success: false, Message: util.T(err.Error())}, http.StatusInternalServerError)
return
}
JSONResponse(w, s, http.StatusCreated)
@ -485,7 +485,7 @@ func API_SMTP_Id(w http.ResponseWriter, r *http.Request) {
id, _ := strconv.ParseInt(vars["id"], 0, 64)
s, err := models.GetSMTP(id, ctx.Get(r, "user_id").(int64))
if err != nil {
JSONResponse(w, models.Response{Success: false, Message: "SMTP not found"}, http.StatusNotFound)
JSONResponse(w, models.Response{Success: false, Message: util.T("SMTP not found")}, http.StatusNotFound)
return
}
switch {
@ -494,10 +494,10 @@ func API_SMTP_Id(w http.ResponseWriter, r *http.Request) {
case r.Method == "DELETE":
err = models.DeleteSMTP(id, ctx.Get(r, "user_id").(int64))
if err != nil {
JSONResponse(w, models.Response{Success: false, Message: "Error deleting SMTP"}, http.StatusInternalServerError)
JSONResponse(w, models.Response{Success: false, Message: util.T("Error deleting SMTP")}, http.StatusInternalServerError)
return
}
JSONResponse(w, models.Response{Success: true, Message: "SMTP Deleted Successfully"}, http.StatusOK)
JSONResponse(w, models.Response{Success: true, Message: util.T("SMTP Deleted Successfully")}, http.StatusOK)
case r.Method == "PUT":
s = models.SMTP{}
err = json.NewDecoder(r.Body).Decode(&s)
@ -505,19 +505,19 @@ func API_SMTP_Id(w http.ResponseWriter, r *http.Request) {
Logger.Println(err)
}
if s.Id != id {
JSONResponse(w, models.Response{Success: false, Message: "/:id and /:smtp_id mismatch"}, http.StatusBadRequest)
JSONResponse(w, models.Response{Success: false, Message: util.T("/:id and /:smtp_id mismatch")}, http.StatusBadRequest)
return
}
err = s.Validate()
if err != nil {
JSONResponse(w, models.Response{Success: false, Message: err.Error()}, http.StatusBadRequest)
JSONResponse(w, models.Response{Success: false, Message: util.T(err.Error())}, http.StatusBadRequest)
return
}
s.ModifiedDate = time.Now()
s.UserId = ctx.Get(r, "user_id").(int64)
err = models.PutSMTP(&s)
if err != nil {
JSONResponse(w, models.Response{Success: false, Message: "Error updating page"}, http.StatusInternalServerError)
JSONResponse(w, models.Response{Success: false, Message: util.T("Error updating page")}, http.StatusInternalServerError)
return
}
JSONResponse(w, s, http.StatusOK)
@ -528,7 +528,7 @@ func API_SMTP_Id(w http.ResponseWriter, r *http.Request) {
func API_Import_Group(w http.ResponseWriter, r *http.Request) {
ts, err := util.ParseCSV(r)
if err != nil {
JSONResponse(w, models.Response{Success: false, Message: "Error parsing CSV"}, http.StatusInternalServerError)
JSONResponse(w, models.Response{Success: false, Message: util.T("Error parsing CSV")}, http.StatusInternalServerError)
return
}
JSONResponse(w, ts, http.StatusOK)
@ -539,7 +539,7 @@ func API_Import_Group(w http.ResponseWriter, r *http.Request) {
// Returns a Message object
func API_Import_Email(w http.ResponseWriter, r *http.Request) {
if r.Method != "POST" {
JSONResponse(w, models.Response{Success: false, Message: "Method not allowed"}, http.StatusBadRequest)
JSONResponse(w, models.Response{Success: false, Message: util.T("Method not allowed")}, http.StatusBadRequest)
return
}
ir := struct {
@ -548,7 +548,7 @@ func API_Import_Email(w http.ResponseWriter, r *http.Request) {
}{}
err := json.NewDecoder(r.Body).Decode(&ir)
if err != nil {
JSONResponse(w, models.Response{Success: false, Message: "Error decoding JSON Request"}, http.StatusBadRequest)
JSONResponse(w, models.Response{Success: false, Message: util.T("Error decoding JSON Request")}, http.StatusBadRequest)
return
}
e, err := email.NewEmailFromReader(strings.NewReader(ir.Content))
@ -561,7 +561,7 @@ func API_Import_Email(w http.ResponseWriter, r *http.Request) {
if ir.ConvertLinks {
d, err := goquery.NewDocumentFromReader(bytes.NewReader(e.HTML))
if err != nil {
JSONResponse(w, models.Response{Success: false, Message: err.Error()}, http.StatusBadRequest)
JSONResponse(w, models.Response{Success: false, Message: util.T(err.Error())}, http.StatusBadRequest)
return
}
d.Find("a").Each(func(i int, a *goquery.Selection) {
@ -569,7 +569,7 @@ func API_Import_Email(w http.ResponseWriter, r *http.Request) {
})
h, err := d.Html()
if err != nil {
JSONResponse(w, models.Response{Success: false, Message: err.Error()}, http.StatusInternalServerError)
JSONResponse(w, models.Response{Success: false, Message: util.T(err.Error())}, http.StatusInternalServerError)
return
}
e.HTML = []byte(h)
@ -589,16 +589,16 @@ func API_Import_Email(w http.ResponseWriter, r *http.Request) {
func API_Import_Site(w http.ResponseWriter, r *http.Request) {
cr := cloneRequest{}
if r.Method != "POST" {
JSONResponse(w, models.Response{Success: false, Message: "Method not allowed"}, http.StatusBadRequest)
JSONResponse(w, models.Response{Success: false, Message: util.T("Method not allowed")}, http.StatusBadRequest)
return
}
err := json.NewDecoder(r.Body).Decode(&cr)
if err != nil {
JSONResponse(w, models.Response{Success: false, Message: "Error decoding JSON Request"}, http.StatusBadRequest)
JSONResponse(w, models.Response{Success: false, Message: util.T("Error decoding JSON Request")}, http.StatusBadRequest)
return
}
if err = cr.validate(); err != nil {
JSONResponse(w, models.Response{Success: false, Message: err.Error()}, http.StatusBadRequest)
JSONResponse(w, models.Response{Success: false, Message: util.T(err.Error())}, http.StatusBadRequest)
return
}
tr := &http.Transport{
@ -609,13 +609,13 @@ func API_Import_Site(w http.ResponseWriter, r *http.Request) {
client := &http.Client{Transport: tr}
resp, err := client.Get(cr.URL)
if err != nil {
JSONResponse(w, models.Response{Success: false, Message: err.Error()}, http.StatusBadRequest)
JSONResponse(w, models.Response{Success: false, Message: util.T(err.Error())}, http.StatusBadRequest)
return
}
// Insert the base href tag to better handle relative resources
d, err := goquery.NewDocumentFromResponse(resp)
if err != nil {
JSONResponse(w, models.Response{Success: false, Message: err.Error()}, http.StatusBadRequest)
JSONResponse(w, models.Response{Success: false, Message: util.T(err.Error())}, http.StatusBadRequest)
return
}
// Assuming we don't want to include resources, we'll need a base href
@ -634,7 +634,7 @@ func API_Import_Site(w http.ResponseWriter, r *http.Request) {
})
h, err := d.Html()
if err != nil {
JSONResponse(w, models.Response{Success: false, Message: err.Error()}, http.StatusInternalServerError)
JSONResponse(w, models.Response{Success: false, Message: util.T(err.Error())}, http.StatusInternalServerError)
return
}
cs := cloneResponse{HTML: h}
@ -647,17 +647,17 @@ func API_Import_Site(w http.ResponseWriter, r *http.Request) {
func API_Send_Test_Email(w http.ResponseWriter, r *http.Request) {
s := &models.SendTestEmailRequest{}
if r.Method != "POST" {
JSONResponse(w, models.Response{Success: false, Message: "Method not allowed"}, http.StatusBadRequest)
JSONResponse(w, models.Response{Success: false, Message: util.T("Method not allowed")}, http.StatusBadRequest)
return
}
err := json.NewDecoder(r.Body).Decode(s)
if err != nil {
JSONResponse(w, models.Response{Success: false, Message: "Error decoding JSON Request"}, http.StatusBadRequest)
JSONResponse(w, models.Response{Success: false, Message: util.T("Error decoding JSON Request")}, http.StatusBadRequest)
return
}
// Validate the given request
if err = s.Validate(); err != nil {
JSONResponse(w, models.Response{Success: false, Message: err.Error()}, http.StatusBadRequest)
JSONResponse(w, models.Response{Success: false, Message: util.T(err.Error())}, http.StatusBadRequest)
return
}
@ -682,10 +682,10 @@ func API_Send_Test_Email(w http.ResponseWriter, r *http.Request) {
s.Template, err = models.GetTemplateByName(s.Template.Name, ctx.Get(r, "user_id").(int64))
if err == gorm.ErrRecordNotFound {
Logger.Printf("Error - Template %s does not exist", s.Template.Name)
JSONResponse(w, models.Response{Success: false, Message: models.ErrTemplateNotFound.Error()}, http.StatusBadRequest)
JSONResponse(w, models.Response{Success: false, Message: util.T(models.ErrTemplateNotFound.Error())}, http.StatusBadRequest)
} else if err != nil {
Logger.Println(err)
JSONResponse(w, models.Response{Success: false, Message: err.Error()}, http.StatusBadRequest)
JSONResponse(w, models.Response{Success: false, Message: util.T(err.Error())}, http.StatusBadRequest)
return
}
}
@ -696,10 +696,10 @@ func API_Send_Test_Email(w http.ResponseWriter, r *http.Request) {
s.SMTP, err = models.GetSMTPByName(s.SMTP.Name, ctx.Get(r, "user_id").(int64))
if err == gorm.ErrRecordNotFound {
Logger.Printf("Error - Sending profile %s does not exist", s.SMTP.Name)
JSONResponse(w, models.Response{Success: false, Message: models.ErrSMTPNotFound.Error()}, http.StatusBadRequest)
JSONResponse(w, models.Response{Success: false, Message: util.T(models.ErrSMTPNotFound.Error())}, http.StatusBadRequest)
} else if err != nil {
Logger.Println(err)
JSONResponse(w, models.Response{Success: false, Message: err.Error()}, http.StatusBadRequest)
JSONResponse(w, models.Response{Success: false, Message: util.T(err.Error())}, http.StatusBadRequest)
return
}
}
@ -707,10 +707,10 @@ func API_Send_Test_Email(w http.ResponseWriter, r *http.Request) {
// Send the test email
err = worker.SendTestEmail(s)
if err != nil {
JSONResponse(w, models.Response{Success: false, Message: err.Error()}, http.StatusInternalServerError)
JSONResponse(w, models.Response{Success: false, Message: util.T(err.Error())}, http.StatusInternalServerError)
return
}
JSONResponse(w, models.Response{Success: true, Message: "Email Sent"}, http.StatusOK)
JSONResponse(w, models.Response{Success: true, Message: util.T("Email Sent")}, http.StatusOK)
return
}

View File

@ -21,6 +21,7 @@ import (
"github.com/gorilla/csrf"
"github.com/gorilla/mux"
"github.com/gorilla/sessions"
"../util"
)
// Logger is used to send logging messages to stdout.
@ -241,7 +242,9 @@ func PhishHandler(w http.ResponseWriter, r *http.Request) {
}
}
var htmlBuff bytes.Buffer
tmpl, err := template.New("html_template").Parse(p.HTML)
tmpl, err := template.New("html_template").Funcs(template.FuncMap{
"T": util.T,
}).Parse(p.HTML)
if err != nil {
Logger.Println(err)
http.NotFound(w, r)
@ -295,7 +298,9 @@ func Register(w http.ResponseWriter, r *http.Request) {
case r.Method == "GET":
params.Flashes = session.Flashes()
session.Save(r, w)
templates := template.New("template")
templates := template.New("template").Funcs(template.FuncMap{
"T": util.T,
})
_, err := templates.ParseFiles("templates/register.html", "templates/flashes.html")
if err != nil {
Logger.Println(err)
@ -455,7 +460,9 @@ func Login(w http.ResponseWriter, r *http.Request) {
case r.Method == "GET":
params.Flashes = session.Flashes()
session.Save(r, w)
templates := template.New("template")
templates := template.New("template").Funcs(template.FuncMap{
"T": util.T,
})
_, err := templates.ParseFiles("templates/login.html", "templates/flashes.html")
if err != nil {
Logger.Println(err)
@ -512,7 +519,9 @@ func Clone(w http.ResponseWriter, r *http.Request) {
}
func getTemplate(w http.ResponseWriter, tmpl string) *template.Template {
templates := template.New("template")
templates := template.New("template").Funcs(template.FuncMap{
"T": util.T,
})
_, err := templates.ParseFiles("templates/base.html", "templates/"+tmpl+".html", "templates/flashes.html")
if err != nil {
Logger.Println(err)

View File

@ -36,16 +36,18 @@ import (
"github.com/NYTimes/gziphandler"
"github.com/gophish/gophish/auth"
"github.com/gophish/gophish/config"
"github.com/gophish/gophish/controllers"
"./controllers"
"github.com/gophish/gophish/models"
"github.com/gophish/gophish/util"
"./util"
"github.com/gorilla/handlers"
"github.com/nicksnyder/go-i18n/i18n"
)
var Logger = log.New(os.Stdout, " ", log.Ldate|log.Ltime|log.Lshortfile)
func main() {
// Setup the global variables and settings
i18n.MustLoadTranslationFile("translations/en-US.all.json")
err := models.Setup()
if err != nil {
fmt.Println(err)

View File

@ -5,6 +5,7 @@ import (
"time"
"github.com/jinzhu/gorm"
"../util"
)
// Campaign is a struct representing a created campaign
@ -65,31 +66,31 @@ type CampaignStats struct {
}
// ErrCampaignNameNotSpecified indicates there was no template given by the user
var ErrCampaignNameNotSpecified = errors.New("Campaign name not specified")
var ErrCampaignNameNotSpecified = errors.New(util.T("Campaign name not specified"))
// ErrGroupNotSpecified indicates there was no template given by the user
var ErrGroupNotSpecified = errors.New("No groups specified")
var ErrGroupNotSpecified = errors.New(util.T("No groups specified"))
// ErrTemplateNotSpecified indicates there was no template given by the user
var ErrTemplateNotSpecified = errors.New("No email template specified")
var ErrTemplateNotSpecified = errors.New(util.T("No email template specified"))
// ErrPageNotSpecified indicates a landing page was not provided for the campaign
var ErrPageNotSpecified = errors.New("No landing page specified")
var ErrPageNotSpecified = errors.New(util.T("No landing page specified"))
// ErrSMTPNotSpecified indicates a sending profile was not provided for the campaign
var ErrSMTPNotSpecified = errors.New("No sending profile specified")
var ErrSMTPNotSpecified = errors.New(util.T("No sending profile specified"))
// ErrTemplateNotFound indicates the template specified does not exist in the database
var ErrTemplateNotFound = errors.New("Template not found")
var ErrTemplateNotFound = errors.New(util.T("Template not found"))
// ErrGroupnNotFound indicates a group specified by the user does not exist in the database
var ErrGroupNotFound = errors.New("Group not found")
var ErrGroupNotFound = errors.New(util.T("Group not found"))
// ErrPageNotFound indicates a page specified by the user does not exist in the database
var ErrPageNotFound = errors.New("Page not found")
var ErrPageNotFound = errors.New(util.T("Page not found"))
// ErrSMTPNotFound indicates a sending profile specified by the user does not exist in the database
var ErrSMTPNotFound = errors.New("Sending profile not found")
var ErrSMTPNotFound = errors.New(util.T("Sending profile not found"))
// Validate checks to make sure there are no invalid fields in a submitted campaign
func (c *Campaign) Validate() error {

View File

@ -6,6 +6,7 @@ import (
"time"
"github.com/jinzhu/gorm"
"../util"
)
// Group contains the fields needed for a user -> group mapping
@ -51,13 +52,13 @@ type Target struct {
}
// ErrNoEmailSpecified is thrown when no email is specified for the Target
var ErrEmailNotSpecified = errors.New("No email address specified")
var ErrEmailNotSpecified = errors.New(util.T("No email address specified"))
// ErrGroupNameNotSpecified is thrown when a group name is not specified
var ErrGroupNameNotSpecified = errors.New("Group name not specified")
var ErrGroupNameNotSpecified = errors.New(util.T("Group name not specified"))
// ErrNoTargetsSpecified is thrown when no targets are specified by the user
var ErrNoTargetsSpecified = errors.New("No targets specified")
var ErrNoTargetsSpecified = errors.New(util.T("No targets specified"))
// Validate performs validation on a group given by the user
func (g *Group) Validate() error {

View File

@ -14,13 +14,14 @@ import (
"github.com/gophish/gophish/config"
"github.com/jinzhu/gorm"
_ "github.com/mattn/go-sqlite3" // Blank import needed to import sqlite3
"../util"
)
var db *gorm.DB
var err error
// ErrUsernameTaken is thrown when a user attempts to register a username that is taken.
var ErrUsernameTaken = errors.New("username already taken")
var ErrUsernameTaken = errors.New(util.T("username already taken"))
// Logger is a global logger used to show informational, warning, and error messages
var Logger = log.New(os.Stdout, " ", log.Ldate|log.Ltime|log.Lshortfile)

View File

@ -6,6 +6,7 @@ import (
"time"
"github.com/PuerkitoBio/goquery"
"../util"
)
// Page contains the fields used for a Page model
@ -21,7 +22,7 @@ type Page struct {
}
// ErrPageNameNotSpecified is thrown if the name of the landing page is blank.
var ErrPageNameNotSpecified = errors.New("Page Name not specified")
var ErrPageNameNotSpecified = errors.New(util.T("Page Name not specified"))
// parseHTML parses the page HTML on save to handle the
// capturing (or lack thereof!) of credentials and passwords

View File

@ -8,6 +8,7 @@ import (
"github.com/jinzhu/gorm"
"github.com/oschwald/maxminddb-golang"
"../util"
)
type mmCity struct {

View File

@ -6,6 +6,7 @@ import (
"strconv"
"strings"
"time"
"../util"
)
// SMTP contains the attributes needed to handle the sending of campaign emails
@ -24,14 +25,14 @@ type SMTP struct {
// ErrFromAddressNotSpecified is thrown when there is no "From" address
// specified in the SMTP configuration
var ErrFromAddressNotSpecified = errors.New("No From Address specified")
var ErrFromAddressNotSpecified = errors.New(util.T("No From Address specified"))
// ErrHostNotSpecified is thrown when there is no Host specified
// in the SMTP configuration
var ErrHostNotSpecified = errors.New("No SMTP Host specified")
var ErrHostNotSpecified = errors.New(util.T("No SMTP Host specified"))
// ErrInvalidHost indicates that the SMTP server string is invalid
var ErrInvalidHost = errors.New("Invalid SMTP server address")
var ErrInvalidHost = errors.New(util.T("Invalid SMTP server address"))
// TableName specifies the database tablename for Gorm to use
func (s SMTP) TableName() string {

View File

@ -7,6 +7,7 @@ import (
"time"
"github.com/jinzhu/gorm"
"../util"
)
// Template models hold the attributes for an email template to be sent to targets
@ -22,10 +23,10 @@ type Template struct {
}
// ErrTemplateNameNotSpecified is thrown when a template name is not specified
var ErrTemplateNameNotSpecified = errors.New("Template name not specified")
var ErrTemplateNameNotSpecified = errors.New(util.T("Template name not specified"))
// ErrTemplateMissingParameter is thrown when a needed parameter is not provided
var ErrTemplateMissingParameter = errors.New("Need to specify at least plaintext or HTML content")
var ErrTemplateMissingParameter = errors.New(util.T("Need to specify at least plaintext or HTML content"))
// Validate checks the given template to make sure values are appropriate and complete
func (t *Template) Validate() error {

View File

@ -10,7 +10,7 @@ var labels = {
}
function deleteCampaign(idx) {
if (confirm("Delete " + campaigns[idx].name + "?")) {
if (confirm(T("Delete ") + campaigns[idx].name + "?")) {
api.campaignId.delete(campaigns[idx].id)
.success(function(data) {
successFlash(data.message)
@ -68,11 +68,11 @@ $(document).ready(function() {
campaignTable.row.add([
escapeHtml(campaign.name),
campaign_date,
"<span class=\"label " + label + "\">" + campaign.status + "</span>",
"<div class='pull-right'><a class='btn btn-primary' href='/campaigns/" + campaign.id + "' data-toggle='tooltip' data-placement='right' title='View Results'>\
"<span class=\"label " + label + "\">" + T(campaign.status) + "</span>",
"<div class='pull-right'><a class='btn btn-primary' href='/campaigns/" + campaign.id + "' data-toggle='tooltip' data-placement='right' title='" + T("View Results") +"'>\
<i class='fa fa-bar-chart'></i>\
</a>\
<button class='btn btn-danger' onclick='deleteCampaign(" + i + ")' data-toggle='tooltip' data-placement='right' title='Delete Campaign'>\
<button class='btn btn-danger' onclick='deleteCampaign(" + i + ")' data-toggle='tooltip' data-placement='right' title='" + T("Delete Campaign") + "'>\
<i class='fa fa-trash-o'></i>\
</button></div>"
]).draw()

View File

@ -33,7 +33,7 @@
<div class="container-fluid">
<div class="navbar-header">
<button type="button" class="navbar-toggle" data-toggle="collapse" data-target=".navbar-collapse">
<span class="sr-only">Toggle navigation</span>
<span class="sr-only">{{T "Toggle navigation"}}</span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
@ -43,19 +43,19 @@
</div>
<div class="navbar-collapse collapse">
<ul class="nav navbar-nav navbar-right">
<li><a href="/">Dashboard</a>
<li><a href="/">{{T "Dashboard"}}</a>
</li>
<li><a href="/campaigns">Campaigns</a>
<li><a href="/campaigns">{{T "Campaigns"}}</a>
</li>
<li><a href="/users">Users &amp; Groups</a>
<li><a href="/users">{{T "Users &amp; Groups"}}</a>
</li>
<li><a href="/templates">Email Templates</a>
<li><a href="/templates">{{T "Email Templates"}}</a>
</li>
<li><a href="/landing_pages">Landing Pages</a>
<li><a href="/landing_pages">{{T "Landing Pages"}}</a>
</li>
<li><a href="/sending_profiles">Sending Profiles</a>
<li><a href="/sending_profiles">{{T "Sending Profiles"}}</a>
</li>
<li><a href="/settings">Settings</a>
<li><a href="/settings">{{T "Settings"}}</a>
</li>
<li>
{{if .User}}
@ -67,7 +67,7 @@
</div>
{{else}}
<a href="/login">
<button type="button" class="btn btn-primary">Login</button>
<button type="button" class="btn btn-primary">{{T "Login"}}</button>
</a>
{{end}}
</li>
@ -79,6 +79,7 @@
<!-- Placed at the end of the document so the pages load faster -->
<script src="/js/dist/vendor.min.js"></script>
<script src="/js/dist/app/gophish.min.js"></script>
<script src="/js/src/app/localization.support.js"></script>
{{template "scripts" .}}
</body>

View File

@ -3,24 +3,24 @@
<div class="row">
<div class="col-sm-3 col-md-2 sidebar">
<ul class="nav nav-sidebar">
<li><a href="/">Dashboard</a>
<li><a href="/">{{T "Dashboard"}}</a>
</li>
<li class="active"><a href="/campaigns">Campaigns</a>
<li class="active"><a href="/campaigns">{{T "Campaigns"}}</a>
</li>
<li><a href="/users">Users &amp; Groups</a>
<li><a href="/users">{{T "Users &amp; Groups"}}</a>
</li>
<li><a href="/templates">Email Templates</a>
<li><a href="/templates">{{T "Email Templates"}}</a>
</li>
<li><a href="/landing_pages">Landing Pages</a>
<li><a href="/landing_pages">{{T "Landing Pages"}}</a>
</li>
<li><a href="/sending_profiles">Sending Profiles</a>
<li><a href="/sending_profiles">{{T "Sending Profiles"}}</a>
</li>
<li><a href="/settings">Settings</a>
<li><a href="/settings">{{T "Settings"}}</a>
</li>
<li><hr></li>
<li><a href="https://gophish.gitbooks.io/user-guide/content/">User Guide</a>
<li><a href="https://gophish.gitbooks.io/user-guide/content/">{{T "User Guide"}}</a>
</li>
<li><a href="/api/">API Documentation</a>
<li><a href="/api/">{{T "API Documentation"}}</a>
</li>
</ul>
</div>
@ -32,36 +32,36 @@
</div>
<div style="display:none;" id="campaignResults">
<div class="row">
<h1 class="page-header" id="page-title">Results for campaign.name</h1>
<h1 class="page-header" id="page-title">{{T "Results for campaign.name"}}</h1>
</div>
<div class="row">
<a href="/campaigns" class="btn btn-default">
<i class="fa fa-arrow-circle-o-left fa-lg"></i> Back
<i class="fa fa-arrow-circle-o-left fa-lg"></i> {{T "Back"}}
</a>
<div class="btn-group">
<button type="button" id="exportButton" class="btn btn-primary dropdown-toggle" data-toggle="dropdown" aria-haspopup="true" aria-expanded="true">
<i class="fa fa-file-excel-o"></i> Export CSV
<i class="fa fa-file-excel-o"></i> {{T "Export CSV"}}
<i class="fa fa-caret-down"></i>
</button>
<ul class="dropdown-menu" aria-labelledby="exportButton">
<li><a href="#" onclick="exportAsCSV('results')">Results</a></li>
<li><a href="#" onclick="exportAsCSV('events')">Raw Events</a></li>
<li><a href="#" onclick="exportAsCSV('results')">{{T "Results"}}</a></li>
<li><a href="#" onclick="exportAsCSV('events')">{{T "Raw Events"}}</a></li>
</ul>
</div>
<button id="complete_button" type="button" class="btn btn-blue" data-toggle="tooltip" onclick="completeCampaign()">
<i class="fa fa-flag-checkered"></i> Complete
<i class="fa fa-flag-checkered"></i> {{T "Complete"}}
</button>
<button type="button" class="btn btn-danger" data-toggle="tooltip" onclick="deleteCampaign()">
<i class="fa fa-trash-o fa-lg"></i> Delete
<i class="fa fa-trash-o fa-lg"></i> {{T "Delete"}}
</button>
<span id="refresh_message">
<i class="fa fa-spin fa-spinner"></i> Refreshing
<i class="fa fa-spin fa-spinner"></i> {{T "Refreshing"}}
</span>
</div>
<br />
<div class="row">
<ul class="nav nav-tabs" role="tablist">
<li class="active"><a href="#overview" aria-controls="home" role="tab" data-toggle="tab">Overview</a></li>
<li class="active"><a href="#overview" aria-controls="home" role="tab" data-toggle="tab">{{T "Overview"}}</a></li>
<!--<li><a href="#plugins" aria-controls="profile" role="tab" data-toggle="tab">Plugins</a></li>
<li><a href="#demographics" aria-controls="settings" role="tab" data-toggle="tab">Demographics</a></li>-->
</ul>
@ -70,12 +70,12 @@
<br/>
<div class="row">
<div class="col-lg-6 col-md-6 col-sm-12 col-xs-12">
<p style="text-align:center;">Campaign Timeline</p>
<p style="text-align:center;">{{T "Campaign Timeline"}}</p>
<br/>
<div id="timeline_chart"></div>
</div>
<div class="col-lg-6 col-md-6 col-sm-12 col-xs-12">
<p style="text-align:center;">Email Status</p>
<p style="text-align:center;">{{T "Email Status"}}</p>
<div id="email_chart" class="col-lg-7 col-md-7"></div>
<div class="col-lg-5 col-md-5">
<ul id="email_chart_legend" class="chartist-legend">
@ -85,7 +85,7 @@
</div>
<div class="row">
<div class="col-md-6">
<p style="text-align:center;">Targets Map</p>
<p style="text-align:center;">{{T "Targets Map"}}</p>
<div id="resultsMap"></div>
</div>
</div>
@ -99,17 +99,17 @@
</div>
</div>
<div class="row">
<h2>Details</h2>
<h2>{{T "Details"}}</h2>
<table id="resultsTable" class="table">
<thead>
<tr>
<th>Result ID</th>
<th>{{T "Result ID"}}</th>
<th class="no-sort"></th>
<th>First Name</th>
<th>Last Name</th>
<th>Email</th>
<th>Position</th>
<th>Status</th>
<th>{{T "First Name"}}</th>
<th>{{T "Last Name"}}</th>
<th>{{T "Email"}}</th>
<th>{{T "Position"}}</th>
<th>{{T "Status"}}</th>
</tr>
</thead>
<tbody>

View File

@ -3,24 +3,24 @@
<div class="row">
<div class="col-sm-3 col-md-2 sidebar">
<ul class="nav nav-sidebar">
<li><a href="/">Dashboard</a>
<li><a href="/">{{T "Dashboard"}}</a>
</li>
<li class="active"><a href="/campaigns">Campaigns</a>
<li class="active"><a href="/campaigns">{{T "Campaigns"}}</a>
</li>
<li><a href="/users">Users &amp; Groups</a>
<li><a href="/users">{{T "Users &amp; Groups"}}</a>
</li>
<li><a href="/templates">Email Templates</a>
<li><a href="/templates">{{T "Email Templates"}}</a>
</li>
<li><a href="/landing_pages">Landing Pages</a>
<li><a href="/landing_pages">{{T "Landing Pages"}}</a>
</li>
<li><a href="/sending_profiles">Sending Profiles</a>
<li><a href="/sending_profiles">{{T "Sending Profiles"}}</a>
</li>
<li><a href="/settings">Settings</a>
<li><a href="/settings">{{T "Settings"}}</a>
</li>
<li><hr></li>
<li><a href="https://gophish.gitbooks.io/user-guide/content/">User Guide</a>
<li><a href="https://gophish.gitbooks.io/user-guide/content/">{{T "User Guide"}}</a>
</li>
<li><a href="/api/">API Documentation</a>
<li><a href="/api/">{{T "API Documentation"}}</a>
</li>
</ul>
</div>
@ -29,12 +29,12 @@
<div class="col-sm-9 col-sm-offset-3 col-md-10 col-md-offset-2 main">
<div class="row">
<h1 class="page-header">
Campaigns
{{T "Campaigns"}}
</h1>
</div>
<div id="flashes" class="row"></div>
<div class="row">
<button type="button" class="btn btn-primary" data-toggle="modal" data-target="#modal" onclick="edit('new')"><i class="fa fa-plus"></i> New Campaign</button>
<button type="button" class="btn btn-primary" data-toggle="modal" data-target="#modal" onclick="edit('new')"><i class="fa fa-plus"></i> {{T "New Campaign"}}</button>
</div>
&nbsp;
<div id="loading">
@ -42,16 +42,16 @@
</div>
<div id="emptyMessage" class="row" style="display:none;">
<div class="alert alert-info">
No campaigns created yet. Let's create one!
{{T "No campaigns created yet. Let's create one!"}}
</div>
</div>
<div class="row">
<table id="campaignTable" class="table" style="display:none;">
<thead>
<tr>
<th class="col-md-3">Name</th>
<th class="col-md-4">Created Date</th>
<th class="col-md-2">Status</th>
<th class="col-md-3">{{T "Name"}}</th>
<th class="col-md-4">{{T "Created Date"}}</th>
<th class="col-md-2">{{T "Status"}}</th>
<th class="col-md-3 no-sort"></th>
</tr>
</thead>
@ -66,41 +66,41 @@
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-label="Close" onclick="dismiss()"><span aria-hidden="true">&times;</span></button>
<h4 class="modal-title" id="campaignModalLabel">New Campaign</h4>
<h4 class="modal-title" id="campaignModalLabel">{{T "New Campaign"}}</h4>
</div>
<div class="modal-body" id="modal_body">
<div class="row" id="modal.flashes"></div>
<div class="form-group">
<label for="name">Name:</label>
<input type="text" class="form-control" id="name" placeholder="Campaign name" autofocus>
<label class="control-label" for="template">Email Template:</label>
<select class="form-control" placeholder="Template Name" id="template"/>
<label for="name">{{T "Name"}}:</label>
<input type="text" class="form-control" id="name" placeholder="{{T "Campaign name"}}" autofocus>
<label class="control-label" for="template">{{T "Email Template"}}:</label>
<select class="form-control" placeholder="{{T "Template Name"}}" id="template"/>
<option></option>
</select>
<label class="control-label" for="page">Landing Page:</label>
<label class="control-label" for="page">{{T "Landing Page"}}:</label>
<select class="form-control" placeholder="Landing Page" id="page"/>
<option></option>
</select>
<label class="control-label" for="url">URL: <i class="fa fa-question-circle" data-toggle="tooltip" data-placement="right" title="Location of gophish listener (must be reachable by targets!)"></i></label>
<label class="control-label" for="url">{{T "URL"}}: <i class="fa fa-question-circle" data-toggle="tooltip" data-placement="right" title="{{T "Location of gophish listener (must be reachable by targets!)"}}"></i></label>
<input type="text" class="form-control" placeholder="http://192.168.1.1" id="url"/>
<label class="control-label" for="url">Schedule: </label>
<label class="control-label" for="url">{{T "Schedule"}}: </label>
<input type="text" class="form-control" id="launch_date"/>
<label class="control-label" for="profile">Sending Profile:</label>
<label class="control-label" for="profile">{{T "Sending Profile"}}:</label>
<div class="input-group">
<select class="form-control" placeholder="Sending Profile" id="profile"/>
<select class="form-control" placeholder="{{T "Sending Profile"}}" id="profile"/>
<option></option>
</select>
<span class="input-group-btn">
<button type="button" data-toggle="modal" data-target="#sendTestEmailModal" class="btn btn-primary button"><i class="fa fa-envelope"></i> Send Test Email</button>
<button type="button" data-toggle="modal" data-target="#sendTestEmailModal" class="btn btn-primary button"><i class="fa fa-envelope"></i> {{T "Send Test Email"}}</button>
</span>
</div>
<label class="control-label" for="users">Groups:</label>
<label class="control-label" for="users">{{T "Groups"}}:</label>
<select class="form-control" id="users" multiple="multiple"></select>
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-default" data-dismiss="modal" onclick="dismiss()">Close</button>
<button type="button" id="launchButton" class="btn btn-primary" onclick="launch()"><i class="fa fa-rocket"></i> Launch Campaign</button>
<button type="button" class="btn btn-default" data-dismiss="modal" onclick="dismiss()">{{T "Close"}}</button>
<button type="button" id="launchButton" class="btn btn-primary" onclick="launch()"><i class="fa fa-rocket"></i> {{T "Launch Campaign"}}</button>
</div>
</div>
</div>
@ -112,32 +112,32 @@
<!-- New Email Modal -->
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">&times;</span></button>
<h4 class="modal-title" id="sendTestEmailModalTitle">Send Test Email</h4>
<h4 class="modal-title" id="sendTestEmailModalTitle">{{T "Send Test Email"}}</h4>
</div>
<div class="modal-body">
<div class="row" id="sendTestEmailModal.flashes"></div>
<div class="row">
<div class="col-sm-12">
<label class="control-label" for="to">Send Test Email to:</label>
<label class="control-label" for="to">{{T "Send Test Email to"}}:</label>
</div>
<br>
<div class="col-sm-2">
<input type="text" class="form-control" placeholder="First Name" name="to_first_name">
<input type="text" class="form-control" placeholder="{{T "First Name"}}" name="to_first_name">
</div>
<div class="col-sm-2">
<input type="text" class="form-control" placeholder="Last Name" name="to_last_name">
<input type="text" class="form-control" placeholder="{{T "Last Name"}}" name="to_last_name">
</div>
<div class="col-sm-4">
<input type="email" class="form-control" placeholder="Email" name="to_email" required>
<input type="email" class="form-control" placeholder="{{T "Email"}}" name="to_email" required>
</div>
<div class="col-sm-4">
<input type="text" class="form-control" placeholder="Position" name="to_position">
<input type="text" class="form-control" placeholder="{{T "Position"}}" name="to_position">
</div>
</div>
</div>
<div class="modal-footer">
<button type="button" data-dismiss="modal" class="btn btn-default">Cancel</button>
<button type="button" class="btn btn-primary" id="sendTestModalSubmit" onclick="sendTestEmail()"><i class="fa fa-envelope"></i> Send</button>
<button type="button" data-dismiss="modal" class="btn btn-default">{{T "Cancel"}}</button>
<button type="button" class="btn btn-primary" id="sendTestModalSubmit" onclick="sendTestEmail()"><i class="fa fa-envelope"></i> {{T "Send"}}</button>
</div>
</div>
</div>

View File

@ -3,24 +3,24 @@
<div class="row">
<div class="col-sm-3 col-md-2 sidebar">
<ul class="nav nav-sidebar">
<li class="active"><a href="#">Dashboard</a>
<li class="active"><a href="#">{{T "Dashboard"}}</a>
</li>
<li><a href="/campaigns">Campaigns</a>
<li><a href="/campaigns">{{T "Campaigns"}}</a>
</li>
<li><a href="/users">Users &amp; Groups</a>
<li><a href="/users">{{T "Users &amp; Groups"}}</a>
</li>
<li><a href="/templates">Email Templates</a>
<li><a href="/templates">{{T "Email Templates"}}</a>
</li>
<li><a href="/landing_pages">Landing Pages</a>
<li><a href="/landing_pages">{{T "Landing Pages"}}</a>
</li>
<li><a href="/sending_profiles">Sending Profiles</a>
<li><a href="/sending_profiles">{{T "Sending Profiles"}}</a>
</li>
<li><a href="/settings">Settings</a>
<li><a href="/settings">{{T "Settings"}}</a>
</li>
<li><hr></li>
<li><a href="https://gophish.gitbooks.io/user-guide/content/">User Guide</a>
<li><a href="https://gophish.gitbooks.io/user-guide/content/">{{T "User Guide"}}</a>
</li>
<li><a href="/api/">API Documentation</a>
<li><a href="/api/">{{T "API Documentation"}}</a>
</li>
</ul>
</div>
@ -28,50 +28,50 @@
</div>
<div class="col-sm-9 col-sm-offset-3 col-md-10 col-md-offset-2 main">
<h1 class="page-header">
Dashboard
{{T "Dashboard"}}
</h1>
<div id="loading">
<i class="fa fa-spinner fa-spin fa-4x"></i>
</div>
<div id="emptyMessage" class="row" style="display:none;">
<div class="alert alert-info">
No campaigns created yet. Let's create one!
{{T "No campaigns created yet. Let's create one!"}}
</div>
</div>
<div id="dashboard" style="display:none;">
<div class="row">
<div id="overview_chart" class="col-lg-6 col-md-6 col-sm-12 col-xs-12">
<p style="text-align:center;">Phishing Success Overview</p>
<p style="text-align:center;">{{T "Phishing Success Overview"}}</p>
</div>
<div class="col-lg-6 col-md-6 col-sm-12 col-xs-12">
<p style="text-align:center;">Average Phishing Results</p>
<p style="text-align:center;">{{T "Average Phishing Results"}}</p>
<div id="average_chart" class="col-lg-7 col-md-7"></div>
<div id="average_chart_legend" class="col-lg-5 col-md-5">
<ul class="chartist-legend">
<li>
<span style="background-color:#f05b4f;"></span> Successful Phishes
<span style="background-color:#f05b4f;"></span> {{T "Successful Phishes"}}
</li>
<li>
<span style="background-color:#1abc9c;"></span> Unsuccessful Phishes
<span style="background-color:#1abc9c;"></span> {{T "Unsuccessful Phishes"}}
</li>
</ul>
</div>
</div>
</div>
<div class="row">
<h2>Recent Campaigns</h2>
<h2>{{T "Recent Campaigns"}}</h2>
</div>
<div class="row">
<a href="/campaigns"><button type="button" class="btn btn-primary">View All</button></a>
<a href="/campaigns"><button type="button" class="btn btn-primary">{{T "View All"}}</button></a>
</div>
&nbsp;&nbsp;
<div class="row">
<table id="campaignTable" class="table">
<thead>
<tr>
<th>Name</th>
<th>Created Date</th>
<th>Status</th>
<th>{{T "Name"}}</th>
<th>{{T "Created Date"}}</th>
<th>{{T "Status"}}</th>
<th class="col-md-2 col-sm-2 no-sort"></th>
</tr>
</thead>
@ -83,5 +83,12 @@
</div>
{{end}}
{{define "scripts"}}
<script src="/js/dist/app/dashboard.min.js"></script>
<script>
localizedDatas = {
"Delete": "Sil",
"View Results": "Sonuçları Göster",
"Delete Campaign": "Kampanyayı Sil"
}
</script>
<script src="/js/src/app/dashboard.js"></script>
{{end}}

View File

@ -3,24 +3,24 @@
<div class="row">
<div class="col-sm-3 col-md-2 sidebar">
<ul class="nav nav-sidebar">
<li><a href="/">Dashboard</a>
<li><a href="/">{{T "Dashboard"}}</a>
</li>
<li><a href="/campaigns">Campaigns</a>
<li><a href="/campaigns">{{T "Campaigns"}}</a>
</li>
<li><a href="/users">Users &amp; Groups</a>
<li><a href="/users">{{T "Users &amp; Groups"}}</a>
</li>
<li><a href="/templates">Email Templates</a>
<li><a href="/templates">{{T "Email Templates"}}</a>
</li>
<li class="active"><a href="/landing_pages">Landing Pages</a>
<li class="active"><a href="/landing_pages">{{T "Landing Pages"}}</a>
</li>
<li><a href="/sending_profiles">Sending Profiles</a>
<li><a href="/sending_profiles">{{T "Sending Profiles"}}</a>
</li>
<li><a href="/settings">Settings</a>
<li><a href="/settings">{{T "Settings"}}</a>
</li>
<li><hr></li>
<li><a href="https://gophish.gitbooks.io/user-guide/content/">User Guide</a>
<li><a href="https://gophish.gitbooks.io/user-guide/content/">{{T "User Guide"}}</a>
</li>
<li><a href="/api/">API Documentation</a>
<li><a href="/api/">{{T "API Documentation"}}</a>
</li>
</ul>
</div>
@ -28,11 +28,11 @@
</div>
<div class="col-sm-9 col-sm-offset-3 col-md-10 col-md-offset-2 main">
<h1 class="page-header">
Landing Pages
{{T "Landing Pages"}}
</h1>
<div id="flashes" class="row"></div>
<div class="row">
<button type="button" class="btn btn-primary" onclick="edit(-1)" data-toggle="modal" data-target="#modal"><i class="fa fa-plus"></i> New Page</button>
<button type="button" class="btn btn-primary" onclick="edit(-1)" data-toggle="modal" data-target="#modal"><i class="fa fa-plus"></i> {{T "New Page"}}</button>
</div>
&nbsp;
<div id="loading">
@ -40,15 +40,15 @@
</div>
<div id="emptyMessage" class="row" style="display:none;">
<div class="alert alert-info">
No pages created yet. Let's create one!
{{T "No pages created yet. Let's create one!"}}
</div>
</div>
<div class="row">
<table id="pagesTable" class="table" style="display:none;">
<thead>
<tr>
<th>Name</th>
<th>Last Modified Date</th>
<th>{{T "Name"}}</th>
<th>{{T "Last Modified Date"}}</th>
<th class="col-md-2 no-sort"></th>
</tr>
</thead>
@ -64,16 +64,16 @@
<!-- New Template Modal -->
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-label="Close" onclick="dismiss()"><span aria-hidden="true">&times;</span></button>
<h4 class="modal-title" id="modalLabel">New Landing Page</h4>
<h4 class="modal-title" id="modalLabel">{{T "New Landing Page"}}</h4>
</div>
<div class="modal-body">
<div class="row" id="modal.flashes"></div>
<label class="control-label" for="name">Name:</label>
<label class="control-label" for="name">{{T "Name"}}:</label>
<div class="form-group">
<input type="text" class="form-control" placeholder="Page name" id="name" autofocus/>
<input type="text" class="form-control" placeholder="{{T "Page name"}}" id="name" autofocus/>
</div>
<div class="form-group">
<button class="btn btn-danger" data-toggle="modal" data-target="#importSiteModal"><i class="fa fa-globe"></i> Import Site</button>
<button class="btn btn-danger" data-toggle="modal" data-target="#importSiteModal"><i class="fa fa-globe"></i> {{T "Import Site"}}</button>
</div>
<!-- Nav tabs -->
<ul class="nav nav-tabs" role="tablist">
@ -87,25 +87,25 @@
</div>
<div class="checkbox checkbox-primary">
<input id="capture_credentials_checkbox" type="checkbox">
<label for="capture_credentials_checkbox">Capture Submitted Data <i class="fa fa-question-circle" data-toggle="tooltip" data-placement="right" title="If the landing page contains a form, submitted input (except passwords!) will be captured."></i></label>
<label for="capture_credentials_checkbox">{{T "Capture Submitted Data"}} <i class="fa fa-question-circle" data-toggle="tooltip" data-placement="right" title="{{T "If the landing page contains a form, submitted input (except passwords!) will be captured."}}"></i></label>
</div>
<div class="checkbox checkbox-primary" id="capture_passwords">
<input id="capture_passwords_checkbox" type="checkbox">
<label for="capture_passwords_checkbox">Capture Passwords</label>
<label for="capture_passwords_checkbox">{{T "Capture Passwords"}}</label>
<div class="alert alert-warning">
<i class="fa fa-exclamation-circle"></i> <b>Warning:</b> Credentials are currently <b>not encrypted</b>. This means that captured passwords are stored in the database as cleartext. Be careful with this!
<i class="fa fa-exclamation-circle"></i> {{T "<b>Warning:</b> Credentials are currently <b>not encrypted</b>. This means that captured passwords are stored in the database as cleartext. Be careful with this!"}}
</div>
</div>
<div id="redirect_url">
<label class="control-label" for="redirect_url_input">Redirect to: <i class="fa fa-question-circle" data-toggle="tooltip" data-placement="right" title="This option lets you redirect the user to a page after credentials are submitted."></i></label>
<label class="control-label" for="redirect_url_input">{{T "Redirect to"}}: <i class="fa fa-question-circle" data-toggle="tooltip" data-placement="right" title="{{T "This option lets you redirect the user to a page after credentials are submitted."}}"></i></label>
<div class="form-group">
<input id="redirect_url_input" class="form-control" placeholder="http://example.com"/>
<input id="redirect_url_input" class="form-control" placeholder="{{T "http://example.com"}}"/>
</div>
</div>
</div>
<div class="modal-footer">
<button type="button" data-dismiss="modal" class="btn btn-default" onclick="dismiss()">Cancel</button>
<button type="button" class="btn btn-primary" id="modalSubmit">Save Page</button>
<button type="button" data-dismiss="modal" class="btn btn-default" onclick="dismiss()">{{T "Cancel"}}</button>
<button type="button" class="btn btn-primary" id="modalSubmit">{{T "Save Page"}}</button>
</div>
</div>
</div>
@ -117,18 +117,18 @@
<!-- New Template Modal -->
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">&times;</span></button>
<h4 class="modal-title" id="importSiteModalLabel">Import Site</h4>
<h4 class="modal-title" id="importSiteModalLabel">{{T "Import Site"}}</h4>
</div>
<div class="modal-body">
<div class="row" id="modal.flashes"></div>
<label class="control-label" for="url">URL:</label>
<label class="control-label" for="url">{{T "URL"}}:</label>
<div class="form-group">
<input type="text" class="form-control" placeholder="http://google.com" id="url" autofocus/>
<input type="text" class="form-control" placeholder="{{T "http://google.com"}}" id="url" autofocus/>
</div>
</div>
<div class="modal-footer">
<button type="button" data-dismiss="modal" class="btn btn-default">Cancel</button>
<button type="button" class="btn btn-primary" id="modalSubmit" onclick="importSite()">Import</button>
<button type="button" data-dismiss="modal" class="btn btn-default">{{T "Cancel"}}</button>
<button type="button" class="btn btn-primary" id="modalSubmit" onclick="importSite()">{{T "Import"}}</button>
</div>
</div>
</div>

View File

@ -21,7 +21,7 @@
<div class="container-fluid">
<div class="navbar-header">
<button type="button" class="navbar-toggle" data-toggle="collapse" data-target=".navbar-collapse">
<span class="sr-only">Toggle navigation</span>
<span class="sr-only">{{T "Toggle navigation"}}</span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
@ -33,7 +33,7 @@
<ul class="nav navbar-nav navbar-right">
<li>
<a id="login-button" href="/login">
<button type="button" class="btn btn-primary">Login</button>
<button type="button" class="btn btn-primary">{{T "Login"}}</button>
</a>
</li>
</ul>
@ -43,12 +43,12 @@
<div class="container">
<form class="form-signin" action="/login" method="POST">
<img id="logo" src="/images/logo_purple.png" />
<h2 class="form-signin-heading">Please sign in</h2>
<h2 class="form-signin-heading">{{T "Please sign in"}}</h2>
{{template "flashes" .Flashes}}
<input type="text" name="username" class="form-control top-input" placeholder="Username" required autofocus>
<input type="password" name="password" class="form-control bottom-input" placeholder="Password" autocomplete="off" required>
<input type="text" name="username" class="form-control top-input" placeholder="{{T "Username"}}" required autofocus>
<input type="password" name="password" class="form-control bottom-input" placeholder="{{T "Password"}}" autocomplete="off" required>
<input type="hidden" name="csrf_token" value="{{.Token}}"/>
<button class="btn btn-lg btn-primary btn-block" type="submit">Sign in</button>
<button class="btn btn-lg btn-primary btn-block" type="submit">{{T "Sign in"}}</button>
</form>
</div>
<!-- Placed at the end of the document so the pages load faster -->

View File

@ -21,7 +21,7 @@
<div class="container-fluid">
<div class="navbar-header">
<button type="button" class="navbar-toggle" data-toggle="collapse" data-target=".navbar-collapse">
<span class="sr-only">Toggle navigation</span>
<span class="sr-only">{{T "Toggle navigation"}}</span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
@ -33,7 +33,7 @@
<ul class="nav navbar-nav navbar-right">
<li>
<a id="login-button" href="/login">
<button type="button" class="btn btn-primary">Login</button>
<button type="button" class="btn btn-primary">{{T "Login"}}</button>
</a>
</li>
</ul>
@ -43,13 +43,13 @@
<div class="container">
<form class="form-signin" action="/register" method="POST">
<img id="logo" src="/images/logo_purple.png" />
<h2 class="form-signin-heading">Please register below</h2>
<h2 class="form-signin-heading">{{T "Please register below"}}</h2>
{{template "flashes" .Flashes}}
<input type="text" name="username" class="form-control top-input" placeholder="Username" required autofocus/>
<input type="password" name="password" class="form-control middle-input" placeholder="Password" autocomplete="off" required/>
<input type="text" name="username" class="form-control top-input" placeholder="{{T "Username"}}" required autofocus/>
<input type="password" name="password" class="form-control middle-input" placeholder="{{T "Password"}}" autocomplete="off" required/>
<input type="password" name="confirm_password" class="form-control bottom-input" placeholder="Confirm Password" autocomplete="off" required/>
<input type="hidden" name="csrf_token" value="{{.Token}}"/>
<button class="btn btn-lg btn-primary btn-block" type="submit">Register</button>
<button class="btn btn-lg btn-primary btn-block" type="submit">{{T "Register"}}</button>
</form>
</div>
<!-- Placed at the end of the document so the pages load faster -->

View File

@ -3,24 +3,24 @@
<div class="row">
<div class="col-sm-3 col-md-2 sidebar">
<ul class="nav nav-sidebar">
<li><a href="/">Dashboard</a>
<li><a href="/">{{T "Dashboard"}}</a>
</li>
<li><a href="/campaigns">Campaigns</a>
<li><a href="/campaigns">{{T "Campaigns"}}</a>
</li>
<li><a href="/users">Users &amp; Groups</a>
<li><a href="/users">{{T "Users &amp; Groups"}}</a>
</li>
<li><a href="/templates">Email Templates</a>
<li><a href="/templates">{{T "Email Templates"}}</a>
</li>
<li><a href="/landing_pages">Landing Pages</a>
<li><a href="/landing_pages">{{T "Landing Pages"}}</a>
</li>
<li class="active"><a href="/sending_profiles">Sending Profiles</a>
<li class="active"><a href="/sending_profiles">{{T "Sending Profiles"}}</a>
</li>
<li><a href="/settings">Settings</a>
<li><a href="/settings">{{T "Settings"}}</a>
</li>
<li><hr></li>
<li><a href="https://gophish.gitbooks.io/user-guide/content/">User Guide</a>
<li><a href="https://gophish.gitbooks.io/user-guide/content/">{{T "User Guide"}}</a>
</li>
<li><a href="/api/">API Documentation</a>
<li><a href="/api/">{{T "API Documentation"}}</a>
</li>
</ul>
</div>
@ -28,11 +28,11 @@
</div>
<div class="col-sm-9 col-sm-offset-3 col-md-10 col-md-offset-2 main">
<h1 class="page-header">
Sending Profiles
{{T "Sending Profiles"}}
</h1>
<div id="flashes" class="row"></div>
<div class="row">
<button type="button" class="btn btn-primary" onclick="edit(-1)" data-toggle="modal" data-target="#modal"><i class="fa fa-plus"></i> New Profile</button>
<button type="button" class="btn btn-primary" onclick="edit(-1)" data-toggle="modal" data-target="#modal"><i class="fa fa-plus"></i> {{T "New Profile"}}</button>
</div>
&nbsp;
<div id="loading">
@ -40,16 +40,16 @@
</div>
<div id="emptyMessage" class="row" style="display:none;">
<div class="alert alert-info">
No profiles created yet. Let's create one!
{{T "No profiles created yet. Let's create one!"}}
</div>
</div>
<div class="row">
<table id="profileTable" class="table" style="display:none;">
<thead>
<tr>
<th class="col-md-4">Name</th>
<th>Interface Type</th>
<th>Last Modified Date</th>
<th class="col-md-4">{{T "Name"}}</th>
<th>{{T "Interface Type"}}</th>
<th>{{T "Last Modified Date"}}</th>
<th class="col-md-2 no-sort"></th>
</tr>
</thead>
@ -65,34 +65,34 @@
<!-- New Template Modal -->
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-label="Close" onclick="dismiss()"><span aria-hidden="true">&times;</span></button>
<h4 class="modal-title" id="profileModalLabel">New Sending Profile</h4>
<h4 class="modal-title" id="profileModalLabel">{{T "New Sending Profile"}}</h4>
</div>
<div class="modal-body">
<div class="row" id="modal.flashes"></div>
<div class="form-group">
<label class="control-label" for="name">Name:</label>
<label class="control-label" for="name">{{T "Name"}}:</label>
<input type="text" class="form-control" placeholder="Profile name" id="name" autofocus/>
<label class="control-label" for="interface_type">Interface Type:</label>
<input type="text" class="form-control" value="SMTP" id="interface_type" disabled/>
<label class="control-label" for="from">From:</label>
<input type="text" class="form-control" placeholder="First Last <test@example.com>" id="from" required/>
<label class="control-label" for="host">Host:</label>
<input type="text" class="form-control" placeholder="smtp.example.com:25" id="host" required/>
<label class="control-label" for="username">Username:</label>
<input type="text" class="form-control" placeholder="Username" id="username"/>
<label class="control-label" for="password">Password:</label>
<input type="password" class="form-control" placeholder="Password" id="password"/>
<label class="control-label" for="interface_type">{{T "Interface Type"}}:</label>
<input type="text" class="form-control" value="{{T "SMTP"}}" id="interface_type" disabled/>
<label class="control-label" for="from">{{T "From"}}:</label>
<input type="text" class="form-control" placeholder="{{T "First Last <test@example.com>"}}" id="from" required/>
<label class="control-label" for="host">{{T "Host"}}:</label>
<input type="text" class="form-control" placeholder="{{T "smtp.example.com:25"}}" id="host" required/>
<label class="control-label" for="username">{{T "Username"}}:</label>
<input type="text" class="form-control" placeholder="{{T "Username"}}" id="username"/>
<label class="control-label" for="password">{{T "Password"}}:</label>
<input type="password" class="form-control" placeholder="{{T "Password"}}" id="password"/>
<div class="checkbox checkbox-primary">
<input id="ignore_cert_errors" type="checkbox" checked>
<label for="ignore_cert_errors">Ignore Certificate Errors <i class="fa fa-question-circle" data-toggle="tooltip" data-placement="right" title="Ignore common certificate errors such as self-signed certs (exposes you to MiTM attacks - use carefully!)"></i></label>
<label for="ignore_cert_errors">{{T "Ignore Certificate Errors"}} <i class="fa fa-question-circle" data-toggle="tooltip" data-placement="right" title="{{T "Ignore common certificate errors such as self-signed certs (exposes you to MiTM attacks - use carefully!)"}}"></i></label>
</div>
<button type="button" data-toggle="modal" data-target="#sendTestEmailModal" class="btn btn-primary"><i class="fa fa-envelope"></i> Send Test Email</button>
<button type="button" data-toggle="modal" data-target="#sendTestEmailModal" class="btn btn-primary"><i class="fa fa-envelope"></i> {{T "Send Test Email"}}</button>
<!-- disable sendTestEmail functionality on sending profile page until update handling of /util/send_test_email -->
</div>
</div>
<div class="modal-footer">
<button type="button" data-dismiss="modal" class="btn btn-default" onclick="dismiss()">Cancel</button>
<button type="button" class="btn btn-primary" id="modalSubmit">Save Profile</button>
<button type="button" data-dismiss="modal" class="btn btn-default" onclick="dismiss()">{{T "Cancel"}}</button>
<button type="button" class="btn btn-primary" id="modalSubmit">{{T "Save Profile"}}</button>
</div>
</div>
</div>
@ -104,32 +104,32 @@
<!-- New Email Modal -->
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">&times;</span></button>
<h4 class="modal-title" id="sendTestEmailModalTitle">Send Test Email</h4>
<h4 class="modal-title" id="sendTestEmailModalTitle">{{T "Send Test Email"}}</h4>
</div>
<div class="modal-body">
<div class="row" id="sendTestEmailModal.flashes"></div>
<div class="row">
<div class="col-sm-12">
<label class="control-label" for="to">Send Test Email to:</label>
<label class="control-label" for="to">{{T "Send Test Email to"}}:</label>
</div>
<br>
<div class="col-sm-2">
<input type="text" class="form-control" placeholder="First Name" name="to_first_name">
<input type="text" class="form-control" placeholder="{{T "First Name"}}" name="to_first_name">
</div>
<div class="col-sm-2">
<input type="text" class="form-control" placeholder="Last Name" name="to_last_name">
<input type="text" class="form-control" placeholder="{{T "Last Name"}}" name="to_last_name">
</div>
<div class="col-sm-4">
<input type="email" class="form-control" placeholder="Email" name="to_email" required>
<input type="email" class="form-control" placeholder="{{T "Email"}}" name="to_email" required>
</div>
<div class="col-sm-4">
<input type="text" class="form-control" placeholder="Position" name="to_position">
<input type="text" class="form-control" placeholder="{{T "Position"}}" name="to_position">
</div>
</div>
</div>
<div class="modal-footer">
<button type="button" data-dismiss="modal" class="btn btn-default">Cancel</button>
<button type="button" class="btn btn-primary" id="sendTestModalSubmit" onclick="sendTestEmail()"><i class="fa fa-envelope"></i> Send</button>
<button type="button" data-dismiss="modal" class="btn btn-default">{{T "Cancel"}}</button>
<button type="button" class="btn btn-primary" id="sendTestModalSubmit" onclick="sendTestEmail()"><i class="fa fa-envelope"></i> {{T "Send"}}</button>
</div>
</div>
</div>

View File

@ -3,24 +3,24 @@
<div class="row">
<div class="col-sm-3 col-md-2 sidebar">
<ul class="nav nav-sidebar">
<li><a href="/">Dashboard</a>
<li><a href="/">{{T "Dashboard"}}</a>
</li>
<li><a href="/campaigns">Campaigns</a>
<li><a href="/campaigns">{{T "Campaigns"}}</a>
</li>
<li><a href="/users">Users &amp; Groups</a>
<li><a href="/users">{{T "Users &amp; Groups"}}</a>
</li>
<li><a href="/templates">Email Templates</a>
<li><a href="/templates">{{T "Email Templates"}}</a>
</li>
<li><a href="/landing_pages">Landing Pages</a>
<li><a href="/landing_pages">{{T "Landing Pages"}}</a>
</li>
<li><a href="/sending_profiles">Sending Profiles</a>
<li><a href="/sending_profiles">{{T "Sending Profiles"}}</a>
</li>
<li class="active"><a href="/settings">Settings</a>
<li class="active"><a href="/settings">{{T "Settings"}}</a>
</li>
<li><hr></li>
<li><a href="https://gophish.gitbooks.io/user-guide/content/">User Guide</a>
<li><a href="https://gophish.gitbooks.io/user-guide/content/">{{T "User Guide"}}</a>
</li>
<li><a href="/api/">API Documentation</a>
<li><a href="/api/">{{T "API Documentation"}}</a>
</li>
</ul>
</div>
@ -28,65 +28,65 @@
</div>
<div class="col-sm-9 col-sm-offset-3 col-md-10 col-md-offset-2 main">
<div class="row">
<h1 class="page-header">Settings</h1>
<h1 class="page-header">{{T "Settings"}}</h1>
</div>
<div id="flashes" class="row"></div>
<div class="row">
<label class="col-sm-2 control-label form-label">Gophish version</label>
<label class="col-sm-2 control-label form-label">{{T "Gophish version"}}</label>
<div class="col-md-6">
<label class="form-label">{{.Version}}</label>
</div>
</div>
<br/>
<div class="row">
<label class="col-sm-2 control-label form-label">Register a New User</label>
<label class="col-sm-2 control-label form-label">{{T "Register a New User"}}</label>
<div class="col-md-6">
<a href="/register" class="btn btn-primary"><i class="fa fa-plus"></i> Add User</a>
<a href="/register" class="btn btn-primary"><i class="fa fa-plus"></i> {{T "Add User"}}</a>
</div>
</div>
<br/>
<div class="row">
<label for="api_key" class="col-sm-2 control-label form-label">API Key:</label>
<label for="api_key" class="col-sm-2 control-label form-label">{{T "API Key"}}:</label>
<div class="col-md-6">
<input type="text" id="api_key" onclick="this.select();" value="{{.User.ApiKey}}" class="form-control" readonly/>
</div>
<form id="apiResetForm">
<button class="btn btn-primary"><i class="fa fa-refresh" type="submit"></i> Reset</button>
<button class="btn btn-primary"><i class="fa fa-refresh" type="submit"></i> {{T "Reset"}}</button>
<input type="hidden" name="csrf_token" value="{{.Token}}"/>
</form>
</div>
<br />
<form id="settingsForm">
<div class="row">
<label for="username" class="col-sm-2 control-label form-label">Username:</label>
<label for="username" class="col-sm-2 control-label form-label">{{T "Username"}}:</label>
<div class="col-md-6">
<input type="text" id="username" name="username" value="{{.User.Username}}" class="form-control" />
</div>
</div>
<br />
<div class="row">
<label for="current_password" class="col-sm-2 control-label form-label">Old Password:</label>
<label for="current_password" class="col-sm-2 control-label form-label">{{T "Old Password"}}:</label>
<div class="col-md-6">
<input type="password" id="current_password" name="current_password" autocomplete="off" class="form-control"/>
</div>
</div>
<br />
<div class="row">
<label for="new_password" class="col-sm-2 control-label form-label">New Password:</label>
<label for="new_password" class="col-sm-2 control-label form-label">{{T "New Password"}}:</label>
<div class="col-md-6">
<input type="password" id="new_password" name="new_password" autocomplete="off" class="form-control" />
</div>
</div>
<br />
<div class="row">
<label for="confirm_new_password" class="col-sm-2 control-label form-label">Confirm New Password:</label>
<label for="confirm_new_password" class="col-sm-2 control-label form-label">{{T "Confirm New Password"}}:</label>
<div class="col-md-6">
<input type="password" id="confirm_new_password" name="confirm_new_password" autocomplete="off" class="form-control" />
</div>
</div>
<input type="hidden" name="csrf_token" value="{{.Token}}"/>
<br />
<button class="btn btn-primary" type="submit"><i class="fa fa-save"></i> Save</button>
<button class="btn btn-primary" type="submit"><i class="fa fa-save"></i> {{T "Save"}}</button>
</form>
<br/>
</div>

View File

@ -3,24 +3,24 @@
<div class="row">
<div class="col-sm-3 col-md-2 sidebar">
<ul class="nav nav-sidebar">
<li><a href="/">Dashboard</a>
<li><a href="/">{{T "Dashboard"}}</a>
</li>
<li><a href="/campaigns">Campaigns</a>
<li><a href="/campaigns">{{T "Campaigns"}}</a>
</li>
<li><a href="/users">Users &amp; Groups</a>
<li><a href="/users">{{T "Users &amp; Groups"}}</a>
</li>
<li class="active"><a href="/templates">Email Templates</a>
<li class="active"><a href="/templates">{{T "Email Templates"}}</a>
</li>
<li><a href="/landing_pages">Landing Pages</a>
<li><a href="/landing_pages">{{T "Landing Pages"}}</a>
</li>
<li><a href="/sending_profiles">Sending Profiles</a>
<li><a href="/sending_profiles">{{T "Sending Profiles"}}</a>
</li>
<li><a href="/settings">Settings</a>
<li><a href="/settings">{{T "Settings"}}</a>
</li>
<li><hr></li>
<li><a href="https://gophish.gitbooks.io/user-guide/content/">User Guide</a>
<li><a href="https://gophish.gitbooks.io/user-guide/content/">{{T "User Guide"}}</a>
</li>
<li><a href="/api/">API Documentation</a>
<li><a href="/api/">{{T "API Documentation"}}</a>
</li>
</ul>
</div>
@ -29,12 +29,12 @@
<div class="col-sm-9 col-sm-offset-3 col-md-10 col-md-offset-2 main">
<div class="row">
<h1 class="page-header">
Email Templates
{{T "Email Templates"}}
</h1>
</div>
<div id="flashes" class="row"></div>
<div class="row">
<button type="button" class="btn btn-primary" onclick="edit(-1)" data-toggle="modal" data-target="#modal"><i class="fa fa-plus"></i> New Template</button>
<button type="button" class="btn btn-primary" onclick="edit(-1)" data-toggle="modal" data-target="#modal"><i class="fa fa-plus"></i> {{T "New Template"}}</button>
</div>
&nbsp;
<div id="loading">
@ -42,15 +42,15 @@
</div>
<div id="emptyMessage" class="row" style="display:none;">
<div class="alert alert-info">
No templates yet. Let's create one!
{{T "No templates yet. Let's create one!"}}
</div>
</div>
<div class="row">
<table id="templateTable" class="table" style="display:none;">
<thead>
<tr>
<th>Name</th>
<th>Modified Date</th>
<th>{{T "Name"}}</th>
<th>{{T "Modified Date"}}</th>
<th class="col-md-2 no-sort"></th>
</tr>
</thead>
@ -66,30 +66,30 @@
<!-- New Template Modal -->
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-label="Close" onclick="dismiss()"><span aria-hidden="true">&times;</span></button>
<h4 class="modal-title" id="templateModalLabel">New Template</h4>
<h4 class="modal-title" id="templateModalLabel">{{T "New Template"}}</h4>
</div>
<div class="modal-body">
<div class="row" id="modal.flashes"></div>
<label class="control-label" for="name">Name:</label>
<label class="control-label" for="name">{{T "Name"}}:</label>
<div class="form-group">
<input type="text" class="form-control" ng-model="template.name" placeholder="Template name" id="name" autofocus/>
</div>
<div class="form-group">
<button class="btn btn-danger" data-toggle="modal" data-target="#importEmailModal"><i class="fa fa-envelope"></i> Import Email</button>
<button class="btn btn-danger" data-toggle="modal" data-target="#importEmailModal"><i class="fa fa-envelope"></i> {{T "Import Email"}}</button>
</div>
<label class="control-label" for="subject">Subject:</label>
<label class="control-label" for="subject">{{T "Subject"}}:</label>
<div class="form-group">
<input type="text" class="form-control" placeholder="Email Subject" id="subject" />
<input type="text" class="form-control" placeholder="{{T "Email Subject"}}" id="subject" />
</div>
<!-- Nav tabs -->
<ul class="nav nav-tabs" role="tablist">
<li class="active" role="text"><a href="#text" aria-controls="text" role="tab" data-toggle="tab">Text</a></li>
<li role="html"><a href="#html" aria-controls="html" role="tab" data-toggle="tab">HTML</a></li>
<li class="active" role="text"><a href="#text" aria-controls="text" role="tab" data-toggle="tab">{{T "Text"}}</a></li>
<li role="html"><a href="#html" aria-controls="html" role="tab" data-toggle="tab">{{T "HTML"}}</a></li>
</ul>
<!-- Tab panes -->
<div class="tab-content">
<div role="tabpanel" class="tab-pane active" id="text">
<textarea rows="10" id="text_editor" class="gophish-editor form-control" placeholder="Plaintext"></textarea>
<textarea rows="10" id="text_editor" class="gophish-editor form-control" placeholder="{{T "Plaintext"}}"></textarea>
</div>
<div role="tabpanel" class="tab-pane" id="html">
<textarea id="html_editor"></textarea>
@ -97,9 +97,9 @@
</div>
<div class="checkbox checkbox-primary">
<input id="use_tracker_checkbox" type="checkbox" checked>
<label for="use_tracker_checkbox">Add Tracking Image</label>
<label for="use_tracker_checkbox">{{T "Add Tracking Image"}}</label>
</div>
<span class="btn btn-danger btn-file"><i class="fa fa-plus"></i> Add Files
<span class="btn btn-danger btn-file"><i class="fa fa-plus"></i> {{T "Add Files"}}
<input id="attachmentUpload" type="file" onchange="attach(this.files)" multiple>
</span>
<br />
@ -108,10 +108,10 @@
<thead>
<tr>
<th class="col-md-1 no-sort"></th>
<th class="col-md-10">Name</th>
<th class="col-md-10">{{T "Name"}}</th>
<th class="col-md-1 no-sort"></th>
<th class="datatable_hidden no-sort">Content</th>
<th class="datatable_hidden no-sort">Type</th>
<th class="datatable_hidden no-sort">{{T "Content"}}</th>
<th class="datatable_hidden no-sort">{{T "Type"}}</th>
</tr>
</thead>
<tbody>
@ -119,8 +119,8 @@
</table>
</div>
<div class="modal-footer">
<button type="button" data-dismiss="modal" class="btn btn-default" onclick="dismiss()">Cancel</button>
<button type="button" class="btn btn-primary" id="modalSubmit">Save Template</button>
<button type="button" data-dismiss="modal" class="btn btn-default" onclick="dismiss()">{{T "Cancel"}}</button>
<button type="button" class="btn btn-primary" id="modalSubmit">{{T "Save Template"}}</button>
</div>
</div>
</div>
@ -132,22 +132,22 @@
<!-- New Email Modal -->
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">&times;</span></button>
<h4 class="modal-title" id="importEmailModalLabel">Import Email</h4>
<h4 class="modal-title" id="importEmailModalLabel">{{T "Import Email"}}</h4>
</div>
<div class="modal-body">
<div class="row" id="modal.flashes"></div>
<label class="control-label" for="email">Email Content:</label>
<label class="control-label" for="email">{{T "Email Content"}}:</label>
<div class="form-group">
<textarea rows="10" id="email_content" class="gophish-editor form-control" placeholder="Raw Email Source"></textarea>
<textarea rows="10" id="email_content" class="gophish-editor form-control" placeholder="{{T "Raw Email Source"}}"></textarea>
</div>
<div class="checkbox checkbox-primary">
<input id="convert_links_checkbox" type="checkbox" checked>
<label for="convert_links_checkbox">Change Links to Point to Landing Page</label>
<label for="convert_links_checkbox">{{T "Change Links to Point to Landing Page"}}</label>
</div>
</div>
<div class="modal-footer">
<button type="button" data-dismiss="modal" class="btn btn-default">Cancel</button>
<button type="button" class="btn btn-primary" id="modalSubmit" onclick="importEmail()">Import</button>
<button type="button" data-dismiss="modal" class="btn btn-default">{{T "Cancel"}}</button>
<button type="button" class="btn btn-primary" id="modalSubmit" onclick="importEmail()">{{T "Import"}}</button>
</div>
</div>
</div>

View File

@ -3,24 +3,24 @@
<div class="row">
<div class="col-sm-3 col-md-2 sidebar">
<ul class="nav nav-sidebar">
<li><a href="/">Dashboard</a>
<li><a href="/">{{T "Dashboard"}}</a>
</li>
<li><a href="/campaigns">Campaigns</a>
<li><a href="/campaigns">{{T "Campaigns"}}</a>
</li>
<li class="active"><a href="#/users">Users &amp; Groups</a>
<li class="active"><a href="#/users">{{T "Users &amp; Groups"}}</a>
</li>
<li><a href="/templates">Email Templates</a>
<li><a href="/templates">{{T "Email Templates"}}</a>
</li>
<li><a href="/landing_pages">Landing Pages</a>
<li><a href="/landing_pages">{{T "Landing Pages"}}</a>
</li>
<li><a href="/sending_profiles">Sending Profiles</a>
<li><a href="/sending_profiles">{{T "Sending Profiles"}}</a>
</li>
<li><a href="/settings">Settings</a>
<li><a href="/settings">{{T "Settings"}}</a>
</li>
<li><hr></li>
<li><a href="https://gophish.gitbooks.io/user-guide/content/">User Guide</a>
<li><a href="https://gophish.gitbooks.io/user-guide/content/">{{T "User Guide"}}</a>
</li>
<li><a href="/api/">API Documentation</a>
<li><a href="/api/">{{T "API Documentation"}}</a>
</li>
</ul>
</div>
@ -29,12 +29,12 @@
<div class="col-sm-9 col-sm-offset-3 col-md-10 col-md-offset-2 main">
<div class="row">
<h1 class="page-header">
Users &amp; Groups
{{T "Users &amp; Groups"}}
</h1>
</div>
<div id="flashes" class="row"></div>
<div class="row">
<button type="button" class="btn btn-primary" onclick="edit(-1)" data-toggle="modal" data-target="#modal"><i class="fa fa-plus"></i> New Group</button>
<button type="button" class="btn btn-primary" onclick="edit(-1)" data-toggle="modal" data-target="#modal"><i class="fa fa-plus"></i> {{T "New Group"}}</button>
</div>
&nbsp;
<div id="loading">
@ -42,16 +42,16 @@
</div>
<div id="emptyMessage" class="row" style="display:none;">
<div class="alert alert-info">
No groups created yet. Let's create one!
{{T "No groups created yet. Let's create one!"}}
</div>
</div>
<div class="row">
<table id="groupTable" class="table" style="display:none;">
<thead>
<tr>
<th>Name</th>
<th># of Members</th>
<th>Modified Date</th>
<th>{{T "Name"}}</th>
<th>{{T "# of Members"}}</th>
<th>{{T "Modified Date"}}</th>
<th class="col-md-2 no-sort"></th>
</tr>
</thead>
@ -66,35 +66,35 @@
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">&times;</span></button>
<h4 class="modal-title" id="groupModalLabel">New Group</h4>
<h4 class="modal-title" id="groupModalLabel">{{T "New Group"}}</h4>
</div>
<div class="modal-body">
<div class="row" id="modal.flashes"></div>
<label class="control-label" for="name">Name:</label>
<label class="control-label" for="name">{{T "Name"}}:</label>
<div class="form-group">
<input type="text" class="form-control" ng-model="group.name" placeholder="Group name" id="name" autofocus/>
<input type="text" class="form-control" ng-model="group.name" placeholder="{{T "Group name"}}" id="name" autofocus/>
</div>
<div class="form-group">
<span class="btn btn-danger btn-file" data-toggle="tooltip" data-placement="right" title="Supports CSV files" id="fileUpload"><i class="fa fa-plus"></i> Bulk Import Users
<span class="btn btn-danger btn-file" data-toggle="tooltip" data-placement="right" title="{{T "Supports CSV files"}}" id="fileUpload"><i class="fa fa-plus"></i> {{T "Bulk Import Users"}}
<input type="file" id="csvupload" data-url="/api/import/group" multiple>
</span>
</div>
<div class="row">
<form id="targetForm">
<div class="col-sm-2">
<input type="text" class="form-control" placeholder="First Name" id="firstName">
<input type="text" class="form-control" placeholder="{{T "First Name"}}" id="firstName">
</div>
<div class="col-sm-2">
<input type="text" class="form-control" placeholder="Last Name" id="lastName">
<input type="text" class="form-control" placeholder="{{T "Last Name"}}" id="lastName">
</div>
<div class="col-sm-3">
<input type="email" class="form-control" placeholder="Email" id="email" required>
<input type="email" class="form-control" placeholder="{{T "Email"}}" id="email" required>
</div>
<div class="col-sm-3">
<input type="text" class="form-control" placeholder="Position" id="position">
<input type="text" class="form-control" placeholder="{{T "Position"}}" id="position">
</div>
<div class="col-sm-1">
<button type="submit" class="btn btn-danger btn-lg"><i class="fa fa-plus"></i> Add</button>
<button type="submit" class="btn btn-danger btn-lg"><i class="fa fa-plus"></i> {{T "Add"}}</button>
</div>
</form>
</div>
@ -102,18 +102,18 @@
<table id="targetsTable" class="table table-hover table-striped table-condensed">
<thead>
<tr>
<th>First Name</th>
<th>Last Name</th>
<th>Email</th>
<th>Position</th>
<th>{{T "First Name"}}</th>
<th>{{T "Last Name"}}</th>
<th>{{T "Email"}}</th>
<th>{{T "Position"}}</th>
<th class="no-sort"></th>
<tbody>
</tbody>
</table>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
<button type="button" class="btn btn-primary" id="modalSubmit">Save changes</button>
<button type="button" class="btn btn-default" data-dismiss="modal">{{T "Close"}}</button>
<button type="button" class="btn btn-primary" id="modalSubmit">{{T "Save changes"}}</button>
</div>
</div>
</div>

View File

@ -21,11 +21,21 @@ import (
"github.com/gophish/gophish/models"
"github.com/jordan-wright/email"
"github.com/nicksnyder/go-i18n/i18n"
)
// Logger is used to send logging messages to stdout.
var Logger = log.New(os.Stdout, " ", log.Ldate|log.Ltime|log.Lshortfile)
func T(text string) string{
T, _ := i18n.Tfunc("en-US", "en-US")
result := T(text)
if result == text {
fmt.Println("NON-TRANSLATION %s", text)
}
return result
}
// ParseMail takes in an HTTP Request and returns an Email object
// TODO: This function will likely be changed to take in a []byte
func ParseMail(r *http.Request) (email.Email, error) {