mirror of https://github.com/gophish/gophish
Added util package for handling misc. tasks
Added basic (*not finished*) functionality for handling bulk user insertpull/24/head
parent
01901c9008
commit
efec86ae56
|
@ -13,6 +13,7 @@ import (
|
|||
"github.com/jinzhu/gorm"
|
||||
"github.com/jordan-wright/gophish/auth"
|
||||
"github.com/jordan-wright/gophish/models"
|
||||
"github.com/jordan-wright/gophish/util"
|
||||
"github.com/jordan-wright/gophish/worker"
|
||||
)
|
||||
|
||||
|
@ -245,6 +246,15 @@ func API_Templates_Id(w http.ResponseWriter, r *http.Request) {
|
|||
}
|
||||
}
|
||||
|
||||
func API_Import_Group(w http.ResponseWriter, r *http.Request) {
|
||||
Logger.Println("Parsing CSV....")
|
||||
ts, err := util.ParseCSV(r)
|
||||
if checkError(err, w, "Error deleting template", http.StatusInternalServerError) {
|
||||
return
|
||||
}
|
||||
JSONResponse(w, ts, http.StatusOK)
|
||||
}
|
||||
|
||||
// JSONResponse attempts to set the status code, c, and marshal the given interface, d, into a response that
|
||||
// is written to the given ResponseWriter.
|
||||
func JSONResponse(w http.ResponseWriter, d interface{}, c int) {
|
||||
|
|
|
@ -38,6 +38,7 @@ func CreateRouter() *nosurf.CSRFHandler {
|
|||
api.HandleFunc("/groups/{id:[0-9]+}", Use(API_Groups_Id, mid.RequireAPIKey))
|
||||
api.HandleFunc("/templates/", Use(API_Templates, mid.RequireAPIKey))
|
||||
api.HandleFunc("/templates/{id:[0-9]+}", Use(API_Templates_Id, mid.RequireAPIKey))
|
||||
api.HandleFunc("/import/group", API_Import_Group)
|
||||
|
||||
// Setup static file serving
|
||||
router.PathPrefix("/").Handler(http.FileServer(http.Dir("./static/")))
|
||||
|
@ -48,6 +49,7 @@ func CreateRouter() *nosurf.CSRFHandler {
|
|||
csrfHandler.ExemptGlob("/api/campaigns/*")
|
||||
csrfHandler.ExemptGlob("/api/groups/*")
|
||||
csrfHandler.ExemptGlob("/api/templates/*")
|
||||
csrfHandler.ExemptGlob("/api/import/*")
|
||||
csrfHandler.ExemptGlob("/static/*")
|
||||
return csrfHandler
|
||||
}
|
||||
|
|
|
@ -21,8 +21,10 @@ type GroupTarget struct {
|
|||
}
|
||||
|
||||
type Target struct {
|
||||
Id int64 `json:"-"`
|
||||
Email string `json:"email"`
|
||||
Id int64 `json:"-"`
|
||||
FirstName string `json:"first_name"`
|
||||
LastName string `json:"last_name"`
|
||||
Email string `json:"email"`
|
||||
}
|
||||
|
||||
// GetGroups returns the groups owned by the given user.
|
||||
|
|
File diff suppressed because one or more lines are too long
|
@ -0,0 +1,2 @@
|
|||
/*! 1.4.0 */
|
||||
!function(){var a=angular.module("angularFileUpload",[]);a.service("$upload",["$http","$timeout",function(a,b){function c(c){c.method=c.method||"POST",c.headers=c.headers||{},c.transformRequest=c.transformRequest||function(b,c){return window.ArrayBuffer&&b instanceof window.ArrayBuffer?b:a.defaults.transformRequest[0](b,c)},window.XMLHttpRequest.__isShim&&(c.headers.__setXHR_=function(){return function(a){a&&(c.__XHR=a,c.xhrFn&&c.xhrFn(a),a.upload.addEventListener("progress",function(a){c.progress&&b(function(){c.progress&&c.progress(a)})},!1),a.upload.addEventListener("load",function(a){a.lengthComputable&&c.progress&&c.progress(a)},!1))}});var d=a(c);return d.progress=function(a){return c.progress=a,d},d.abort=function(){return c.__XHR&&b(function(){c.__XHR.abort()}),d},d.xhr=function(a){return c.xhrFn=a,d},d.then=function(a,b){return function(d,e,f){c.progress=f||c.progress;var g=b.apply(a,[d,e,f]);return g.abort=a.abort,g.progress=a.progress,g.xhr=a.xhr,g.then=a.then,g}}(d,d.then),d}this.upload=function(b){b.headers=b.headers||{},b.headers["Content-Type"]=void 0,b.transformRequest=b.transformRequest||a.defaults.transformRequest;var d=new FormData,e=b.transformRequest,f=b.data;return b.transformRequest=function(a,c){if(f)if(b.formDataAppender)for(var d in f){var g=f[d];b.formDataAppender(a,d,g)}else for(var d in f){var g=f[d];if("function"==typeof e)g=e(g,c);else for(var h=0;h<e.length;h++){var i=e[h];"function"==typeof i&&(g=i(g,c))}a.append(d,g)}if(null!=b.file){var j=b.fileFormDataName||"file";if("[object Array]"===Object.prototype.toString.call(b.file))for(var k="[object String]"===Object.prototype.toString.call(j),h=0;h<b.file.length;h++)a.append(k?j+h:j[h],b.file[h],b.file[h].name);else a.append(j,b.file,b.file.name)}return a},b.data=d,c(b)},this.http=function(a){return c(a)}}]),a.directive("ngFileSelect",["$parse","$timeout",function(a,b){return function(c,d,e){var f=a(e.ngFileSelect);d.bind("change",function(a){var d,e,g=[];if(d=a.target.files,null!=d)for(e=0;e<d.length;e++)g.push(d.item(e));b(function(){f(c,{$files:g,$event:a})})}),("ontouchstart"in window||navigator.maxTouchPoints>0||navigator.msMaxTouchPoints>0)&&d.bind("touchend",function(a){a.preventDefault(),a.target.click()})}}]),a.directive("ngFileDropAvailable",["$parse","$timeout",function(a,b){return function(c,d,e){if("draggable"in document.createElement("span")){var f=a(e.ngFileDropAvailable);b(function(){f(c)})}}}]),a.directive("ngFileDrop",["$parse","$timeout",function(a,b){return function(c,d,e){function f(a,b){if(b.isDirectory){var c=b.createReader();i++,c.readEntries(function(b){for(var c=0;c<b.length;c++)f(a,b[c]);i--})}else i++,b.file(function(b){i--,a.push(b)})}if("draggable"in document.createElement("span")){var g=null,h=a(e.ngFileDrop);d[0].addEventListener("dragover",function(a){b.cancel(g),a.stopPropagation(),a.preventDefault(),d.addClass(e.ngFileDragOverClass||"dragover")},!1),d[0].addEventListener("dragleave",function(){g=b(function(){d.removeClass(e.ngFileDragOverClass||"dragover")})},!1);var i=0;d[0].addEventListener("drop",function(a){a.stopPropagation(),a.preventDefault(),d.removeClass(e.ngFileDragOverClass||"dragover");var g=[],j=a.dataTransfer.items;if(j&&j.length>0&&j[0].webkitGetAsEntry)for(var k=0;k<j.length;k++)f(g,j[k].webkitGetAsEntry());else{var l=a.dataTransfer.files;if(null!=l)for(var k=0;k<l.length;k++)g.push(l.item(k))}!function m(d){b(function(){i?m(10):h(c,{$files:g,$event:a})},d||0)}()},!1)}}}])}();
|
|
@ -1,4 +1,4 @@
|
|||
var app = angular.module('gophish', ['ngRoute', 'ngTable', 'ngResource', 'ui.bootstrap', 'highcharts-ng']);
|
||||
var app = angular.module('gophish', ['ngRoute', 'ngTable', 'ngResource', 'ui.bootstrap', 'highcharts-ng', 'angularFileUpload']);
|
||||
|
||||
app.config(function($routeProvider) {
|
||||
$routeProvider
|
||||
|
|
|
@ -193,8 +193,8 @@ app.controller('CampaignResultsCtrl', function($scope, CampaignService, GroupSer
|
|||
size: {
|
||||
height: 300
|
||||
},
|
||||
credits : {
|
||||
enabled : false
|
||||
credits: {
|
||||
enabled: false
|
||||
},
|
||||
loading: false,
|
||||
}
|
||||
|
@ -324,7 +324,25 @@ app.controller('GroupCtrl', function($scope, $modal, GroupService, ngTableParams
|
|||
}
|
||||
})
|
||||
|
||||
var GroupModalCtrl = function($scope, $modalInstance) {
|
||||
var GroupModalCtrl = function($scope, $modalInstance, $upload) {
|
||||
$scope.onFileSelect = function($file) {
|
||||
$scope.upload = $upload.upload({
|
||||
url: '/api/import/group',
|
||||
data: {},
|
||||
file: $file,
|
||||
}).progress(function(evt) {
|
||||
console.log('percent: ' + parseInt(100.0 * evt.loaded / evt.total));
|
||||
}).success(function(data, status, headers, config) {
|
||||
// file is uploaded successfully
|
||||
angular.forEach(data, function(record, key) {
|
||||
$scope.group.targets.push({
|
||||
email: record.email
|
||||
});
|
||||
});
|
||||
$scope.editGroupTableParams.reload();
|
||||
//.error(...)
|
||||
});
|
||||
};
|
||||
$scope.cancel = function() {
|
||||
$modalInstance.dismiss('cancel');
|
||||
};
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
<div class="form-group">
|
||||
<input type="text" class="form-control" ng-model="group.name" placeholder="Group name" id="name" autofocus/>
|
||||
</div>
|
||||
<input type="file" ng-file-select="onFileSelect($files)">
|
||||
<fieldset disabled>
|
||||
<div class="form-group">
|
||||
<button class="btn btn-danger"><i class="fa fa-plus"></i> Bulk Import Users (Coming Soon!)</button>
|
||||
|
|
|
@ -91,8 +91,10 @@
|
|||
<!-- Placed at the end of the document so the pages load faster -->
|
||||
<script src="/js/jquery.js"></script>
|
||||
<script src="/js/bootstrap.min.js"></script>
|
||||
<script src="/js/angular-file-upload-shim.min.js"></script>
|
||||
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.10/angular.min.js"></script>
|
||||
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.16/angular-route.js"></script>
|
||||
<script src="/js/angular-file-upload.min.js"></script>
|
||||
<script src="/js/ui-bootstrap-0.10.0.min.js"></script>
|
||||
<script src="/js/ng-resource.min.js"></script>
|
||||
<script src="/js/ng-table.min.js"></script>
|
||||
|
|
|
@ -0,0 +1,74 @@
|
|||
package util
|
||||
|
||||
import (
|
||||
"encoding/csv"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
|
||||
"github.com/jordan-wright/gophish/models"
|
||||
)
|
||||
|
||||
func ParseCSV(r *http.Request) ([]models.Target, error) {
|
||||
mr, err := r.MultipartReader()
|
||||
ts := []models.Target{}
|
||||
if err != nil {
|
||||
return ts, err
|
||||
}
|
||||
for {
|
||||
part, err := mr.NextPart()
|
||||
if err == io.EOF {
|
||||
break
|
||||
}
|
||||
// Skip the "submit" part
|
||||
if part.FileName() == "" {
|
||||
continue
|
||||
}
|
||||
defer part.Close()
|
||||
reader := csv.NewReader(part)
|
||||
reader.TrimLeadingSpace = true
|
||||
record, err := reader.Read()
|
||||
if err == io.EOF {
|
||||
break
|
||||
}
|
||||
fi := -1
|
||||
li := -1
|
||||
ei := -1
|
||||
fn := ""
|
||||
ln := ""
|
||||
ea := ""
|
||||
for i, v := range record {
|
||||
fmt.Println(v)
|
||||
switch {
|
||||
case v == "First Name":
|
||||
fi = i
|
||||
case v == "Last Name":
|
||||
li = i
|
||||
case v == "Email":
|
||||
ei = i
|
||||
}
|
||||
}
|
||||
for {
|
||||
record, err := reader.Read()
|
||||
if err == io.EOF {
|
||||
break
|
||||
}
|
||||
if fi != -1 {
|
||||
fn = record[fi]
|
||||
}
|
||||
if li != -1 {
|
||||
ln = record[li]
|
||||
}
|
||||
if ei != -1 {
|
||||
ea = record[ei]
|
||||
}
|
||||
t := models.Target{
|
||||
FirstName: fn,
|
||||
LastName: ln,
|
||||
Email: ea,
|
||||
}
|
||||
ts = append(ts, t)
|
||||
}
|
||||
}
|
||||
return ts, nil
|
||||
}
|
Loading…
Reference in New Issue