mirror of
https://github.com/gophish/gophish
synced 2024-11-14 16:27:23 +00:00
Adding support for custom headers in sending profiles (#544)
Closes #215 Closes #128
This commit is contained in:
parent
dbadac3eca
commit
66c4be3d4f
12 changed files with 429 additions and 151 deletions
|
@ -0,0 +1,12 @@
|
|||
|
||||
-- +goose Up
|
||||
-- SQL in section 'Up' is executed when this migration is applied
|
||||
CREATE TABLE IF NOT EXISTS headers(
|
||||
id integer primary key auto_increment,
|
||||
`key` varchar(255),
|
||||
`value` varchar(255),
|
||||
`smtp_id` bigint
|
||||
);
|
||||
-- +goose Down
|
||||
-- SQL section 'Down' is executed when this migration is rolled back
|
||||
DROP TABLE headers;
|
|
@ -0,0 +1,12 @@
|
|||
|
||||
-- +goose Up
|
||||
-- SQL in section 'Up' is executed when this migration is applied
|
||||
CREATE TABLE IF NOT EXISTS headers(
|
||||
id integer primary key autoincrement,
|
||||
key varchar(255),
|
||||
value varchar(255),
|
||||
"smtp_id" bigint
|
||||
);
|
||||
-- +goose Down
|
||||
-- SQL section 'Down' is executed when this migration is rolled back
|
||||
DROP TABLE headers;
|
|
@ -189,6 +189,11 @@ func (c *Campaign) getDetails() error {
|
|||
c.SMTP = SMTP{Name: "[Deleted]"}
|
||||
Logger.Printf("%s: sending profile not found for campaign\n", err)
|
||||
}
|
||||
err = db.Where("smtp_id=?", c.SMTP.Id).Find(&c.SMTP.Headers).Error
|
||||
if err != nil && err != gorm.ErrRecordNotFound {
|
||||
Logger.Println(err)
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
|
|
|
@ -246,6 +246,24 @@ func (s *ModelsSuite) TestPostSMTPNoFrom(c *check.C) {
|
|||
c.Assert(err, check.Equals, ErrFromAddressNotSpecified)
|
||||
}
|
||||
|
||||
func (s *ModelsSuite) TestPostSMTPValidHeader(c *check.C) {
|
||||
smtp := SMTP{
|
||||
Name: "Test SMTP",
|
||||
Host: "1.1.1.1:25",
|
||||
FromAddress: "Foo Bar <foo@example.com>",
|
||||
UserId: 1,
|
||||
Headers: []Header{
|
||||
Header{Key: "Reply-To", Value: "test@example.com"},
|
||||
Header{Key: "X-Mailer", Value: "gophish"},
|
||||
},
|
||||
}
|
||||
err = PostSMTP(&smtp)
|
||||
c.Assert(err, check.Equals, nil)
|
||||
ss, err := GetSMTPs(1)
|
||||
c.Assert(err, check.Equals, nil)
|
||||
c.Assert(len(ss), check.Equals, 1)
|
||||
}
|
||||
|
||||
func (s *ModelsSuite) TestPostPage(c *check.C) {
|
||||
html := `<html>
|
||||
<head></head>
|
||||
|
|
|
@ -6,6 +6,8 @@ import (
|
|||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/jinzhu/gorm"
|
||||
)
|
||||
|
||||
// SMTP contains the attributes needed to handle the sending of campaign emails
|
||||
|
@ -19,9 +21,19 @@ type SMTP struct {
|
|||
Password string `json:"password,omitempty"`
|
||||
FromAddress string `json:"from_address"`
|
||||
IgnoreCertErrors bool `json:"ignore_cert_errors"`
|
||||
Headers []Header `json:"headers"`
|
||||
ModifiedDate time.Time `json:"modified_date"`
|
||||
}
|
||||
|
||||
// Header contains the fields and methods for a sending profile to have
|
||||
// custom headers
|
||||
type Header struct {
|
||||
Id int64 `json:"-"`
|
||||
SMTPId int64 `json:"-"`
|
||||
Key string `json:"key"`
|
||||
Value string `json:"value"`
|
||||
}
|
||||
|
||||
// ErrFromAddressNotSpecified is thrown when there is no "From" address
|
||||
// specified in the SMTP configuration
|
||||
var ErrFromAddressNotSpecified = errors.New("No From Address specified")
|
||||
|
@ -70,8 +82,16 @@ func GetSMTPs(uid int64) ([]SMTP, error) {
|
|||
err := db.Where("user_id=?", uid).Find(&ss).Error
|
||||
if err != nil {
|
||||
Logger.Println(err)
|
||||
return ss, err
|
||||
}
|
||||
return ss, err
|
||||
for i, _ := range ss {
|
||||
err = db.Where("smtp_id=?", ss[i].Id).Find(&ss[i].Headers).Error
|
||||
if err != nil && err != gorm.ErrRecordNotFound {
|
||||
Logger.Println(err)
|
||||
return ss, err
|
||||
}
|
||||
}
|
||||
return ss, nil
|
||||
}
|
||||
|
||||
// GetSMTP returns the SMTP, if it exists, specified by the given id and user_id.
|
||||
|
@ -81,6 +101,11 @@ func GetSMTP(id int64, uid int64) (SMTP, error) {
|
|||
if err != nil {
|
||||
Logger.Println(err)
|
||||
}
|
||||
err = db.Where("smtp_id=?", s.Id).Find(&s.Headers).Error
|
||||
if err != nil && err != gorm.ErrRecordNotFound {
|
||||
Logger.Println(err)
|
||||
return s, err
|
||||
}
|
||||
return s, err
|
||||
}
|
||||
|
||||
|
@ -90,6 +115,11 @@ func GetSMTPByName(n string, uid int64) (SMTP, error) {
|
|||
err := db.Where("user_id=? and name=?", uid, n).Find(&s).Error
|
||||
if err != nil {
|
||||
Logger.Println(err)
|
||||
return s, err
|
||||
}
|
||||
err = db.Where("smtp_id=?", s.Id).Find(&s.Headers).Error
|
||||
if err != nil && err != gorm.ErrRecordNotFound {
|
||||
Logger.Println(err)
|
||||
}
|
||||
return s, err
|
||||
}
|
||||
|
@ -106,6 +136,15 @@ func PostSMTP(s *SMTP) error {
|
|||
if err != nil {
|
||||
Logger.Println(err)
|
||||
}
|
||||
// Save custom headers
|
||||
for i, _ := range s.Headers {
|
||||
s.Headers[i].SMTPId = s.Id
|
||||
err := db.Save(&s.Headers[i]).Error
|
||||
if err != nil {
|
||||
Logger.Println(err)
|
||||
return err
|
||||
}
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
|
@ -121,12 +160,32 @@ func PutSMTP(s *SMTP) error {
|
|||
if err != nil {
|
||||
Logger.Println(err)
|
||||
}
|
||||
// Delete all custom headers, and replace with new ones
|
||||
err = db.Where("smtp_id=?", s.Id).Delete(&Header{}).Error
|
||||
if err != nil && err != gorm.ErrRecordNotFound {
|
||||
Logger.Println(err)
|
||||
return err
|
||||
}
|
||||
for i, _ := range s.Headers {
|
||||
s.Headers[i].SMTPId = s.Id
|
||||
err := db.Save(&s.Headers[i]).Error
|
||||
if err != nil {
|
||||
Logger.Println(err)
|
||||
return err
|
||||
}
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
// DeleteSMTP deletes an existing SMTP in the database.
|
||||
// An error is returned if a SMTP with the given user id and SMTP id is not found.
|
||||
func DeleteSMTP(id int64, uid int64) error {
|
||||
// Delete all custom headers
|
||||
err = db.Where("smtp_id=?", id).Delete(&Header{}).Error
|
||||
if err != nil {
|
||||
Logger.Println(err)
|
||||
return err
|
||||
}
|
||||
err = db.Where("user_id=?", uid).Delete(SMTP{Id: id}).Error
|
||||
if err != nil {
|
||||
Logger.Println(err)
|
||||
|
|
|
@ -64,6 +64,7 @@ func (t *Template) Validate() error {
|
|||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
tmpl, err = template.New("text_template").Parse(t.Text)
|
||||
if err != nil {
|
||||
return err
|
||||
|
@ -81,6 +82,7 @@ func GetTemplates(uid int64) ([]Template, error) {
|
|||
return ts, err
|
||||
}
|
||||
for i, _ := range ts {
|
||||
// Get Attachments
|
||||
err = db.Where("template_id=?", ts[i].Id).Find(&ts[i].Attachments).Error
|
||||
if err == nil && len(ts[i].Attachments) == 0 {
|
||||
ts[i].Attachments = make([]Attachment, 0)
|
||||
|
@ -101,6 +103,8 @@ func GetTemplate(id int64, uid int64) (Template, error) {
|
|||
Logger.Println(err)
|
||||
return t, err
|
||||
}
|
||||
|
||||
// Get Attachments
|
||||
err = db.Where("template_id=?", t.Id).Find(&t.Attachments).Error
|
||||
if err != nil && err != gorm.ErrRecordNotFound {
|
||||
Logger.Println(err)
|
||||
|
@ -120,6 +124,8 @@ func GetTemplateByName(n string, uid int64) (Template, error) {
|
|||
Logger.Println(err)
|
||||
return t, err
|
||||
}
|
||||
|
||||
// Get Attachments
|
||||
err = db.Where("template_id=?", t.Id).Find(&t.Attachments).Error
|
||||
if err != nil && err != gorm.ErrRecordNotFound {
|
||||
Logger.Println(err)
|
||||
|
@ -142,6 +148,8 @@ func PostTemplate(t *Template) error {
|
|||
Logger.Println(err)
|
||||
return err
|
||||
}
|
||||
|
||||
// Save every attachment
|
||||
for i, _ := range t.Attachments {
|
||||
Logger.Println(t.Attachments[i].Name)
|
||||
t.Attachments[i].TemplateId = t.Id
|
||||
|
@ -177,6 +185,8 @@ func PutTemplate(t *Template) error {
|
|||
return err
|
||||
}
|
||||
}
|
||||
|
||||
// Save final template
|
||||
err = db.Where("id=?", t.Id).Save(t).Error
|
||||
if err != nil {
|
||||
Logger.Println(err)
|
||||
|
@ -188,11 +198,14 @@ func PutTemplate(t *Template) error {
|
|||
// DeleteTemplate deletes an existing template in the database.
|
||||
// An error is returned if a template with the given user id and template id is not found.
|
||||
func DeleteTemplate(id int64, uid int64) error {
|
||||
// Delete attachments
|
||||
err := db.Where("template_id=?", id).Delete(&Attachment{}).Error
|
||||
if err != nil {
|
||||
Logger.Println(err)
|
||||
return err
|
||||
}
|
||||
|
||||
// Finally, delete the template itself
|
||||
err = db.Where("user_id=?", uid).Delete(Template{Id: id}).Error
|
||||
if err != nil {
|
||||
Logger.Println(err)
|
||||
|
|
2
static/js/dist/app/sending_profiles.min.js
vendored
2
static/js/dist/app/sending_profiles.min.js
vendored
File diff suppressed because one or more lines are too long
|
@ -2,6 +2,13 @@ var profiles = []
|
|||
|
||||
// Attempts to send a test email by POSTing to /campaigns/
|
||||
function sendTestEmail() {
|
||||
var headers = [];
|
||||
$.each($("#headersTable").DataTable().rows().data(), function(i, header) {
|
||||
headers.push({
|
||||
key: unescapeHtml(header[0]),
|
||||
value: unescapeHtml(header[1]),
|
||||
})
|
||||
})
|
||||
var test_email_request = {
|
||||
template: {},
|
||||
first_name: $("input[name=to_first_name]").val(),
|
||||
|
@ -14,7 +21,8 @@ function sendTestEmail() {
|
|||
host: $("#host").val(),
|
||||
username: $("#username").val(),
|
||||
password: $("#password").val(),
|
||||
ignore_cert_errors: $("#ignore_cert_errors").prop("checked")
|
||||
ignore_cert_errors: $("#ignore_cert_errors").prop("checked"),
|
||||
headers: headers,
|
||||
}
|
||||
}
|
||||
btnHtml = $("#sendTestModalSubmit").html()
|
||||
|
@ -35,7 +43,15 @@ function sendTestEmail() {
|
|||
|
||||
// Save attempts to POST to /smtp/
|
||||
function save(idx) {
|
||||
var profile = {}
|
||||
var profile = {
|
||||
headers: []
|
||||
}
|
||||
$.each($("#headersTable").DataTable().rows().data(), function(i, header) {
|
||||
profile.headers.push({
|
||||
key: unescapeHtml(header[0]),
|
||||
value: unescapeHtml(header[1]),
|
||||
})
|
||||
})
|
||||
profile.name = $("#name").val()
|
||||
profile.interface_type = $("#interface_type").val()
|
||||
profile.from_address = $("#from").val()
|
||||
|
@ -77,6 +93,7 @@ function dismiss() {
|
|||
$("#username").val("")
|
||||
$("#password").val("")
|
||||
$("#ignore_cert_errors").prop("checked", true)
|
||||
$("#headersTable").dataTable().DataTable().clear().draw()
|
||||
$("#modal").modal('hide')
|
||||
}
|
||||
|
||||
|
@ -91,6 +108,14 @@ function deleteProfile(idx) {
|
|||
}
|
||||
|
||||
function edit(idx) {
|
||||
headers = $("#headersTable").dataTable({
|
||||
destroy: true, // Destroy any other instantiated table - http://datatables.net/manual/tech-notes/3#destroy
|
||||
columnDefs: [{
|
||||
orderable: false,
|
||||
targets: "no-sort"
|
||||
}]
|
||||
})
|
||||
|
||||
$("#modalSubmit").unbind('click').click(function() {
|
||||
save(idx)
|
||||
})
|
||||
|
@ -104,6 +129,9 @@ function edit(idx) {
|
|||
$("#username").val(profile.username)
|
||||
$("#password").val(profile.password)
|
||||
$("#ignore_cert_errors").prop("checked", profile.ignore_cert_errors)
|
||||
$.each(profile.headers, function(i, record) {
|
||||
addCustomHeader(record.key, record.value)
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -167,6 +195,34 @@ function load() {
|
|||
})
|
||||
}
|
||||
|
||||
function addCustomHeader(header, value) {
|
||||
// Create new data row.
|
||||
var newRow = [
|
||||
escapeHtml(header),
|
||||
escapeHtml(value),
|
||||
'<span style="cursor:pointer;"><i class="fa fa-trash-o"></i></span>'
|
||||
];
|
||||
|
||||
// Check table to see if header already exists.
|
||||
var headersTable = headers.DataTable();
|
||||
var existingRowIndex = headersTable
|
||||
.column(0) // Email column has index of 2
|
||||
.data()
|
||||
.indexOf(escapeHtml(header));
|
||||
|
||||
// Update or add new row as necessary.
|
||||
if (existingRowIndex >= 0) {
|
||||
headersTable
|
||||
.row(existingRowIndex, {
|
||||
order: "index"
|
||||
})
|
||||
.data(newRow);
|
||||
} else {
|
||||
headersTable.row.add(newRow);
|
||||
}
|
||||
headersTable.draw();
|
||||
}
|
||||
|
||||
$(document).ready(function() {
|
||||
// Setup multiple modals
|
||||
// Code based on http://miles-by-motorcycle.com/static/bootstrap-modal/index.html
|
||||
|
@ -208,5 +264,26 @@ $(document).ready(function() {
|
|||
$('#modal').on('hidden.bs.modal', function(event) {
|
||||
dismiss()
|
||||
});
|
||||
// Code to deal with custom email headers
|
||||
$("#headersForm").on('submit', function() {
|
||||
headerKey = $("#headerKey").val();
|
||||
headerValue = $("#headerValue").val();
|
||||
|
||||
if (headerKey == "" || headerValue == "") {
|
||||
return false;
|
||||
}
|
||||
addCustomHeader(headerKey, headerValue);
|
||||
// Reset user input.
|
||||
$("#headersForm>div>input").val('');
|
||||
$("#headerKey").focus();
|
||||
return false;
|
||||
});
|
||||
// Handle Deletion
|
||||
$("#headersTable").on("click", "span>i.fa-trash-o", function() {
|
||||
headers.DataTable()
|
||||
.row($(this).parents('tr'))
|
||||
.remove()
|
||||
.draw();
|
||||
});
|
||||
load()
|
||||
})
|
||||
|
|
|
@ -42,6 +42,7 @@ function save(idx) {
|
|||
type: target[4],
|
||||
})
|
||||
})
|
||||
|
||||
if (idx != -1) {
|
||||
template.id = templates[idx].id
|
||||
api.templateId.put(template)
|
||||
|
@ -169,6 +170,7 @@ function edit(idx) {
|
|||
} else {
|
||||
$("#use_tracker_checkbox").prop("checked", false)
|
||||
}
|
||||
|
||||
}
|
||||
// Handle Deletion
|
||||
$("#attachmentsTable").unbind('click').on("click", "span>i.fa-trash-o", function() {
|
||||
|
@ -346,4 +348,5 @@ $(document).ready(function() {
|
|||
dismiss()
|
||||
});
|
||||
load()
|
||||
|
||||
})
|
||||
|
|
|
@ -48,7 +48,7 @@
|
|||
<thead>
|
||||
<tr>
|
||||
<th class="col-md-4">Name</th>
|
||||
<th>Interface Type</th>
|
||||
<th>Interface Type</th>
|
||||
<th>Last Modified Date</th>
|
||||
<th class="col-md-2 no-sort"></th>
|
||||
</tr>
|
||||
|
@ -60,83 +60,105 @@
|
|||
</div>
|
||||
<!-- Modal -->
|
||||
<div class="modal fade" id="modal" tabindex="-1" role="dialog" aria-labelledby="modalLabel">
|
||||
<div class="modal-dialog" role="document">
|
||||
<div class="modal-content">
|
||||
<!-- New Template Modal -->
|
||||
<div class="modal-header">
|
||||
<button type="button" class="close" data-dismiss="modal" aria-label="Close" onclick="dismiss()"><span aria-hidden="true">×</span></button>
|
||||
<h4 class="modal-title" id="profileModalLabel">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>
|
||||
<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"/>
|
||||
<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>
|
||||
</div>
|
||||
<button type="button" data-toggle="modal" data-target="#sendTestEmailModal" class="btn btn-primary"><i class="fa fa-envelope"></i> 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>
|
||||
<div class="modal-dialog" role="document">
|
||||
<div class="modal-content">
|
||||
<!-- New Template Modal -->
|
||||
<div class="modal-header">
|
||||
<button type="button" class="close" data-dismiss="modal" aria-label="Close" onclick="dismiss()"><span aria-hidden="true">×</span></button>
|
||||
<h4 class="modal-title" id="profileModalLabel">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>
|
||||
<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"/>
|
||||
<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>
|
||||
</div>
|
||||
<label class="control-label" for="headersForm">Email Headers:</label>
|
||||
<form id="headersForm">
|
||||
<div class="col-md-4">
|
||||
<input type="text" class="form-control" name="headerKey" id="headerKey" placeholder="X-Custom-Header">
|
||||
</div>
|
||||
<div class="col-md-4">
|
||||
<input type="text" class="form-control" name="headerValue" id="headerValue" placeholder="{{"{{"}}.URL{{"}}"}}-gophish">
|
||||
</div>
|
||||
<div class="col-md-2">
|
||||
<button class="btn btn-danger btn-headers" type="submit"><i class="fa fa-plus"></i> Add Custom Header</button>
|
||||
</div>
|
||||
</form>
|
||||
<br />
|
||||
<br />
|
||||
<table id="headersTable" class="table table-hover table-striped table-condensed">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Header</th>
|
||||
<th>Value</th>
|
||||
<th class="no-sort"></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
</tbody>
|
||||
</table>
|
||||
<button type="button" data-toggle="modal" data-target="#sendTestEmailModal" class="btn btn-primary"><i class="fa fa-envelope"></i> Send Test Email</button>
|
||||
</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>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Send Test Email Modal -->
|
||||
<div class="modal" id="sendTestEmailModal" tabindex="-1" role="dialog" aria-labelledby="modalLabel">
|
||||
<div class="modal-dialog" role="document">
|
||||
<div class="modal-content">
|
||||
<!-- New Email Modal -->
|
||||
<div class="modal-header">
|
||||
<button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">×</span></button>
|
||||
<h4 class="modal-title" id="sendTestEmailModalTitle">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>
|
||||
</div>
|
||||
<br>
|
||||
<div class="col-sm-2">
|
||||
<input type="text" class="form-control" placeholder="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">
|
||||
</div>
|
||||
<div class="col-sm-4">
|
||||
<input type="email" class="form-control" placeholder="Email" name="to_email" required>
|
||||
</div>
|
||||
<div class="col-sm-4">
|
||||
<input type="text" class="form-control" placeholder="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>
|
||||
</div>
|
||||
<div class="modal-dialog" role="document">
|
||||
<div class="modal-content">
|
||||
<!-- New Email Modal -->
|
||||
<div class="modal-header">
|
||||
<button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">×</span></button>
|
||||
<h4 class="modal-title" id="sendTestEmailModalTitle">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>
|
||||
</div>
|
||||
<br>
|
||||
<div class="col-sm-2">
|
||||
<input type="text" class="form-control" placeholder="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">
|
||||
</div>
|
||||
<div class="col-sm-4">
|
||||
<input type="email" class="form-control" placeholder="Email" name="to_email" required>
|
||||
</div>
|
||||
<div class="col-sm-4">
|
||||
<input type="text" class="form-control" placeholder="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>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{{end}}
|
||||
{{define "scripts"}}
|
||||
<script src="/js/ckeditor/ckeditor.js"></script>
|
||||
<script src="/js/ckeditor/adapters/jquery.js"></script>
|
||||
<script src="/js/dist/app/sending_profiles.min.js"></script>
|
||||
{{end}}
|
||||
|
|
|
@ -61,96 +61,97 @@
|
|||
</div>
|
||||
<!-- Modal -->
|
||||
<div class="modal fade" id="modal" tabindex="-1" role="dialog" aria-labelledby="modalLabel">
|
||||
<div class="modal-dialog" role="document">
|
||||
<div class="modal-content">
|
||||
<!-- New Template Modal -->
|
||||
<div class="modal-header">
|
||||
<button type="button" class="close" data-dismiss="modal" aria-label="Close" onclick="dismiss()"><span aria-hidden="true">×</span></button>
|
||||
<h4 class="modal-title" id="templateModalLabel">New Template</h4>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<div class="row" id="modal.flashes"></div>
|
||||
<label class="control-label" for="name">Name:</label>
|
||||
<div class="form-group">
|
||||
<input type="text" class="form-control" ng-model="template.name" placeholder="Template name" id="name" autofocus/>
|
||||
<div class="modal-dialog" role="document">
|
||||
<div class="modal-content">
|
||||
<!-- New Template Modal -->
|
||||
<div class="modal-header">
|
||||
<button type="button" class="close" data-dismiss="modal" aria-label="Close" onclick="dismiss()"><span aria-hidden="true">×</span></button>
|
||||
<h4 class="modal-title" id="templateModalLabel">New Template</h4>
|
||||
</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>
|
||||
</div>
|
||||
<label class="control-label" for="subject">Subject:</label>
|
||||
<div class="form-group">
|
||||
<input type="text" class="form-control" placeholder="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>
|
||||
</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>
|
||||
<div class="modal-body">
|
||||
<div class="row" id="modal.flashes"></div>
|
||||
<label class="control-label" for="name">Name:</label>
|
||||
<div class="form-group">
|
||||
<input type="text" class="form-control" ng-model="template.name" placeholder="Template name" id="name" autofocus/>
|
||||
</div>
|
||||
<div role="tabpanel" class="tab-pane" id="html">
|
||||
<textarea id="html_editor"></textarea>
|
||||
<div class="form-group">
|
||||
<button class="btn btn-danger" data-toggle="modal" data-target="#importEmailModal"><i class="fa fa-envelope"></i> Import Email</button>
|
||||
</div>
|
||||
<label class="control-label" for="subject">Subject:</label>
|
||||
<div class="form-group">
|
||||
<input type="text" class="form-control" placeholder="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>
|
||||
</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>
|
||||
</div>
|
||||
<div role="tabpanel" class="tab-pane" id="html">
|
||||
<textarea id="html_editor"></textarea>
|
||||
</div>
|
||||
</div>
|
||||
<div class="checkbox checkbox-primary">
|
||||
<input id="use_tracker_checkbox" type="checkbox" checked>
|
||||
<label for="use_tracker_checkbox">Add Tracking Image</label>
|
||||
</div>
|
||||
<span class="btn btn-danger btn-file"><i class="fa fa-plus"></i> Add Files
|
||||
<input id="attachmentUpload" type="file" onchange="attach(this.files)" multiple>
|
||||
</span>
|
||||
<br />
|
||||
<br />
|
||||
<table id="attachmentsTable" class="table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th class="col-md-1 no-sort"></th>
|
||||
<th class="col-md-10">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>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
</tbody>
|
||||
</table>
|
||||
<hr>
|
||||
</div>
|
||||
<div class="checkbox checkbox-primary">
|
||||
<input id="use_tracker_checkbox" type="checkbox" checked>
|
||||
<label for="use_tracker_checkbox">Add Tracking Image</label>
|
||||
<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>
|
||||
</div>
|
||||
<span class="btn btn-danger btn-file"><i class="fa fa-plus"></i> Add Files
|
||||
<input id="attachmentUpload" type="file" onchange="attach(this.files)" multiple>
|
||||
</span>
|
||||
<br />
|
||||
<br />
|
||||
<table id="attachmentsTable" class="table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th class="col-md-1 no-sort"></th>
|
||||
<th class="col-md-10">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>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
</tbody>
|
||||
</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>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Modal -->
|
||||
<div class="modal fade" id="importEmailModal" tabindex="-1" role="dialog" aria-labelledby="modalLabel">
|
||||
<div class="modal-dialog" role="document">
|
||||
<div class="modal-content">
|
||||
<!-- New Email Modal -->
|
||||
<div class="modal-header">
|
||||
<button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">×</span></button>
|
||||
<h4 class="modal-title" id="importEmailModalLabel">Import Email</h4>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<div class="row" id="modal.flashes"></div>
|
||||
<label class="control-label" for="email">Email Content:</label>
|
||||
<div class="form-group">
|
||||
<div class="modal-dialog" role="document">
|
||||
<div class="modal-content">
|
||||
<!-- New Email Modal -->
|
||||
<div class="modal-header">
|
||||
<button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">×</span></button>
|
||||
<h4 class="modal-title" id="importEmailModalLabel">Import Email</h4>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<div class="row" id="modal.flashes"></div>
|
||||
<label class="control-label" for="email">Email Content:</label>
|
||||
<div class="form-group">
|
||||
<textarea rows="10" id="email_content" class="gophish-editor form-control" placeholder="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>
|
||||
</div>
|
||||
</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>
|
||||
<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>
|
||||
</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>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{{end}}
|
||||
{{define "scripts"}}
|
||||
|
|
|
@ -127,7 +127,36 @@ func processCampaign(c *models.Campaign) {
|
|||
"<img alt='' style='display: none' src='" + c.URL + "/track?rid=" + t.RId + "'/>",
|
||||
fn,
|
||||
}
|
||||
// Parse the templates
|
||||
|
||||
// Parse the customHeader templates
|
||||
for _, header := range c.SMTP.Headers {
|
||||
parsedHeader := struct {
|
||||
Key bytes.Buffer
|
||||
Value bytes.Buffer
|
||||
}{}
|
||||
keytmpl, err := template.New("text_template").Parse(header.Key)
|
||||
if err != nil {
|
||||
Logger.Println(err)
|
||||
}
|
||||
err = keytmpl.Execute(&parsedHeader.Key, td)
|
||||
if err != nil {
|
||||
Logger.Println(err)
|
||||
}
|
||||
|
||||
valtmpl, err := template.New("text_template").Parse(header.Value)
|
||||
if err != nil {
|
||||
Logger.Println(err)
|
||||
}
|
||||
err = valtmpl.Execute(&parsedHeader.Value, td)
|
||||
if err != nil {
|
||||
Logger.Println(err)
|
||||
}
|
||||
|
||||
// Add our header immediately
|
||||
e.SetHeader(parsedHeader.Key.String(), parsedHeader.Value.String())
|
||||
}
|
||||
|
||||
// Parse remaining templates
|
||||
var subjBuff bytes.Buffer
|
||||
tmpl, err := template.New("text_template").Parse(c.Template.Subject)
|
||||
if err != nil {
|
||||
|
@ -243,10 +272,37 @@ func SendTestEmail(s *models.SendTestEmailRequest) error {
|
|||
Logger.Println(err)
|
||||
return err
|
||||
}
|
||||
Logger.Println("Creating email using template")
|
||||
e := gomail.NewMessage()
|
||||
// Parse the customHeader templates
|
||||
for _, header := range s.SMTP.Headers {
|
||||
parsedHeader := struct {
|
||||
Key bytes.Buffer
|
||||
Value bytes.Buffer
|
||||
}{}
|
||||
keytmpl, err := template.New("text_template").Parse(header.Key)
|
||||
if err != nil {
|
||||
Logger.Println(err)
|
||||
}
|
||||
err = keytmpl.Execute(&parsedHeader.Key, s)
|
||||
if err != nil {
|
||||
Logger.Println(err)
|
||||
}
|
||||
|
||||
valtmpl, err := template.New("text_template").Parse(header.Value)
|
||||
if err != nil {
|
||||
Logger.Println(err)
|
||||
}
|
||||
err = valtmpl.Execute(&parsedHeader.Value, s)
|
||||
if err != nil {
|
||||
Logger.Println(err)
|
||||
}
|
||||
|
||||
// Add our header immediately
|
||||
e.SetHeader(parsedHeader.Key.String(), parsedHeader.Value.String())
|
||||
}
|
||||
e.SetHeader("From", s.SMTP.FromAddress)
|
||||
e.SetHeader("To", s.Email)
|
||||
Logger.Println("Creating email using template")
|
||||
// Parse the templates
|
||||
var subjBuff bytes.Buffer
|
||||
tmpl, err := template.New("text_template").Parse(s.Template.Subject)
|
||||
|
|
Loading…
Reference in a new issue