mirror of https://github.com/gophish/gophish
Improved group CSV parsing. Added ability to download CSV template from the group modal.
parent
ebb6cd61b2
commit
35a8f13990
File diff suppressed because one or more lines are too long
|
@ -415,7 +415,6 @@ p {
|
||||||
margin-top: -30px;
|
margin-top: -30px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Handle the navbar collapse at < 1300px */
|
/* Handle the navbar collapse at < 1300px */
|
||||||
|
|
||||||
@media (min-width: 768px) and (max-width: 1300px) {
|
@media (min-width: 768px) and (max-width: 1300px) {
|
||||||
|
@ -434,7 +433,6 @@ p {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Table Styling */
|
/* Table Styling */
|
||||||
|
|
||||||
.modal-content table {
|
.modal-content table {
|
||||||
|
@ -452,7 +450,6 @@ p {
|
||||||
font-size: 15px;
|
font-size: 15px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Sort Icons */
|
/* Sort Icons */
|
||||||
|
|
||||||
table.dataTable thead .sorting:after,
|
table.dataTable thead .sorting:after,
|
||||||
|
@ -672,3 +669,8 @@ table.dataTable {
|
||||||
#resultsMapContainer {
|
#resultsMapContainer {
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#csv-template {
|
||||||
|
margin-left: 15px;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
|
@ -1 +1 @@
|
||||||
function save(a){var e=[];$.each($("#targetsTable").DataTable().rows().data(),function(a,s){e.push({first_name:unescapeHtml(s[0]),last_name:unescapeHtml(s[1]),email:unescapeHtml(s[2]),position:unescapeHtml(s[3])})});var s={name:$("#name").val(),targets:e};-1!=a?(s.id=a,api.groupId.put(s).success(function(a){successFlash("Group updated successfully!"),load(),dismiss(),$("#modal").modal("hide")}).error(function(a){modalError(a.responseJSON.message)})):api.groups.post(s).success(function(a){successFlash("Group added successfully!"),load(),dismiss(),$("#modal").modal("hide")}).error(function(a){modalError(a.responseJSON.message)})}function dismiss(){$("#targetsTable").dataTable().DataTable().clear().draw(),$("#name").val(""),$("#modal\\.flashes").empty()}function edit(a){if(targets=$("#targetsTable").dataTable({destroy:!0,columnDefs:[{orderable:!1,targets:"no-sort"}]}),$("#modalSubmit").unbind("click").click(function(){save(a)}),-1==a);else api.groupId.get(a).success(function(a){$("#name").val(a.name),$.each(a.targets,function(a,e){targets.DataTable().row.add([escapeHtml(e.first_name),escapeHtml(e.last_name),escapeHtml(e.email),escapeHtml(e.position),'<span style="cursor:pointer;"><i class="fa fa-trash-o"></i></span>']).draw()})}).error(function(){errorFlash("Error fetching group")});$("#csvupload").fileupload({url:"/api/import/group?api_key="+user.api_key,dataType:"json",add:function(a,e){$("#modal\\.flashes").empty();var s=/(csv|txt)$/i,t=e.originalFiles[0].name;if(t&&!s.test(t.split(".").pop()))return modalError("Unsupported file extension (use .csv or .txt)"),!1;e.submit()},done:function(a,e){$.each(e.result,function(a,e){addTarget(e.first_name,e.last_name,e.email,e.position)}),targets.DataTable().draw()}})}function deleteGroup(a){var e=groups.find(function(e){return e.id===a});if(!e)return void console.log("wat");confirm("Delete "+e.name+"?")&&api.groupId.delete(a).success(function(a){successFlash(a.message),load()})}function addTarget(a,e,s,t){var o=escapeHtml(s).toLowerCase(),r=[escapeHtml(a),escapeHtml(e),o,escapeHtml(t),'<span style="cursor:pointer;"><i class="fa fa-trash-o"></i></span>'],n=targets.DataTable(),i=n.column(2,{order:"index"}).data().indexOf(o);i>=0?n.row(i,{order:"index"}).data(r):n.row.add(r)}function load(){$("#groupTable").hide(),$("#emptyMessage").hide(),$("#loading").show(),api.groups.summary().success(function(a){if($("#loading").hide(),a.total>0){groups=a.groups,$("#emptyMessage").hide(),$("#groupTable").show();var e=$("#groupTable").DataTable({destroy:!0,columnDefs:[{orderable:!1,targets:"no-sort"}]});e.clear(),$.each(groups,function(a,s){e.row.add([escapeHtml(s.name),escapeHtml(s.num_targets),moment(s.modified_date).format("MMMM Do YYYY, h:mm:ss a"),"<div class='pull-right'><button class='btn btn-primary' data-toggle='modal' data-target='#modal' onclick='edit("+s.id+")'> <i class='fa fa-pencil'></i> </button> <button class='btn btn-danger' onclick='deleteGroup("+s.id+")'> <i class='fa fa-trash-o'></i> </button></div>"]).draw()})}else $("#emptyMessage").show()}).error(function(){errorFlash("Error fetching groups")})}var groups=[];$(document).ready(function(){load(),$("#targetForm").submit(function(){return addTarget($("#firstName").val(),$("#lastName").val(),$("#email").val(),$("#position").val()),targets.DataTable().draw(),$("#targetForm>div>input").val(""),$("#firstName").focus(),!1}),$("#targetsTable").on("click","span>i.fa-trash-o",function(){targets.DataTable().row($(this).parents("tr")).remove().draw()}),$("#modal").on("hide.bs.modal",function(){dismiss()})});
|
function save(a){var e=[];$.each($("#targetsTable").DataTable().rows().data(),function(a,t){e.push({first_name:unescapeHtml(t[0]),last_name:unescapeHtml(t[1]),email:unescapeHtml(t[2]),position:unescapeHtml(t[3])})});var t={name:$("#name").val(),targets:e};-1!=a?(t.id=a,api.groupId.put(t).success(function(a){successFlash("Group updated successfully!"),load(),dismiss(),$("#modal").modal("hide")}).error(function(a){modalError(a.responseJSON.message)})):api.groups.post(t).success(function(a){successFlash("Group added successfully!"),load(),dismiss(),$("#modal").modal("hide")}).error(function(a){modalError(a.responseJSON.message)})}function dismiss(){$("#targetsTable").dataTable().DataTable().clear().draw(),$("#name").val(""),$("#modal\\.flashes").empty()}function edit(a){if(targets=$("#targetsTable").dataTable({destroy:!0,columnDefs:[{orderable:!1,targets:"no-sort"}]}),$("#modalSubmit").unbind("click").click(function(){save(a)}),-1==a);else api.groupId.get(a).success(function(a){$("#name").val(a.name),$.each(a.targets,function(a,e){targets.DataTable().row.add([escapeHtml(e.first_name),escapeHtml(e.last_name),escapeHtml(e.email),escapeHtml(e.position),'<span style="cursor:pointer;"><i class="fa fa-trash-o"></i></span>']).draw()})}).error(function(){errorFlash("Error fetching group")});$("#csvupload").fileupload({url:"/api/import/group?api_key="+user.api_key,dataType:"json",add:function(a,e){$("#modal\\.flashes").empty();var t=/(csv|txt)$/i,s=e.originalFiles[0].name;if(s&&!t.test(s.split(".").pop()))return modalError("Unsupported file extension (use .csv or .txt)"),!1;e.submit()},done:function(a,e){$.each(e.result,function(a,e){addTarget(e.first_name,e.last_name,e.email,e.position)}),targets.DataTable().draw()}})}function deleteGroup(a){var e=groups.find(function(e){return e.id===a});if(!e)return void console.log("wat");confirm("Delete "+e.name+"?")&&api.groupId.delete(a).success(function(a){successFlash(a.message),load()})}function addTarget(a,e,t,s){var o=escapeHtml(t).toLowerCase(),r=[escapeHtml(a),escapeHtml(e),o,escapeHtml(s),'<span style="cursor:pointer;"><i class="fa fa-trash-o"></i></span>'],n=targets.DataTable(),i=n.column(2,{order:"index"}).data().indexOf(o);i>=0?n.row(i,{order:"index"}).data(r):n.row.add(r)}function load(){$("#groupTable").hide(),$("#emptyMessage").hide(),$("#loading").show(),api.groups.summary().success(function(a){if($("#loading").hide(),a.total>0){groups=a.groups,$("#emptyMessage").hide(),$("#groupTable").show();var e=$("#groupTable").DataTable({destroy:!0,columnDefs:[{orderable:!1,targets:"no-sort"}]});e.clear(),$.each(groups,function(a,t){e.row.add([escapeHtml(t.name),escapeHtml(t.num_targets),moment(t.modified_date).format("MMMM Do YYYY, h:mm:ss a"),"<div class='pull-right'><button class='btn btn-primary' data-toggle='modal' data-target='#modal' onclick='edit("+t.id+")'> <i class='fa fa-pencil'></i> </button> <button class='btn btn-danger' onclick='deleteGroup("+t.id+")'> <i class='fa fa-trash-o'></i> </button></div>"]).draw()})}else $("#emptyMessage").show()}).error(function(){errorFlash("Error fetching groups")})}var groups=[],downloadCSVTemplate=function(){var a=[{"First Name":"Example","Last Name":"User",Email:"foobar@example.com",Position:"Systems Administrator"}],e=Papa.unparse(a,{}),t=new Blob([e],{type:"text/csv;charset=utf-8;"});if(navigator.msSaveBlob)navigator.msSaveBlob(t,"group_template.csv");else{var s=window.URL.createObjectURL(t),o=document.createElement("a");o.href=s,o.setAttribute("download","group_template.csv"),document.body.appendChild(o),o.click(),document.body.removeChild(o)}};$(document).ready(function(){load(),$("#targetForm").submit(function(){return addTarget($("#firstName").val(),$("#lastName").val(),$("#email").val(),$("#position").val()),targets.DataTable().draw(),$("#targetForm>div>input").val(""),$("#firstName").focus(),!1}),$("#targetsTable").on("click","span>i.fa-trash-o",function(){targets.DataTable().row($(this).parents("tr")).remove().draw()}),$("#modal").on("hide.bs.modal",function(){dismiss()}),$("#csv-template").click(downloadCSVTemplate)});
|
|
@ -112,6 +112,31 @@ function edit(id) {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var downloadCSVTemplate = function () {
|
||||||
|
var csvScope = [{
|
||||||
|
'First Name': 'Example',
|
||||||
|
'Last Name': 'User',
|
||||||
|
'Email': 'foobar@example.com',
|
||||||
|
'Position': 'Systems Administrator'
|
||||||
|
}]
|
||||||
|
var filename = 'group_template.csv'
|
||||||
|
var csvString = Papa.unparse(csvScope, {})
|
||||||
|
var csvData = new Blob([csvString], {
|
||||||
|
type: 'text/csv;charset=utf-8;'
|
||||||
|
});
|
||||||
|
if (navigator.msSaveBlob) {
|
||||||
|
navigator.msSaveBlob(csvData, filename);
|
||||||
|
} else {
|
||||||
|
var csvURL = window.URL.createObjectURL(csvData);
|
||||||
|
var dlLink = document.createElement('a');
|
||||||
|
dlLink.href = csvURL;
|
||||||
|
dlLink.setAttribute('download', filename)
|
||||||
|
document.body.appendChild(dlLink)
|
||||||
|
dlLink.click();
|
||||||
|
document.body.removeChild(dlLink)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function deleteGroup(id) {
|
function deleteGroup(id) {
|
||||||
var group = groups.find(function (x) {
|
var group = groups.find(function (x) {
|
||||||
return x.id === id
|
return x.id === id
|
||||||
|
@ -228,4 +253,5 @@ $(document).ready(function () {
|
||||||
$("#modal").on("hide.bs.modal", function () {
|
$("#modal").on("hide.bs.modal", function () {
|
||||||
dismiss();
|
dismiss();
|
||||||
});
|
});
|
||||||
|
$("#csv-template").click(downloadCSVTemplate)
|
||||||
});
|
});
|
|
@ -93,6 +93,8 @@
|
||||||
<i class="fa fa-plus"></i> Bulk Import Users
|
<i class="fa fa-plus"></i> Bulk Import Users
|
||||||
<input type="file" id="csvupload" multiple>
|
<input type="file" id="csvupload" multiple>
|
||||||
</span>
|
</span>
|
||||||
|
<span id="csv-template" class="text-muted small">
|
||||||
|
<i class="fa fa-file-excel-o"></i> Download CSV Template</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<form id="targetForm">
|
<form id="targetForm">
|
||||||
|
|
16
util/util.go
16
util/util.go
|
@ -15,6 +15,7 @@ import (
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/mail"
|
"net/mail"
|
||||||
"os"
|
"os"
|
||||||
|
"regexp"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
log "github.com/gophish/gophish/logger"
|
log "github.com/gophish/gophish/logger"
|
||||||
|
@ -22,6 +23,13 @@ import (
|
||||||
"github.com/jordan-wright/email"
|
"github.com/jordan-wright/email"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
firstNameRegex = regexp.MustCompile(`(?i)first[\s_-]*name`)
|
||||||
|
lastNameRegex = regexp.MustCompile(`(?i)last[\s_-]*name`)
|
||||||
|
emailRegex = regexp.MustCompile(`(?i)email`)
|
||||||
|
positionRegex = regexp.MustCompile(`(?i)position`)
|
||||||
|
)
|
||||||
|
|
||||||
// ParseMail takes in an HTTP Request and returns an Email object
|
// ParseMail takes in an HTTP Request and returns an Email object
|
||||||
// TODO: This function will likely be changed to take in a []byte
|
// TODO: This function will likely be changed to take in a []byte
|
||||||
func ParseMail(r *http.Request) (email.Email, error) {
|
func ParseMail(r *http.Request) (email.Email, error) {
|
||||||
|
@ -68,13 +76,13 @@ func ParseCSV(r *http.Request) ([]models.Target, error) {
|
||||||
ps := ""
|
ps := ""
|
||||||
for i, v := range record {
|
for i, v := range record {
|
||||||
switch {
|
switch {
|
||||||
case v == "First Name":
|
case firstNameRegex.MatchString(v):
|
||||||
fi = i
|
fi = i
|
||||||
case v == "Last Name":
|
case lastNameRegex.MatchString(v):
|
||||||
li = i
|
li = i
|
||||||
case v == "Email":
|
case emailRegex.MatchString(v):
|
||||||
ei = i
|
ei = i
|
||||||
case v == "Position":
|
case positionRegex.MatchString(v):
|
||||||
pi = i
|
pi = i
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue