mirror of https://github.com/gophish/gophish
Moved models.Result into its own file
Added initial dashboard template (some updates and changes will be needed) Added some documentationpull/24/head
parent
0f603e6501
commit
02c7c4b5b1
|
@ -18,6 +18,8 @@ import (
|
|||
var templateDelims = []string{"{{%", "%}}"}
|
||||
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 {
|
||||
router := mux.NewRouter()
|
||||
// Base Front-end routes
|
||||
|
@ -62,7 +64,21 @@ func CreatePhishingRouter() http.Handler {
|
|||
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) {
|
||||
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!"))
|
||||
}
|
||||
|
||||
|
|
|
@ -41,29 +41,18 @@ func (c *Campaign) UpdateStatus(s string) 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.Time = time.Now()
|
||||
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 {
|
||||
Id int64 `json:"-"`
|
||||
CampaignId int64 `json:"-"`
|
||||
Email string `json:"email"`
|
||||
Time time.Time `json:"time"`
|
||||
Message string `json:"message"`
|
||||
Message string `json:"message"`
|
||||
}
|
||||
|
||||
// GetCampaigns returns the campaigns owned by the given user.
|
||||
|
@ -115,7 +104,7 @@ func PostCampaign(c *Campaign, uid int64) error {
|
|||
c.UserId = uid
|
||||
c.CreatedDate = time.Now()
|
||||
c.CompletedDate = time.Time{}
|
||||
c.Status = QUEUED
|
||||
c.Status = CAMPAIGN_QUEUED
|
||||
// Check to make sure all the groups already exist
|
||||
for i, g := range c.Groups {
|
||||
c.Groups[i], err = GetGroupByName(g.Name, uid)
|
||||
|
@ -144,7 +133,7 @@ func PostCampaign(c *Campaign, uid int64) error {
|
|||
Logger.Println(err)
|
||||
return err
|
||||
}
|
||||
err = c.AddEvent(Event{Message:"Campaign Created"})
|
||||
err = c.AddEvent(Event{Message: "Campaign Created"})
|
||||
if err != nil {
|
||||
Logger.Println(err)
|
||||
}
|
||||
|
@ -153,7 +142,8 @@ func PostCampaign(c *Campaign, uid int64) error {
|
|||
// Insert a result for each target in the group
|
||||
for _, t := range g.Targets {
|
||||
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 {
|
||||
Logger.Printf("Error adding result record for target %s\n", t.Email)
|
||||
Logger.Println(err)
|
||||
|
|
|
@ -18,10 +18,13 @@ var ErrUsernameTaken = errors.New("username already taken")
|
|||
var Logger = log.New(os.Stdout, " ", log.Ldate|log.Ltime|log.Lshortfile)
|
||||
|
||||
const (
|
||||
IN_PROGRESS string = "In progress"
|
||||
QUEUED string = "Queued"
|
||||
COMPLETE string = "Completed"
|
||||
ERROR string = "Error"
|
||||
CAMPAIGN_IN_PROGRESS string = "In progress"
|
||||
CAMPAIGN_QUEUED string = "Queued"
|
||||
CAMPAIGN_COMPLETE string = "Completed"
|
||||
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.
|
||||
|
|
|
@ -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
|
||||
}
|
|
@ -5,8 +5,8 @@ app.config(function($routeProvider) {
|
|||
|
||||
// route for the home page
|
||||
.when('/', {
|
||||
templateUrl: 'js/app/partials/campaigns.html',
|
||||
controller: 'CampaignCtrl'
|
||||
templateUrl: 'js/app/partials/dashboard.html',
|
||||
controller: 'DashboardCtrl'
|
||||
})
|
||||
|
||||
.when('/campaigns', {
|
||||
|
|
|
@ -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) {
|
||||
$scope.flashes = []
|
||||
$scope.mainTableParams = new ngTableParams({
|
||||
|
|
|
@ -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 & 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>
|
||||
|
||||
<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>
|
|
@ -35,7 +35,7 @@ func (w *Worker) Start() {
|
|||
|
||||
func processCampaign(c *models.Campaign) {
|
||||
Logger.Printf("Worker received: %s", c.Name)
|
||||
err := c.UpdateStatus(models.IN_PROGRESS)
|
||||
err := c.UpdateStatus(models.CAMPAIGN_IN_PROGRESS)
|
||||
if err != nil {
|
||||
Logger.Println(err)
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue