diff --git a/static/js/dist/app/campaign_results.min.js b/static/js/dist/app/campaign_results.min.js index a685f661..4ca745ad 100644 --- a/static/js/dist/app/campaign_results.min.js +++ b/static/js/dist/app/campaign_results.min.js @@ -1 +1 @@ -function dismiss(){$("#modal\\.flashes").empty(),$("#modal").modal("hide"),$("#resultsTable").dataTable().DataTable().clear().draw()}function deleteCampaign(){swal({title:"Are you sure?",text:"This will delete the campaign. This can't be undone!",type:"warning",animation:!1,showCancelButton:!0,confirmButtonText:"Delete Campaign",confirmButtonColor:"#428bca",reverseButtons:!0,allowOutsideClick:!1,preConfirm:function(){return new Promise(function(e,t){api.campaignId.delete(campaign.id).success(function(t){e()}).error(function(e){t(e.responseJSON.message)})})}}).then(function(){swal("Campaign Deleted!","This campaign has been deleted!","success"),$('button:contains("OK")').on("click",function(){location.href="/campaigns"})})}function completeCampaign(){swal({title:"Are you sure?",text:"Gophish will stop processing events for this campaign",type:"warning",animation:!1,showCancelButton:!0,confirmButtonText:"Complete Campaign",confirmButtonColor:"#428bca",reverseButtons:!0,allowOutsideClick:!1,preConfirm:function(){return new Promise(function(e,t){api.campaignId.complete(campaign.id).success(function(t){e()}).error(function(e){t(e.responseJSON.message)})})}}).then(function(){swal("Campaign Completed!","This campaign has been completed!","success"),$("#complete_button")[0].disabled=!0,$("#complete_button").text("Completed!"),doPoll=!1})}function exportAsCSV(e){exportHTML=$("#exportButton").html();var t=null;switch(e){case"results":t=campaign.results;break;case"events":t=campaign.timeline}if(t){$("#exportButton").html('');var a=Papa.unparse(t,{}),i=new Blob([a],{type:"text/csv;charset=utf-8;"});if(navigator.msSaveBlob)navigator.msSaveBlob(i,e+".csv");else{var s=window.URL.createObjectURL(i),l=document.createElement("a");l.href=s,l.setAttribute("download",e+".csv"),document.body.appendChild(l),l.click(),document.body.removeChild(l)}$("#exportButton").html(exportHTML)}}function replay(e){function t(){form.attr({action:url}),form.appendTo("body").submit().remove()}request=campaign.timeline[e],details=JSON.parse(request.details),url=null,form=$("
").attr({method:"POST",target:"_blank"}),$.each(Object.keys(details.payload),function(e,t){return"rid"==t||("__original_url"==t?(url=details.payload[t],!0):void $("").attr({name:t}).val(details.payload[t]).appendTo(form))}),swal({title:"Where do you want the credentials submitted to?",input:"text",showCancelButton:!0,inputPlaceholder:"http://example.com/login",inputValue:url||"",inputValidator:function(e){return new Promise(function(t,a){e?t():a("Invalid URL.")})}}).then(function(e){url=e,t()})}function renderTimeline(e){return record={first_name:e[2],last_name:e[3],email:e[4],position:e[5]},results='
Timeline for '+escapeHtml(record.first_name)+" "+escapeHtml(record.last_name)+'
Email: '+escapeHtml(record.email)+'
',$.each(campaign.timeline,function(e,t){t.email&&t.email!=record.email||(results+='
',results+='
'+escapeHtml(t.message)+' '+moment(t.time).format("MMMM Do YYYY h:mm a")+"",t.details&&("Submitted Data"==t.message&&(results+='
',results+='
View Details
'),details=JSON.parse(t.details),details.payload&&(results+='
',results+=' ',results+=" ",$.each(Object.keys(details.payload),function(e,t){return"rid"==t||(results+=" ",results+=" ",results+=" ",void(results+=" "))}),results+="
ParameterValue(s)
"+escapeHtml(t)+""+escapeHtml(details.payload[t])+"
",results+="
"),details.error&&(results+='
View Details
',results+='
',results+='Error '+details.error,results+="
")),results+="
")}),results+="
",results}function poll(){api.campaignId.results(campaign.id).success(function(e){campaign=e;var t={series:[{name:"Events",data:[]}]};$.each(campaign.timeline,function(e,a){t.series[0].data.push({meta:e,x:new Date(a.time),y:1})});var a=$("#timeline_chart");a.get(0).__chartist__&&a.get(0).__chartist__.update(t);var i={series:[]},s={};$.each(campaign.results,function(e,t){s[t.status]?s[t.status]++:s[t.status]=1}),$("#email_chart_legend").html(""),$.each(s,function(e,t){i.series.push({meta:e,value:t}),$("#email_chart_legend").append('
  • '+e+"
  • ")});var l=$("#email_chart");l.get(0).__chartist__&&(l.get(0).__chartist__.on("draw",function(e){e.element.addClass(statuses[e.meta].slice)}),l.get(0).__chartist__.update(i)),resultsTable=$("#resultsTable").DataTable(),resultsTable.rows().every(function(e,t,a){var i=this.row(e),s=i.data(),l=s[0];$.each(campaign.results,function(t,a){if(a.id==l){var n=statuses[a.status].label||"label-default";return s[6]=''+a.status+"",resultsTable.row(e).data(s).draw(!1),i.child.isShown()&&i.child(renderTimeline(i.data())),!1}})}),bubbles=[],$.each(campaign.results,function(e,t){return 0==t.latitude&&0==t.longitude||(newIP=!0,$.each(bubbles,function(e,a){if(a.ip==t.ip)return bubbles[e].radius+=1,newIP=!1,!1}),void(newIP&&bubbles.push({latitude:t.latitude,longitude:t.longitude,name:t.ip,fillKey:"point",radius:2})))}),map.bubbles(bubbles)})}function load(){campaign.id=window.location.pathname.split("/").slice(-1)[0],api.campaignId.results(campaign.id).success(function(e){if(campaign=e){$("title").text(e.name+" - Gophish"),$("#loading").hide(),$("#campaignResults").show(),$("#page-title").text("Results for "+e.name),"Completed"==e.status&&($("#complete_button")[0].disabled=!0,$("#complete_button").text("Completed!"),doPoll=!1),$('[data-toggle="tooltip"]').tooltip(),$("#resultsTable").on("click",".timeline-event-details",function(){payloadResults=$(this).parent().find(".timeline-event-results"),payloadResults.is(":visible")?($(this).find("i").removeClass("fa-caret-down"),$(this).find("i").addClass("fa-caret-right"),payloadResults.hide()):($(this).find("i").removeClass("fa-caret-right"),$(this).find("i").addClass("fa-caret-down"),payloadResults.show())});var t={series:[{name:"Events",data:[]}]},a={series:[]},i={},s={axisX:{showGrid:!1,type:Chartist.FixedScaleAxis,divisor:5,labelInterpolationFnc:function(e){return moment(e).format("MMMM Do YYYY h:mm a")}},axisY:{type:Chartist.FixedScaleAxis,ticks:[0,1,2],low:0,showLabel:!1},showArea:!1,plugins:[]},l={donut:!0,donutWidth:40,chartPadding:0,showLabel:!1};resultsTable=$("#resultsTable").DataTable({destroy:!0,order:[[2,"asc"]],columnDefs:[{orderable:!1,targets:"no-sort"},{className:"details-control",targets:[1]},{visible:!1,targets:[0]}]}),resultsTable.clear(),$.each(campaign.results,function(e,t){label=statuses[t.status].label||"label-default",resultsTable.row.add([t.id,'',escapeHtml(t.first_name)||"",escapeHtml(t.last_name)||"",escapeHtml(t.email)||"",escapeHtml(t.position)||"",''+t.status+""]).draw(),i[t.status]?i[t.status]++:i[t.status]=1}),$("#resultsTable tbody").on("click","td.details-control",function(){var e=$(this).closest("tr"),t=resultsTable.row(e);t.child.isShown()?(t.child.hide(),e.removeClass("shown"),$(this).find("i").removeClass("fa-caret-down"),$(this).find("i").addClass("fa-caret-right"),t.invalidate("dom").draw(!1)):($(this).find("i").removeClass("fa-caret-right"),$(this).find("i").addClass("fa-caret-down"),t.child(renderTimeline(t.data())).show(),e.addClass("shown"),t.invalidate("dom").draw(!1))}),$.each(campaign.timeline,function(e,a){t.series[0].data.push({meta:e,x:new Date(a.time),y:1})}),$("#email_chart_legend").html(""),$.each(i,function(e,t){a.series.push({meta:e,value:t}),$("#email_chart_legend").append('
  • '+e+"
  • ")});var n=new Chartist.Line("#timeline_chart",t,s);n.on("draw",function(e){if("point"===e.type){var t=statuses[campaign.timeline[e.meta].message].point,a=new Chartist.Svg("circle",{cx:[e.x],cy:[e.y],r:5,fill:"#283F50",meta:e.meta,value:1},t+" ct-timeline-point");e.element.replace(a)}}),$chart=$("#timeline_chart");var o=$chart.append('
    ').find(".chartist-tooltip").hide();$chart.on("mouseenter",".ct-timeline-point",function(){var e=$(this);cidx=e.attr("meta"),html="Event: "+campaign.timeline[cidx].message,campaign.timeline[cidx].email&&(html+="
    Email: "+escapeHtml(campaign.timeline[cidx].email)),o.html(html).show()}),$chart.on("mouseleave",".ct-timeline-point",function(){o.hide()}),$chart.on("mousemove",function(e){o.css({left:(e.offsetX||e.originalEvent.layerX)-o.width()/2-10,top:(e.offsetY+70||e.originalEvent.layerY)-o.height()-40})});var r=new Chartist.Pie("#email_chart",a,l);r.on("draw",function(e){e.element.addClass(statuses[e.meta].slice)}),$piechart=$("#email_chart");var c=$piechart.append('
    ').find(".chartist-tooltip").hide();$piechart.on("mouseenter",".ct-slice-donut",function(){var e=$(this);value=e.attr("ct:value"),label=e.attr("ct:meta"),c.html(label+": "+value.toString()).show()}),$piechart.on("mouseleave",".ct-slice-donut",function(){c.hide()}),$piechart.on("mousemove",function(e){c.css({left:(e.offsetX||e.originalEvent.layerX)-c.width()/2-10,top:(e.offsetY+40||e.originalEvent.layerY)-c.height()-80})}),map||(map=new Datamap({element:document.getElementById("resultsMap"),responsive:!0,fills:{defaultFill:"#ffffff",point:"#283F50"},geographyConfig:{highlightFillColor:"#1abc9c",borderColor:"#283F50"},bubblesConfig:{borderColor:"#283F50"}})),$.each(campaign.results,function(e,t){return 0==t.latitude&&0==t.longitude||(newIP=!0,$.each(bubbles,function(e,a){if(a.ip==t.ip)return bubbles[e].radius+=1,newIP=!1,!1}),void(newIP&&bubbles.push({latitude:t.latitude,longitude:t.longitude,name:t.ip,fillKey:"point",radius:2})))}),map.bubbles(bubbles)}$('a[data-toggle="tab"]').on("shown.bs.tab",function(e){"#overview"==$(e.target).attr("href")&&(map||(map=new Datamap({element:document.getElementById("resultsMap"),responsive:!0,fills:{defaultFill:"#ffffff"},geographyConfig:{highlightFillColor:"#1abc9c",borderColor:"#283F50"}})))})}).error(function(){$("#loading").hide(),errorFlash(" Campaign not found!")})}var map=null,doPoll=!0,statuses={"Email Sent":{slice:"ct-slice-donut-sent",legend:"ct-legend-sent",label:"label-success",icon:"fa-envelope",point:"ct-point-sent"},"Email Opened":{slice:"ct-slice-donut-opened",legend:"ct-legend-opened",label:"label-warning",icon:"fa-envelope",point:"ct-point-opened"},"Clicked Link":{slice:"ct-slice-donut-clicked",legend:"ct-legend-clicked",label:"label-clicked",icon:"fa-mouse-pointer",point:"ct-point-clicked"},Success:{slice:"ct-slice-donut-success",legend:"ct-legend-success",label:"label-danger",icon:"fa-exclamation",point:"ct-point-clicked"},Error:{slice:"ct-slice-donut-error",legend:"ct-legend-error",label:"label-default",icon:"fa-times",point:"ct-point-error"},"Error Sending Email":{slice:"ct-slice-donut-error",legend:"ct-legend-error",label:"label-default",icon:"fa-times",point:"ct-point-error"},"Submitted Data":{slice:"ct-slice-donut-success",legend:"ct-legend-success",label:"label-danger",icon:"fa-exclamation",point:"ct-point-clicked"},Unknown:{slice:"ct-slice-donut-error",legend:"ct-legend-error",label:"label-default",icon:"fa-question",point:"ct-point-error"},Sending:{slice:"ct-slice-donut-sending",legend:"ct-legend-sending",label:"label-primary",icon:"fa-spinner",point:"ct-point-sending"},"Campaign Created":{label:"label-success",icon:"fa-rocket"}},campaign={},bubbles=[];$(document).ready(function(){function e(){doPoll&&($("#refresh_message").show(),poll(),$("#refresh_message").hide(),setTimeout(e,1e4))}load(),setTimeout(e,1e4)}); \ No newline at end of file +function dismiss(){$("#modal\\.flashes").empty(),$("#modal").modal("hide"),$("#resultsTable").dataTable().DataTable().clear().draw()}function deleteCampaign(){swal({title:"Are you sure?",text:"This will delete the campaign. This can't be undone!",type:"warning",animation:!1,showCancelButton:!0,confirmButtonText:"Delete Campaign",confirmButtonColor:"#428bca",reverseButtons:!0,allowOutsideClick:!1,preConfirm:function(){return new Promise(function(e,t){api.campaignId.delete(campaign.id).success(function(t){e()}).error(function(e){t(e.responseJSON.message)})})}}).then(function(){swal("Campaign Deleted!","This campaign has been deleted!","success"),$('button:contains("OK")').on("click",function(){location.href="/campaigns"})})}function completeCampaign(){swal({title:"Are you sure?",text:"Gophish will stop processing events for this campaign",type:"warning",animation:!1,showCancelButton:!0,confirmButtonText:"Complete Campaign",confirmButtonColor:"#428bca",reverseButtons:!0,allowOutsideClick:!1,preConfirm:function(){return new Promise(function(e,t){api.campaignId.complete(campaign.id).success(function(t){e()}).error(function(e){t(e.responseJSON.message)})})}}).then(function(){swal("Campaign Completed!","This campaign has been completed!","success"),$("#complete_button")[0].disabled=!0,$("#complete_button").text("Completed!"),doPoll=!1})}function exportAsCSV(e){exportHTML=$("#exportButton").html();var t=null;switch(e){case"results":t=campaign.results;break;case"events":t=campaign.timeline}if(t){$("#exportButton").html('');var a=Papa.unparse(t,{}),i=new Blob([a],{type:"text/csv;charset=utf-8;"});if(navigator.msSaveBlob)navigator.msSaveBlob(i,e+".csv");else{var s=window.URL.createObjectURL(i),l=document.createElement("a");l.href=s,l.setAttribute("download",e+".csv"),document.body.appendChild(l),l.click(),document.body.removeChild(l)}$("#exportButton").html(exportHTML)}}function replay(e){function t(){form.attr({action:url}),form.appendTo("body").submit().remove()}request=campaign.timeline[e],details=JSON.parse(request.details),url=null,form=$("").attr({method:"POST",target:"_blank"}),$.each(Object.keys(details.payload),function(e,t){return"rid"==t||("__original_url"==t?(url=details.payload[t],!0):void $("").attr({name:t}).val(details.payload[t]).appendTo(form))}),swal({title:"Where do you want the credentials submitted to?",input:"text",showCancelButton:!0,inputPlaceholder:"http://example.com/login",inputValue:url||"",inputValidator:function(e){return new Promise(function(t,a){e?t():a("Invalid URL.")})}}).then(function(e){url=e,t()})}function renderTimeline(e){return record={first_name:e[2],last_name:e[3],email:e[4],position:e[5]},results='
    Timeline for '+escapeHtml(record.first_name)+" "+escapeHtml(record.last_name)+'
    Email: '+escapeHtml(record.email)+'
    ',$.each(campaign.timeline,function(e,t){t.email&&t.email!=record.email||(results+='
    ',results+='
    '+escapeHtml(t.message)+' '+moment(t.time).format("MMMM Do YYYY h:mm a")+"",t.details&&("Submitted Data"==t.message&&(results+='
    ',results+='
    View Details
    '),details=JSON.parse(t.details),details.payload&&(results+='
    ',results+=' ',results+=" ",$.each(Object.keys(details.payload),function(e,t){return"rid"==t||(results+=" ",results+=" ",results+=" ",void(results+=" "))}),results+="
    ParameterValue(s)
    "+escapeHtml(t)+""+escapeHtml(details.payload[t])+"
    ",results+="
    "),details.error&&(results+='
    View Details
    ',results+='
    ',results+='Error '+details.error,results+="
    ")),results+="
    ")}),results+="
    ",results}function poll(){api.campaignId.results(campaign.id).success(function(e){campaign=e;var t={series:[{name:"Events",data:[]}]};$.each(campaign.timeline,function(e,a){t.series[0].data.push({meta:e,x:new Date(a.time),y:1})});var a=$("#timeline_chart");a.get(0).__chartist__&&a.get(0).__chartist__.update(t);var i={series:[]},s={};$.each(campaign.results,function(e,t){s[t.status]?s[t.status]++:s[t.status]=1}),$("#email_chart_legend").html(""),$.each(s,function(e,t){i.series.push({meta:e,value:t}),$("#email_chart_legend").append('
  • '+e+"
  • ")});var l=$("#email_chart");l.get(0).__chartist__&&(l.get(0).__chartist__.on("draw",function(e){e.element.addClass(statuses[e.meta].slice)}),l.get(0).__chartist__.update(i)),resultsTable=$("#resultsTable").DataTable(),resultsTable.rows().every(function(e,t,a){var i=this.row(e),s=i.data(),l=s[0];$.each(campaign.results,function(t,a){if(a.id==l){var n=statuses[a.status].label||"label-default";return s[6]=''+a.status+"",resultsTable.row(e).data(s).draw(!1),i.child.isShown()&&i.child(renderTimeline(i.data())),!1}})}),bubbles=[],$.each(campaign.results,function(e,t){return 0==t.latitude&&0==t.longitude||(newIP=!0,$.each(bubbles,function(e,a){if(a.ip==t.ip)return bubbles[e].radius+=1,newIP=!1,!1}),void(newIP&&bubbles.push({latitude:t.latitude,longitude:t.longitude,name:t.ip,fillKey:"point",radius:2})))}),map.bubbles(bubbles),$("#refresh_message").hide(),$("#refresh_btn").show()})}function load(){campaign.id=window.location.pathname.split("/").slice(-1)[0],api.campaignId.results(campaign.id).success(function(e){if(campaign=e){$("title").text(e.name+" - Gophish"),$("#loading").hide(),$("#campaignResults").show(),$("#page-title").text("Results for "+e.name),"Completed"==e.status&&($("#complete_button")[0].disabled=!0,$("#complete_button").text("Completed!"),doPoll=!1),$('[data-toggle="tooltip"]').tooltip(),$("#resultsTable").on("click",".timeline-event-details",function(){payloadResults=$(this).parent().find(".timeline-event-results"),payloadResults.is(":visible")?($(this).find("i").removeClass("fa-caret-down"),$(this).find("i").addClass("fa-caret-right"),payloadResults.hide()):($(this).find("i").removeClass("fa-caret-right"),$(this).find("i").addClass("fa-caret-down"),payloadResults.show())});var t={series:[{name:"Events",data:[]}]},a={series:[]},i={},s={axisX:{showGrid:!1,type:Chartist.FixedScaleAxis,divisor:5,labelInterpolationFnc:function(e){return moment(e).format("MMMM Do YYYY h:mm a")}},axisY:{type:Chartist.FixedScaleAxis,ticks:[0,1,2],low:0,showLabel:!1},showArea:!1,plugins:[]},l={donut:!0,donutWidth:40,chartPadding:0,showLabel:!1};resultsTable=$("#resultsTable").DataTable({destroy:!0,order:[[2,"asc"]],columnDefs:[{orderable:!1,targets:"no-sort"},{className:"details-control",targets:[1]},{visible:!1,targets:[0]}]}),resultsTable.clear(),$.each(campaign.results,function(e,t){label=statuses[t.status].label||"label-default",resultsTable.row.add([t.id,'',escapeHtml(t.first_name)||"",escapeHtml(t.last_name)||"",escapeHtml(t.email)||"",escapeHtml(t.position)||"",''+t.status+""]).draw(),i[t.status]?i[t.status]++:i[t.status]=1}),$("#resultsTable tbody").on("click","td.details-control",function(){var e=$(this).closest("tr"),t=resultsTable.row(e);t.child.isShown()?(t.child.hide(),e.removeClass("shown"),$(this).find("i").removeClass("fa-caret-down"),$(this).find("i").addClass("fa-caret-right"),t.invalidate("dom").draw(!1)):($(this).find("i").removeClass("fa-caret-right"),$(this).find("i").addClass("fa-caret-down"),t.child(renderTimeline(t.data())).show(),e.addClass("shown"),t.invalidate("dom").draw(!1))}),$.each(campaign.timeline,function(e,a){t.series[0].data.push({meta:e,x:new Date(a.time),y:1})}),$("#email_chart_legend").html(""),$.each(i,function(e,t){a.series.push({meta:e,value:t}),$("#email_chart_legend").append('
  • '+e+"
  • ")});var n=new Chartist.Line("#timeline_chart",t,s);n.on("draw",function(e){if("point"===e.type){var t=statuses[campaign.timeline[e.meta].message].point,a=new Chartist.Svg("circle",{cx:[e.x],cy:[e.y],r:5,fill:"#283F50",meta:e.meta,value:1},t+" ct-timeline-point");e.element.replace(a)}}),$chart=$("#timeline_chart");var o=$chart.append('
    ').find(".chartist-tooltip").hide();$chart.on("mouseenter",".ct-timeline-point",function(){var e=$(this);cidx=e.attr("meta"),html="Event: "+campaign.timeline[cidx].message,campaign.timeline[cidx].email&&(html+="
    Email: "+escapeHtml(campaign.timeline[cidx].email)),o.html(html).show()}),$chart.on("mouseleave",".ct-timeline-point",function(){o.hide()}),$chart.on("mousemove",function(e){o.css({left:(e.offsetX||e.originalEvent.layerX)-o.width()/2-10,top:(e.offsetY+70||e.originalEvent.layerY)-o.height()-40})});var r=new Chartist.Pie("#email_chart",a,l);r.on("draw",function(e){e.element.addClass(statuses[e.meta].slice)}),$piechart=$("#email_chart");var c=$piechart.append('
    ').find(".chartist-tooltip").hide();$piechart.on("mouseenter",".ct-slice-donut",function(){var e=$(this);value=e.attr("ct:value"),label=e.attr("ct:meta"),c.html(label+": "+value.toString()).show()}),$piechart.on("mouseleave",".ct-slice-donut",function(){c.hide()}),$piechart.on("mousemove",function(e){c.css({left:(e.offsetX||e.originalEvent.layerX)-c.width()/2-10,top:(e.offsetY+40||e.originalEvent.layerY)-c.height()-80})}),map||(map=new Datamap({element:document.getElementById("resultsMap"),responsive:!0,fills:{defaultFill:"#ffffff",point:"#283F50"},geographyConfig:{highlightFillColor:"#1abc9c",borderColor:"#283F50"},bubblesConfig:{borderColor:"#283F50"}})),$.each(campaign.results,function(e,t){return 0==t.latitude&&0==t.longitude||(newIP=!0,$.each(bubbles,function(e,a){if(a.ip==t.ip)return bubbles[e].radius+=1,newIP=!1,!1}),void(newIP&&bubbles.push({latitude:t.latitude,longitude:t.longitude,name:t.ip,fillKey:"point",radius:2})))}),map.bubbles(bubbles)}$('a[data-toggle="tab"]').on("shown.bs.tab",function(e){"#overview"==$(e.target).attr("href")&&(map||(map=new Datamap({element:document.getElementById("resultsMap"),responsive:!0,fills:{defaultFill:"#ffffff"},geographyConfig:{highlightFillColor:"#1abc9c",borderColor:"#283F50"}})))})}).error(function(){$("#loading").hide(),errorFlash(" Campaign not found!")})}function refresh(){doPoll&&($("#refresh_message").show(),$("#refresh_btn").hide(),poll(),clearTimeout(setRefresh),setRefresh=setTimeout(refresh,6e4))}var map=null,doPoll=!0,statuses={"Email Sent":{slice:"ct-slice-donut-sent",legend:"ct-legend-sent",label:"label-success",icon:"fa-envelope",point:"ct-point-sent"},"Email Opened":{slice:"ct-slice-donut-opened",legend:"ct-legend-opened",label:"label-warning",icon:"fa-envelope",point:"ct-point-opened"},"Clicked Link":{slice:"ct-slice-donut-clicked",legend:"ct-legend-clicked",label:"label-clicked",icon:"fa-mouse-pointer",point:"ct-point-clicked"},Success:{slice:"ct-slice-donut-success",legend:"ct-legend-success",label:"label-danger",icon:"fa-exclamation",point:"ct-point-clicked"},Error:{slice:"ct-slice-donut-error",legend:"ct-legend-error",label:"label-default",icon:"fa-times",point:"ct-point-error"},"Error Sending Email":{slice:"ct-slice-donut-error",legend:"ct-legend-error",label:"label-default",icon:"fa-times",point:"ct-point-error"},"Submitted Data":{slice:"ct-slice-donut-success",legend:"ct-legend-success",label:"label-danger",icon:"fa-exclamation",point:"ct-point-clicked"},Unknown:{slice:"ct-slice-donut-error",legend:"ct-legend-error",label:"label-default",icon:"fa-question",point:"ct-point-error"},Sending:{slice:"ct-slice-donut-sending",legend:"ct-legend-sending",label:"label-primary",icon:"fa-spinner",point:"ct-point-sending"},"Campaign Created":{label:"label-success",icon:"fa-rocket"}},campaign={},bubbles=[],setRefresh;$(document).ready(function(){load(),setRefresh=setTimeout(refresh,6e4)}); \ No newline at end of file diff --git a/static/js/src/app/campaign_results.js b/static/js/src/app/campaign_results.js index 0b65d33f..6b099377 100644 --- a/static/js/src/app/campaign_results.js +++ b/static/js/src/app/campaign_results.js @@ -1,691 +1,700 @@ -var map = null -var doPoll = true; - -// statuses is a helper map to point result statuses to ui classes -var statuses = { - "Email Sent": { - slice: "ct-slice-donut-sent", - legend: "ct-legend-sent", - label: "label-success", - icon: "fa-envelope", - point: "ct-point-sent" - }, - "Email Opened": { - slice: "ct-slice-donut-opened", - legend: "ct-legend-opened", - label: "label-warning", - icon: "fa-envelope", - point: "ct-point-opened" - }, - "Clicked Link": { - slice: "ct-slice-donut-clicked", - legend: "ct-legend-clicked", - label: "label-clicked", - icon: "fa-mouse-pointer", - point: "ct-point-clicked" - }, - "Success": { - slice: "ct-slice-donut-success", - legend: "ct-legend-success", - label: "label-danger", - icon: "fa-exclamation", - point: "ct-point-clicked" - }, - "Error": { - slice: "ct-slice-donut-error", - legend: "ct-legend-error", - label: "label-default", - icon: "fa-times", - point: "ct-point-error" - }, - "Error Sending Email": { - slice: "ct-slice-donut-error", - legend: "ct-legend-error", - label: "label-default", - icon: "fa-times", - point: "ct-point-error" - }, - "Submitted Data": { - slice: "ct-slice-donut-success", - legend: "ct-legend-success", - label: "label-danger", - icon: "fa-exclamation", - point: "ct-point-clicked" - }, - "Unknown": { - slice: "ct-slice-donut-error", - legend: "ct-legend-error", - label: "label-default", - icon: "fa-question", - point: "ct-point-error" - }, - "Sending": { - slice: "ct-slice-donut-sending", - legend: "ct-legend-sending", - label: "label-primary", - icon: "fa-spinner", - point: "ct-point-sending" - }, - "Campaign Created": { - label: "label-success", - icon: "fa-rocket" - } -} - -var campaign = {} -var bubbles = [] - -function dismiss() { - $("#modal\\.flashes").empty() - $("#modal").modal('hide') - $("#resultsTable").dataTable().DataTable().clear().draw() -} - -// Deletes a campaign after prompting the user -function deleteCampaign() { - swal({ - title: "Are you sure?", - text: "This will delete the campaign. This can't be undone!", - type: "warning", - animation: false, - showCancelButton: true, - confirmButtonText: "Delete Campaign", - confirmButtonColor: "#428bca", - reverseButtons: true, - allowOutsideClick: false, - preConfirm: function() { - return new Promise(function(resolve, reject) { - api.campaignId.delete(campaign.id) - .success(function(msg) { - resolve() - }) - .error(function(data) { - reject(data.responseJSON.message) - }) - }) - } - }).then(function() { - swal( - 'Campaign Deleted!', - 'This campaign has been deleted!', - 'success' - ); - $('button:contains("OK")').on('click', function() { - location.href = '/campaigns' - }) - }) -} - -// Completes a campaign after prompting the user -function completeCampaign() { - swal({ - title: "Are you sure?", - text: "Gophish will stop processing events for this campaign", - type: "warning", - animation: false, - showCancelButton: true, - confirmButtonText: "Complete Campaign", - confirmButtonColor: "#428bca", - reverseButtons: true, - allowOutsideClick: false, - preConfirm: function() { - return new Promise(function(resolve, reject) { - api.campaignId.complete(campaign.id) - .success(function(msg) { - resolve() - }) - .error(function(data) { - reject(data.responseJSON.message) - }) - }) - } - }).then(function() { - swal( - 'Campaign Completed!', - 'This campaign has been completed!', - 'success' - ); - $('#complete_button')[0].disabled = true; - $('#complete_button').text('Completed!') - doPoll = false; - }) -} - -// Exports campaign results as a CSV file -function exportAsCSV(scope) { - exportHTML = $("#exportButton").html() - var csvScope = null - switch (scope) { - case "results": - csvScope = campaign.results - break; - case "events": - csvScope = campaign.timeline - break; - } - if (!csvScope) { - return - } - $("#exportButton").html('') - var csvString = Papa.unparse(csvScope, {}) - var csvData = new Blob([csvString], { - type: 'text/csv;charset=utf-8;' - }); - if (navigator.msSaveBlob) { - navigator.msSaveBlob(csvData, scope + '.csv'); - } else { - var csvURL = window.URL.createObjectURL(csvData); - var dlLink = document.createElement('a'); - dlLink.href = csvURL; - dlLink.setAttribute('download', scope + '.csv'); - document.body.appendChild(dlLink) - dlLink.click(); - document.body.removeChild(dlLink) - } - $("#exportButton").html(exportHTML) -} - -function replay(event_idx) { - request = campaign.timeline[event_idx] - details = JSON.parse(request.details) - url = null - form = $('').attr({ - method: 'POST', - target: '_blank', - }) - /* Create a form object and submit it */ - $.each(Object.keys(details.payload), function(i, param) { - if (param == "rid") { - return true; - } - if (param == "__original_url") { - url = details.payload[param]; - return true; - } - $('').attr({ - name: param, - }).val(details.payload[param]).appendTo(form); - }) - /* Ensure we know where to send the user */ - // Prompt for the URL - swal({ - title: 'Where do you want the credentials submitted to?', - input: 'text', - showCancelButton: true, - inputPlaceholder: "http://example.com/login", - inputValue: url || "", - inputValidator: function(value) { - return new Promise(function(resolve, reject) { - if (value) { - resolve(); - } else { - reject('Invalid URL.'); - } - }); - } - }).then(function(result) { - url = result - submitForm() - }) - return - submitForm() - - function submitForm() { - form.attr({ - action: url - }) - form.appendTo('body').submit().remove() - } -} - -function renderTimeline(data) { - record = { - "first_name": data[2], - "last_name": data[3], - "email": data[4], - "position": data[5] - } - results = '
    ' + - '
    Timeline for ' + escapeHtml(record.first_name) + ' ' + escapeHtml(record.last_name) + - '
    Email: ' + escapeHtml(record.email) + '' + - '
    ' - $.each(campaign.timeline, function(i, event) { - if (!event.email || event.email == record.email) { - // Add the event - results += '
    ' + - '
    ' - results += - '
    ' + - '
    ' + - '
    ' + escapeHtml(event.message) + - ' ' + moment(event.time).format('MMMM Do YYYY h:mm a') + '' - if (event.details) { - if (event.message == "Submitted Data") { - results += '
    ' - results += '
    View Details
    ' - } - details = JSON.parse(event.details) - if (details.payload) { - results += '
    ' - results += ' ' - results += ' ' - $.each(Object.keys(details.payload), function(i, param) { - if (param == "rid") { - return true; - } - results += ' ' - results += ' ' - results += ' ' - results += ' ' - }) - results += '
    ParameterValue(s)
    ' + escapeHtml(param) + '' + escapeHtml(details.payload[param]) + '
    ' - results += '
    ' - } - if (details.error) { - results += '
    View Details
    ' - results += '
    ' - results += 'Error ' + details.error - results += '
    ' - } - } - results += '
    ' - } - }) - results += '
    ' - return results -} - - -/* poll - Queries the API and updates the UI with the results - * - * Updates: - * * Timeline Chart - * * Email (Donut) Chart - * * Map Bubbles - * * Datatables - */ -function poll() { - api.campaignId.results(campaign.id) - .success(function(c) { - campaign = c - /* Update the timeline */ - var timeline_data = { - series: [{ - name: "Events", - data: [] - }] - } - $.each(campaign.timeline, function(i, event) { - timeline_data.series[0].data.push({ - meta: i, - x: new Date(event.time), - y: 1 - }) - }) - var timeline_chart = $("#timeline_chart") - if (timeline_chart.get(0).__chartist__) { - timeline_chart.get(0).__chartist__.update(timeline_data) - } - /* Update the results donut chart */ - var email_data = { - series: [] - } - var email_series_data = {} - $.each(campaign.results, function(i, result) { - if (!email_series_data[result.status]) { - email_series_data[result.status] = 1 - } else { - email_series_data[result.status]++; - } - }) - $("#email_chart_legend").html("") - $.each(email_series_data, function(status, count) { - email_data.series.push({ - meta: status, - value: count - }) - $("#email_chart_legend").append('
  • ' + status + '
  • ') - }) - var email_chart = $("#email_chart") - if (email_chart.get(0).__chartist__) { - email_chart.get(0).__chartist__.on('draw', function(data) { - data.element.addClass(statuses[data.meta].slice) - }) - // Update with the latest data - email_chart.get(0).__chartist__.update(email_data) - } - /* Update the datatable */ - resultsTable = $("#resultsTable").DataTable() - resultsTable.rows().every(function(i, tableLoop, rowLoop) { - var row = this.row(i) - var rowData = row.data() - var rid = rowData[0] - $.each(campaign.results, function(j, result) { - if (result.id == rid) { - var label = statuses[result.status].label || "label-default"; - rowData[6] = "" + result.status + "" - resultsTable.row(i).data(rowData).draw(false) - if (row.child.isShown()) { - row.child(renderTimeline(row.data())) - } - return false - } - }) - }) - /* Update the map information */ - bubbles = [] - $.each(campaign.results, function(i, result) { - // Check that it wasn't an internal IP - if (result.latitude == 0 && result.longitude == 0) { - return true; - } - newIP = true - $.each(bubbles, function(i, bubble) { - if (bubble.ip == result.ip) { - bubbles[i].radius += 1 - newIP = false - return false - } - }) - if (newIP) { - bubbles.push({ - latitude: result.latitude, - longitude: result.longitude, - name: result.ip, - fillKey: "point", - radius: 2 - }) - } - }) - map.bubbles(bubbles) - }) -} - -function load() { - campaign.id = window.location.pathname.split('/').slice(-1)[0] - api.campaignId.results(campaign.id) - .success(function(c) { - campaign = c - if (campaign) { - $("title").text(c.name + " - Gophish") - $("#loading").hide() - $("#campaignResults").show() - // Set the title - $("#page-title").text("Results for " + c.name) - if (c.status == "Completed") { - $('#complete_button')[0].disabled = true; - $('#complete_button').text('Completed!'); - doPoll = false; - } - // Setup tooltips - $('[data-toggle="tooltip"]').tooltip() - // Setup viewing the details of a result - $("#resultsTable").on("click", ".timeline-event-details", function() { - // Show the parameters - payloadResults = $(this).parent().find(".timeline-event-results") - if (payloadResults.is(":visible")) { - $(this).find("i").removeClass("fa-caret-down") - $(this).find("i").addClass("fa-caret-right") - payloadResults.hide() - } else { - $(this).find("i").removeClass("fa-caret-right") - $(this).find("i").addClass("fa-caret-down") - payloadResults.show() - } - }) - // Setup our graphs - var timeline_data = { - series: [{ - name: "Events", - data: [] - }] - } - var email_data = { - series: [] - } - var email_legend = {} - var email_series_data = {} - var timeline_opts = { - axisX: { - showGrid: false, - type: Chartist.FixedScaleAxis, - divisor: 5, - labelInterpolationFnc: function(value) { - return moment(value).format('MMMM Do YYYY h:mm a') - } - }, - axisY: { - type: Chartist.FixedScaleAxis, - ticks: [0, 1, 2], - low: 0, - showLabel: false - }, - showArea: false, - plugins: [] - } - var email_opts = { - donut: true, - donutWidth: 40, - chartPadding: 0, - showLabel: false - } - // Setup the results table - resultsTable = $("#resultsTable").DataTable({ - destroy: true, - "order": [ - [2, "asc"] - ], - columnDefs: [{ - orderable: false, - targets: "no-sort" - }, { - className: "details-control", - "targets": [1] - }, { - "visible": false, - "targets": [0] - }] - }); - resultsTable.clear(); - $.each(campaign.results, function(i, result) { - label = statuses[result.status].label || "label-default"; - resultsTable.row.add([ - result.id, - "", - escapeHtml(result.first_name) || "", - escapeHtml(result.last_name) || "", - escapeHtml(result.email) || "", - escapeHtml(result.position) || "", - "" + result.status + "" - ]).draw() - if (!email_series_data[result.status]) { - email_series_data[result.status] = 1 - } else { - email_series_data[result.status]++; - } - }) - // Setup the individual timelines - $('#resultsTable tbody').on('click', 'td.details-control', function() { - var tr = $(this).closest('tr'); - var row = resultsTable.row(tr); - if (row.child.isShown()) { - // This row is already open - close it - row.child.hide(); - tr.removeClass('shown'); - $(this).find("i").removeClass("fa-caret-down") - $(this).find("i").addClass("fa-caret-right") - row.invalidate('dom').draw(false) - } else { - // Open this row - $(this).find("i").removeClass("fa-caret-right") - $(this).find("i").addClass("fa-caret-down") - row.child(renderTimeline(row.data())).show(); - tr.addClass('shown'); - row.invalidate('dom').draw(false) - } - }); - // Setup the graphs - $.each(campaign.timeline, function(i, event) { - timeline_data.series[0].data.push({ - meta: i, - x: new Date(event.time), - y: 1 - }) - }) - $("#email_chart_legend").html("") - $.each(email_series_data, function(status, count) { - email_data.series.push({ - meta: status, - value: count - }) - $("#email_chart_legend").append('
  • ' + status + '
  • ') - }) - var timeline_chart = new Chartist.Line('#timeline_chart', timeline_data, timeline_opts) - timeline_chart.on('draw', function(data) { - if (data.type === "point") { - var point_style = statuses[campaign.timeline[data.meta].message].point - var circle = new Chartist.Svg("circle", { - cx: [data.x], - cy: [data.y], - r: 5, - fill: "#283F50", - meta: data.meta, - value: 1, - }, point_style + ' ct-timeline-point') - data.element.replace(circle) - } - }) - // Setup the overview chart listeners - $chart = $("#timeline_chart") - var $toolTip = $chart - .append('
    ') - .find('.chartist-tooltip') - .hide(); - $chart.on('mouseenter', '.ct-timeline-point', function() { - var $point = $(this) - cidx = $point.attr('meta') - html = "Event: " + campaign.timeline[cidx].message - if (campaign.timeline[cidx].email) { - html += '
    ' + "Email: " + escapeHtml(campaign.timeline[cidx].email) - } - $toolTip.html(html).show() - }); - $chart.on('mouseleave', '.ct-timeline-point', function() { - $toolTip.hide(); - }); - $chart.on('mousemove', function(event) { - $toolTip.css({ - left: (event.offsetX || event.originalEvent.layerX) - $toolTip.width() / 2 - 10, - top: (event.offsetY + 70 || event.originalEvent.layerY) - $toolTip.height() - 40 - }); - }); - - var email_chart = new Chartist.Pie("#email_chart", email_data, email_opts) - email_chart.on('draw', function(data) { - data.element.addClass(statuses[data.meta].slice) - }) - // Setup the average chart listeners - $piechart = $("#email_chart") - var $pietoolTip = $piechart - .append('
    ') - .find('.chartist-tooltip') - .hide(); - - $piechart.on('mouseenter', '.ct-slice-donut', function() { - var $point = $(this) - value = $point.attr('ct:value') - label = $point.attr('ct:meta') - $pietoolTip.html(label + ': ' + value.toString()).show(); - }); - - $piechart.on('mouseleave', '.ct-slice-donut', function() { - $pietoolTip.hide(); - }); - $piechart.on('mousemove', function(event) { - $pietoolTip.css({ - left: (event.offsetX || event.originalEvent.layerX) - $pietoolTip.width() / 2 - 10, - top: (event.offsetY + 40 || event.originalEvent.layerY) - $pietoolTip.height() - 80 - }); - }); - if (!map) { - map = new Datamap({ - element: document.getElementById("resultsMap"), - responsive: true, - fills: { - defaultFill: "#ffffff", - point: "#283F50" - }, - geographyConfig: { - highlightFillColor: "#1abc9c", - borderColor: "#283F50" - }, - bubblesConfig: { - borderColor: "#283F50" - } - }); - } - $.each(campaign.results, function(i, result) { - // Check that it wasn't an internal IP - if (result.latitude == 0 && result.longitude == 0) { - return true; - } - newIP = true - $.each(bubbles, function(i, bubble) { - if (bubble.ip == result.ip) { - bubbles[i].radius += 1 - newIP = false - return false - } - }) - if (newIP) { - bubbles.push({ - latitude: result.latitude, - longitude: result.longitude, - name: result.ip, - fillKey: "point", - radius: 2 - }) - } - }) - map.bubbles(bubbles) - } - // Load up the map data (only once!) - $('a[data-toggle="tab"]').on('shown.bs.tab', function(e) { - if ($(e.target).attr('href') == "#overview") { - if (!map) { - map = new Datamap({ - element: document.getElementById("resultsMap"), - responsive: true, - fills: { - defaultFill: "#ffffff" - }, - geographyConfig: { - highlightFillColor: "#1abc9c", - borderColor: "#283F50" - } - }); - } - } - }) - }) - .error(function() { - $("#loading").hide() - errorFlash(" Campaign not found!") - }) -} -$(document).ready(function() { - load(); - // Start the polling loop - function refresh() { - if (!doPoll) { - return; - } - $("#refresh_message").show() - poll() - $("#refresh_message").hide() - setTimeout(refresh, 10000) - }; - // Start the polling loop - setTimeout(refresh, 10000) -}) +var map = null +var doPoll = true; + +// statuses is a helper map to point result statuses to ui classes +var statuses = { + "Email Sent": { + slice: "ct-slice-donut-sent", + legend: "ct-legend-sent", + label: "label-success", + icon: "fa-envelope", + point: "ct-point-sent" + }, + "Email Opened": { + slice: "ct-slice-donut-opened", + legend: "ct-legend-opened", + label: "label-warning", + icon: "fa-envelope", + point: "ct-point-opened" + }, + "Clicked Link": { + slice: "ct-slice-donut-clicked", + legend: "ct-legend-clicked", + label: "label-clicked", + icon: "fa-mouse-pointer", + point: "ct-point-clicked" + }, + "Success": { + slice: "ct-slice-donut-success", + legend: "ct-legend-success", + label: "label-danger", + icon: "fa-exclamation", + point: "ct-point-clicked" + }, + "Error": { + slice: "ct-slice-donut-error", + legend: "ct-legend-error", + label: "label-default", + icon: "fa-times", + point: "ct-point-error" + }, + "Error Sending Email": { + slice: "ct-slice-donut-error", + legend: "ct-legend-error", + label: "label-default", + icon: "fa-times", + point: "ct-point-error" + }, + "Submitted Data": { + slice: "ct-slice-donut-success", + legend: "ct-legend-success", + label: "label-danger", + icon: "fa-exclamation", + point: "ct-point-clicked" + }, + "Unknown": { + slice: "ct-slice-donut-error", + legend: "ct-legend-error", + label: "label-default", + icon: "fa-question", + point: "ct-point-error" + }, + "Sending": { + slice: "ct-slice-donut-sending", + legend: "ct-legend-sending", + label: "label-primary", + icon: "fa-spinner", + point: "ct-point-sending" + }, + "Campaign Created": { + label: "label-success", + icon: "fa-rocket" + } +} + +var campaign = {} +var bubbles = [] + +function dismiss() { + $("#modal\\.flashes").empty() + $("#modal").modal('hide') + $("#resultsTable").dataTable().DataTable().clear().draw() +} + +// Deletes a campaign after prompting the user +function deleteCampaign() { + swal({ + title: "Are you sure?", + text: "This will delete the campaign. This can't be undone!", + type: "warning", + animation: false, + showCancelButton: true, + confirmButtonText: "Delete Campaign", + confirmButtonColor: "#428bca", + reverseButtons: true, + allowOutsideClick: false, + preConfirm: function() { + return new Promise(function(resolve, reject) { + api.campaignId.delete(campaign.id) + .success(function(msg) { + resolve() + }) + .error(function(data) { + reject(data.responseJSON.message) + }) + }) + } + }).then(function() { + swal( + 'Campaign Deleted!', + 'This campaign has been deleted!', + 'success' + ); + $('button:contains("OK")').on('click', function() { + location.href = '/campaigns' + }) + }) +} + +// Completes a campaign after prompting the user +function completeCampaign() { + swal({ + title: "Are you sure?", + text: "Gophish will stop processing events for this campaign", + type: "warning", + animation: false, + showCancelButton: true, + confirmButtonText: "Complete Campaign", + confirmButtonColor: "#428bca", + reverseButtons: true, + allowOutsideClick: false, + preConfirm: function() { + return new Promise(function(resolve, reject) { + api.campaignId.complete(campaign.id) + .success(function(msg) { + resolve() + }) + .error(function(data) { + reject(data.responseJSON.message) + }) + }) + } + }).then(function() { + swal( + 'Campaign Completed!', + 'This campaign has been completed!', + 'success' + ); + $('#complete_button')[0].disabled = true; + $('#complete_button').text('Completed!') + doPoll = false; + }) +} + +// Exports campaign results as a CSV file +function exportAsCSV(scope) { + exportHTML = $("#exportButton").html() + var csvScope = null + switch (scope) { + case "results": + csvScope = campaign.results + break; + case "events": + csvScope = campaign.timeline + break; + } + if (!csvScope) { + return + } + $("#exportButton").html('') + var csvString = Papa.unparse(csvScope, {}) + var csvData = new Blob([csvString], { + type: 'text/csv;charset=utf-8;' + }); + if (navigator.msSaveBlob) { + navigator.msSaveBlob(csvData, scope + '.csv'); + } else { + var csvURL = window.URL.createObjectURL(csvData); + var dlLink = document.createElement('a'); + dlLink.href = csvURL; + dlLink.setAttribute('download', scope + '.csv'); + document.body.appendChild(dlLink) + dlLink.click(); + document.body.removeChild(dlLink) + } + $("#exportButton").html(exportHTML) +} + +function replay(event_idx) { + request = campaign.timeline[event_idx] + details = JSON.parse(request.details) + url = null + form = $('').attr({ + method: 'POST', + target: '_blank', + }) + /* Create a form object and submit it */ + $.each(Object.keys(details.payload), function(i, param) { + if (param == "rid") { + return true; + } + if (param == "__original_url") { + url = details.payload[param]; + return true; + } + $('').attr({ + name: param, + }).val(details.payload[param]).appendTo(form); + }) + /* Ensure we know where to send the user */ + // Prompt for the URL + swal({ + title: 'Where do you want the credentials submitted to?', + input: 'text', + showCancelButton: true, + inputPlaceholder: "http://example.com/login", + inputValue: url || "", + inputValidator: function(value) { + return new Promise(function(resolve, reject) { + if (value) { + resolve(); + } else { + reject('Invalid URL.'); + } + }); + } + }).then(function(result) { + url = result + submitForm() + }) + return + submitForm() + + function submitForm() { + form.attr({ + action: url + }) + form.appendTo('body').submit().remove() + } +} + +function renderTimeline(data) { + record = { + "first_name": data[2], + "last_name": data[3], + "email": data[4], + "position": data[5] + } + results = '
    ' + + '
    Timeline for ' + escapeHtml(record.first_name) + ' ' + escapeHtml(record.last_name) + + '
    Email: ' + escapeHtml(record.email) + '' + + '
    ' + $.each(campaign.timeline, function(i, event) { + if (!event.email || event.email == record.email) { + // Add the event + results += '
    ' + + '
    ' + results += + '
    ' + + '
    ' + + '
    ' + escapeHtml(event.message) + + ' ' + moment(event.time).format('MMMM Do YYYY h:mm a') + '' + if (event.details) { + if (event.message == "Submitted Data") { + results += '
    ' + results += '
    View Details
    ' + } + details = JSON.parse(event.details) + if (details.payload) { + results += '
    ' + results += ' ' + results += ' ' + $.each(Object.keys(details.payload), function(i, param) { + if (param == "rid") { + return true; + } + results += ' ' + results += ' ' + results += ' ' + results += ' ' + }) + results += '
    ParameterValue(s)
    ' + escapeHtml(param) + '' + escapeHtml(details.payload[param]) + '
    ' + results += '
    ' + } + if (details.error) { + results += '
    View Details
    ' + results += '
    ' + results += 'Error ' + details.error + results += '
    ' + } + } + results += '
    ' + } + }) + results += '
    ' + return results +} + + +/* poll - Queries the API and updates the UI with the results + * + * Updates: + * * Timeline Chart + * * Email (Donut) Chart + * * Map Bubbles + * * Datatables + */ +function poll() { + api.campaignId.results(campaign.id) + .success(function(c) { + campaign = c + /* Update the timeline */ + var timeline_data = { + series: [{ + name: "Events", + data: [] + }] + } + $.each(campaign.timeline, function(i, event) { + timeline_data.series[0].data.push({ + meta: i, + x: new Date(event.time), + y: 1 + }) + }) + var timeline_chart = $("#timeline_chart") + if (timeline_chart.get(0).__chartist__) { + timeline_chart.get(0).__chartist__.update(timeline_data) + } + /* Update the results donut chart */ + var email_data = { + series: [] + } + var email_series_data = {} + $.each(campaign.results, function(i, result) { + if (!email_series_data[result.status]) { + email_series_data[result.status] = 1 + } else { + email_series_data[result.status]++; + } + }) + $("#email_chart_legend").html("") + $.each(email_series_data, function(status, count) { + email_data.series.push({ + meta: status, + value: count + }) + $("#email_chart_legend").append('
  • ' + status + '
  • ') + }) + var email_chart = $("#email_chart") + if (email_chart.get(0).__chartist__) { + email_chart.get(0).__chartist__.on('draw', function(data) { + data.element.addClass(statuses[data.meta].slice) + }) + // Update with the latest data + email_chart.get(0).__chartist__.update(email_data) + } + /* Update the datatable */ + resultsTable = $("#resultsTable").DataTable() + resultsTable.rows().every(function(i, tableLoop, rowLoop) { + var row = this.row(i) + var rowData = row.data() + var rid = rowData[0] + $.each(campaign.results, function(j, result) { + if (result.id == rid) { + var label = statuses[result.status].label || "label-default"; + rowData[6] = "" + result.status + "" + resultsTable.row(i).data(rowData).draw(false) + if (row.child.isShown()) { + row.child(renderTimeline(row.data())) + } + return false + } + }) + }) + /* Update the map information */ + bubbles = [] + $.each(campaign.results, function(i, result) { + // Check that it wasn't an internal IP + if (result.latitude == 0 && result.longitude == 0) { + return true; + } + newIP = true + $.each(bubbles, function(i, bubble) { + if (bubble.ip == result.ip) { + bubbles[i].radius += 1 + newIP = false + return false + } + }) + if (newIP) { + bubbles.push({ + latitude: result.latitude, + longitude: result.longitude, + name: result.ip, + fillKey: "point", + radius: 2 + }) + } + }) + map.bubbles(bubbles) + $("#refresh_message").hide() + $("#refresh_btn").show() + }) +} + +function load() { + campaign.id = window.location.pathname.split('/').slice(-1)[0] + api.campaignId.results(campaign.id) + .success(function(c) { + campaign = c + if (campaign) { + $("title").text(c.name + " - Gophish") + $("#loading").hide() + $("#campaignResults").show() + // Set the title + $("#page-title").text("Results for " + c.name) + if (c.status == "Completed") { + $('#complete_button')[0].disabled = true; + $('#complete_button').text('Completed!'); + doPoll = false; + } + // Setup tooltips + $('[data-toggle="tooltip"]').tooltip() + // Setup viewing the details of a result + $("#resultsTable").on("click", ".timeline-event-details", function() { + // Show the parameters + payloadResults = $(this).parent().find(".timeline-event-results") + if (payloadResults.is(":visible")) { + $(this).find("i").removeClass("fa-caret-down") + $(this).find("i").addClass("fa-caret-right") + payloadResults.hide() + } else { + $(this).find("i").removeClass("fa-caret-right") + $(this).find("i").addClass("fa-caret-down") + payloadResults.show() + } + }) + // Setup our graphs + var timeline_data = { + series: [{ + name: "Events", + data: [] + }] + } + var email_data = { + series: [] + } + var email_legend = {} + var email_series_data = {} + var timeline_opts = { + axisX: { + showGrid: false, + type: Chartist.FixedScaleAxis, + divisor: 5, + labelInterpolationFnc: function(value) { + return moment(value).format('MMMM Do YYYY h:mm a') + } + }, + axisY: { + type: Chartist.FixedScaleAxis, + ticks: [0, 1, 2], + low: 0, + showLabel: false + }, + showArea: false, + plugins: [] + } + var email_opts = { + donut: true, + donutWidth: 40, + chartPadding: 0, + showLabel: false + } + // Setup the results table + resultsTable = $("#resultsTable").DataTable({ + destroy: true, + "order": [ + [2, "asc"] + ], + columnDefs: [{ + orderable: false, + targets: "no-sort" + }, { + className: "details-control", + "targets": [1] + }, { + "visible": false, + "targets": [0] + }] + }); + resultsTable.clear(); + $.each(campaign.results, function(i, result) { + label = statuses[result.status].label || "label-default"; + resultsTable.row.add([ + result.id, + "", + escapeHtml(result.first_name) || "", + escapeHtml(result.last_name) || "", + escapeHtml(result.email) || "", + escapeHtml(result.position) || "", + "" + result.status + "" + ]).draw() + if (!email_series_data[result.status]) { + email_series_data[result.status] = 1 + } else { + email_series_data[result.status]++; + } + }) + // Setup the individual timelines + $('#resultsTable tbody').on('click', 'td.details-control', function() { + var tr = $(this).closest('tr'); + var row = resultsTable.row(tr); + if (row.child.isShown()) { + // This row is already open - close it + row.child.hide(); + tr.removeClass('shown'); + $(this).find("i").removeClass("fa-caret-down") + $(this).find("i").addClass("fa-caret-right") + row.invalidate('dom').draw(false) + } else { + // Open this row + $(this).find("i").removeClass("fa-caret-right") + $(this).find("i").addClass("fa-caret-down") + row.child(renderTimeline(row.data())).show(); + tr.addClass('shown'); + row.invalidate('dom').draw(false) + } + }); + // Setup the graphs + $.each(campaign.timeline, function(i, event) { + timeline_data.series[0].data.push({ + meta: i, + x: new Date(event.time), + y: 1 + }) + }) + $("#email_chart_legend").html("") + $.each(email_series_data, function(status, count) { + email_data.series.push({ + meta: status, + value: count + }) + $("#email_chart_legend").append('
  • ' + status + '
  • ') + }) + var timeline_chart = new Chartist.Line('#timeline_chart', timeline_data, timeline_opts) + timeline_chart.on('draw', function(data) { + if (data.type === "point") { + var point_style = statuses[campaign.timeline[data.meta].message].point + var circle = new Chartist.Svg("circle", { + cx: [data.x], + cy: [data.y], + r: 5, + fill: "#283F50", + meta: data.meta, + value: 1, + }, point_style + ' ct-timeline-point') + data.element.replace(circle) + } + }) + // Setup the overview chart listeners + $chart = $("#timeline_chart") + var $toolTip = $chart + .append('
    ') + .find('.chartist-tooltip') + .hide(); + $chart.on('mouseenter', '.ct-timeline-point', function() { + var $point = $(this) + cidx = $point.attr('meta') + html = "Event: " + campaign.timeline[cidx].message + if (campaign.timeline[cidx].email) { + html += '
    ' + "Email: " + escapeHtml(campaign.timeline[cidx].email) + } + $toolTip.html(html).show() + }); + $chart.on('mouseleave', '.ct-timeline-point', function() { + $toolTip.hide(); + }); + $chart.on('mousemove', function(event) { + $toolTip.css({ + left: (event.offsetX || event.originalEvent.layerX) - $toolTip.width() / 2 - 10, + top: (event.offsetY + 70 || event.originalEvent.layerY) - $toolTip.height() - 40 + }); + }); + + var email_chart = new Chartist.Pie("#email_chart", email_data, email_opts) + email_chart.on('draw', function(data) { + data.element.addClass(statuses[data.meta].slice) + }) + // Setup the average chart listeners + $piechart = $("#email_chart") + var $pietoolTip = $piechart + .append('
    ') + .find('.chartist-tooltip') + .hide(); + + $piechart.on('mouseenter', '.ct-slice-donut', function() { + var $point = $(this) + value = $point.attr('ct:value') + label = $point.attr('ct:meta') + $pietoolTip.html(label + ': ' + value.toString()).show(); + }); + + $piechart.on('mouseleave', '.ct-slice-donut', function() { + $pietoolTip.hide(); + }); + $piechart.on('mousemove', function(event) { + $pietoolTip.css({ + left: (event.offsetX || event.originalEvent.layerX) - $pietoolTip.width() / 2 - 10, + top: (event.offsetY + 40 || event.originalEvent.layerY) - $pietoolTip.height() - 80 + }); + }); + if (!map) { + map = new Datamap({ + element: document.getElementById("resultsMap"), + responsive: true, + fills: { + defaultFill: "#ffffff", + point: "#283F50" + }, + geographyConfig: { + highlightFillColor: "#1abc9c", + borderColor: "#283F50" + }, + bubblesConfig: { + borderColor: "#283F50" + } + }); + } + $.each(campaign.results, function(i, result) { + // Check that it wasn't an internal IP + if (result.latitude == 0 && result.longitude == 0) { + return true; + } + newIP = true + $.each(bubbles, function(i, bubble) { + if (bubble.ip == result.ip) { + bubbles[i].radius += 1 + newIP = false + return false + } + }) + if (newIP) { + bubbles.push({ + latitude: result.latitude, + longitude: result.longitude, + name: result.ip, + fillKey: "point", + radius: 2 + }) + } + }) + map.bubbles(bubbles) + } + // Load up the map data (only once!) + $('a[data-toggle="tab"]').on('shown.bs.tab', function(e) { + if ($(e.target).attr('href') == "#overview") { + if (!map) { + map = new Datamap({ + element: document.getElementById("resultsMap"), + responsive: true, + fills: { + defaultFill: "#ffffff" + }, + geographyConfig: { + highlightFillColor: "#1abc9c", + borderColor: "#283F50" + } + }); + } + } + }) + }) + .error(function() { + $("#loading").hide() + errorFlash(" Campaign not found!") + }) +} + +var setRefresh +function refresh() { + if (!doPoll) { + return; + } + $("#refresh_message").show() + $("#refresh_btn").hide() + poll() + clearTimeout(setRefresh) + setRefresh = setTimeout(refresh, 60000) +}; + + + +$(document).ready(function() { + load(); + // Start the polling loop + + // Start the polling loop + setRefresh = setTimeout(refresh, 60000) +}) diff --git a/templates/campaign_results.html b/templates/campaign_results.html index 6cb998a7..3f43cd32 100644 --- a/templates/campaign_results.html +++ b/templates/campaign_results.html @@ -54,6 +54,9 @@ + Refreshing