Moved models.Result into its own file

Added initial dashboard template (some updates and changes will be needed)
Added some documentation
pull/24/head
Jordan 2014-07-01 20:32:34 -05:00
parent 0f603e6501
commit 02c7c4b5b1
8 changed files with 211 additions and 23 deletions

View File

@ -18,6 +18,8 @@ import (
var templateDelims = []string{"{{%", "%}}"} var templateDelims = []string{"{{%", "%}}"}
var Logger = log.New(os.Stdout, " ", log.Ldate|log.Ltime|log.Lshortfile) var Logger = log.New(os.Stdout, " ", log.Ldate|log.Ltime|log.Lshortfile)
// CreateAdminRouter creates the routes for handling requests to the web interface.
// This function returns an http.Handler to be used in http.ListenAndServe().
func CreateAdminRouter() http.Handler { func CreateAdminRouter() http.Handler {
router := mux.NewRouter() router := mux.NewRouter()
// Base Front-end routes // Base Front-end routes
@ -62,7 +64,21 @@ func CreatePhishingRouter() http.Handler {
return router return router
} }
// PhishHandler handles incoming client connections and registers the associated actions performed
// (such as clicked link, etc.)
func PhishHandler(w http.ResponseWriter, r *http.Request) { func PhishHandler(w http.ResponseWriter, r *http.Request) {
r.ParseForm()
id := r.Form.Get("rid")
if id == "" {
http.NotFound(w, r)
return
}
rs, err := models.GetResult(id)
if err != nil {
http.NotFound(w, r)
return
}
rs.UpdateStatus("Clicked Link")
w.Write([]byte("It Works!")) w.Write([]byte("It Works!"))
} }

View File

@ -41,29 +41,18 @@ func (c *Campaign) UpdateStatus(s string) error {
return db.Table("campaigns").Where("id=?", c.Id).Update("status", s).Error return db.Table("campaigns").Where("id=?", c.Id).Update("status", s).Error
} }
func (c *Campaign) AddEvent (e Event) error { func (c *Campaign) AddEvent(e Event) error {
e.CampaignId = c.Id e.CampaignId = c.Id
e.Time = time.Now() e.Time = time.Now()
return db.Debug().Save(&e).Error return db.Debug().Save(&e).Error
} }
type Result struct {
Id int64 `json:"-"`
CampaignId int64 `json:"-"`
Email string `json:"email"`
Status string `json:"status" sql:"not null"`
}
func (r *Result) UpdateStatus(s string) error {
return db.Debug().Table("results").Where("id=?", r.Id).Update("status", s).Error
}
type Event struct { type Event struct {
Id int64 `json:"-"` Id int64 `json:"-"`
CampaignId int64 `json:"-"` CampaignId int64 `json:"-"`
Email string `json:"email"` Email string `json:"email"`
Time time.Time `json:"time"` Time time.Time `json:"time"`
Message string `json:"message"` Message string `json:"message"`
} }
// GetCampaigns returns the campaigns owned by the given user. // GetCampaigns returns the campaigns owned by the given user.
@ -115,7 +104,7 @@ func PostCampaign(c *Campaign, uid int64) error {
c.UserId = uid c.UserId = uid
c.CreatedDate = time.Now() c.CreatedDate = time.Now()
c.CompletedDate = time.Time{} c.CompletedDate = time.Time{}
c.Status = QUEUED c.Status = CAMPAIGN_QUEUED
// Check to make sure all the groups already exist // Check to make sure all the groups already exist
for i, g := range c.Groups { for i, g := range c.Groups {
c.Groups[i], err = GetGroupByName(g.Name, uid) c.Groups[i], err = GetGroupByName(g.Name, uid)
@ -144,7 +133,7 @@ func PostCampaign(c *Campaign, uid int64) error {
Logger.Println(err) Logger.Println(err)
return err return err
} }
err = c.AddEvent(Event{Message:"Campaign Created"}) err = c.AddEvent(Event{Message: "Campaign Created"})
if err != nil { if err != nil {
Logger.Println(err) Logger.Println(err)
} }
@ -153,7 +142,8 @@ func PostCampaign(c *Campaign, uid int64) error {
// Insert a result for each target in the group // Insert a result for each target in the group
for _, t := range g.Targets { for _, t := range g.Targets {
r := Result{Email: t.Email, Status: "Unknown", CampaignId: c.Id} r := Result{Email: t.Email, Status: "Unknown", CampaignId: c.Id}
err := db.Save(&r).Error r.GenerateId()
err = db.Save(&r).Error
if err != nil { if err != nil {
Logger.Printf("Error adding result record for target %s\n", t.Email) Logger.Printf("Error adding result record for target %s\n", t.Email)
Logger.Println(err) Logger.Println(err)

View File

@ -18,10 +18,13 @@ var ErrUsernameTaken = errors.New("username already taken")
var Logger = log.New(os.Stdout, " ", log.Ldate|log.Ltime|log.Lshortfile) var Logger = log.New(os.Stdout, " ", log.Ldate|log.Ltime|log.Lshortfile)
const ( const (
IN_PROGRESS string = "In progress" CAMPAIGN_IN_PROGRESS string = "In progress"
QUEUED string = "Queued" CAMPAIGN_QUEUED string = "Queued"
COMPLETE string = "Completed" CAMPAIGN_COMPLETE string = "Completed"
ERROR string = "Error" STATUS_SENT string = "Email Sent"
STATUS_OPENED string = "Email Opened"
STATUS_CLICKED string = "Clicked Link"
ERROR string = "Error"
) )
// Flash is used to hold flash information for use in templates. // Flash is used to hold flash information for use in templates.

40
models/result.go Normal file
View File

@ -0,0 +1,40 @@
package models
import (
"crypto/rand"
"fmt"
"io"
"github.com/jinzhu/gorm"
)
type Result struct {
Id int64 `json:"-"`
CampaignId int64 `json:"-"`
RId string `json:"id"`
Email string `json:"email"`
Status string `json:"status" sql:"not null"`
}
func (r *Result) UpdateStatus(s string) error {
return db.Table("results").Where("id=?", r.Id).Update("status", s).Error
}
func (r *Result) GenerateId() {
// Keep trying until we generate a unique key (shouldn't take more than one or two iterations)
k := make([]byte, 32)
for {
io.ReadFull(rand.Reader, k)
r.RId = fmt.Sprintf("%x", k)
err := db.Table("results").Where("id=?", r.RId).First(&Result{}).Error
if err == gorm.RecordNotFound {
break
}
}
}
func GetResult(rid string) (Result, error) {
r := Result{}
err := db.Where("r_id=?", rid).First(&r).Error
return r, err
}

View File

@ -5,8 +5,8 @@ app.config(function($routeProvider) {
// route for the home page // route for the home page
.when('/', { .when('/', {
templateUrl: 'js/app/partials/campaigns.html', templateUrl: 'js/app/partials/dashboard.html',
controller: 'CampaignCtrl' controller: 'DashboardCtrl'
}) })
.when('/campaigns', { .when('/campaigns', {

View File

@ -1,3 +1,73 @@
app.controller('DashboardCtrl', function($scope, CampaignService, ngTableParams, $http) {
$scope.mainTableParams = new ngTableParams({
page: 1, // show first page
count: 10, // count per page
sorting: {
name: 'asc' // initial sorting
}
}, {
total: 0, // length of data
getData: function($defer, params) {
CampaignService.query(function(campaigns) {
$scope.campaigns = campaigns
var campaign_series = []
angular.forEach(campaigns, function(campaign, key) {
campaign_series.push({
y: 0
})
angular.forEach(campaign.results, function(result, r_key) {
if (result.status == "Clicked Link") {
campaign_series[campaign_series.length - 1].y++;
}
})
campaign_series[campaign_series.length - 1].y = Math.floor((campaign_series[campaign_series.length - 1].y / campaign.results.length)*100)
console.log(campaign_series)
});
$scope.overview_chart = {
options: {
chart: {
type: 'area'
},
tooltip: {
formatter: function() {
return "Successful Phishes: " + this.point.y + "%"
},
style: {
padding: 10,
fontWeight: 'bold'
}
},
plotOptions: {
pie: {
allowPointSelect: true,
cursor: 'pointer',
dataLabels: {
enabled: false
},
showInLegend: true
}
}
},
series: [{
data: campaign_series
}],
title: {
text: 'Phishing Success Overview'
},
size: {
height: 300
},
credits: {
enabled: false
},
loading: false,
}
params.total(Math.min(campaigns.length, 5));
$defer.resolve(campaigns.slice(0, params.total()));
})
}
});
})
app.controller('CampaignCtrl', function($scope, $modal, CampaignService, GroupService, TemplateService, ngTableParams, $http) { app.controller('CampaignCtrl', function($scope, $modal, CampaignService, GroupService, TemplateService, ngTableParams, $http) {
$scope.flashes = [] $scope.flashes = []
$scope.mainTableParams = new ngTableParams({ $scope.mainTableParams = new ngTableParams({

View File

@ -0,0 +1,69 @@
<div class="container-fluid">
<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>
<li><a href="#/campaigns">Campaigns</a>
</li>
<li><a href="#/users">Users &amp; Groups</a>
</li>
<li><a href="#/templates">Templates</a>
</li>
<li><a href="#/settings">Settings</a>
</li>
<li><a href="/api/">API Documentation</a>
</li>
</ul>
</div>
</div>
</div>
<div class="col-sm-9 col-sm-offset-3 col-md-10 col-md-offset-2 main" ng-controller="DashboardCtrl">
<h1 class="page-header">
Dashboard
</h1>
<div class="row">
<div ng-repeat="flash in flashes" style="text-align:center" class="alert alert-{{flash.type}}">
<i class="fa {{flash.icon}}"></i> {{flash.message}}
</div>
</div>
<div class="row">
<div class="col-lg-6 col-md-6 col-sm-12 col-xs-12">
<highchart config="overview_chart"></highchart>
</div>
</div>
<div class="row">
<h2>Recent Campaigns</h2>
</div>
<div class="row">
<a href="#/campaigns"><button type="button" class="btn btn-primary">View All</button></a>
</div>
&nbsp;&nbsp;
<div class="row">
<table ng-table="mainTableParams" class="table table-hover table-striped table-bordered">
<tbody>
<tr ng-repeat="campaign in $data" class="editable-row">
<td data-title="'Created Date'" class="col-sm-1">{{campaign.created_date | date:'medium'}}</td>
<td data-title="'Name'" class="col-sm-2">{{campaign.name}}
<div class="btn-group" style="float: right;">
<button type="button" class="btn btn-primary dropdown-toggle edit-button" data-toggle="dropdown">
<span class="caret" style="border-top-color:#FFFFFF"></span>
<span class="sr-only">Toggle Dropdown</span>
</button>
<ul class="dropdown-menu" style="left:auto; right:0;" role="menu">
<li><a ng-href="#/campaigns/{{campaign.id}}">View</a>
</li>
<li><a href="/campaigns/{{campaign.id}}/relaunch">Relaunch</a>
</li>
<li class="divider"></li>
<li><a ng-click="deleteCampaign(campaign)" ng-href="#">Delete</a>
</li>
</ul>
</div>
</td>
<td data-title="'Status'" class="col-sm-1">{{campaign.status}}</td>
</tr>
</tbody>
</table>
</div>
</div>

View File

@ -35,7 +35,7 @@ func (w *Worker) Start() {
func processCampaign(c *models.Campaign) { func processCampaign(c *models.Campaign) {
Logger.Printf("Worker received: %s", c.Name) Logger.Printf("Worker received: %s", c.Name)
err := c.UpdateStatus(models.IN_PROGRESS) err := c.UpdateStatus(models.CAMPAIGN_IN_PROGRESS)
if err != nil { if err != nil {
Logger.Println(err) Logger.Println(err)
} }