github.com/Ne0nd0g/gophish@v0.7.1-0.20190220040016-11493024a07d/static/js/src/app/campaigns.js (about) 1 // labels is a map of campaign statuses to 2 // CSS classes 3 var labels = { 4 "In progress": "label-primary", 5 "Queued": "label-info", 6 "Completed": "label-success", 7 "Emails Sent": "label-success", 8 "Error": "label-danger" 9 } 10 11 var campaigns = [] 12 var campaign = {} 13 14 // Launch attempts to POST to /campaigns/ 15 function launch() { 16 swal({ 17 title: "Are you sure?", 18 text: "This will schedule the campaign to be launched.", 19 type: "question", 20 animation: false, 21 showCancelButton: true, 22 confirmButtonText: "Launch", 23 confirmButtonColor: "#428bca", 24 reverseButtons: true, 25 allowOutsideClick: false, 26 showLoaderOnConfirm: true, 27 preConfirm: function () { 28 return new Promise(function (resolve, reject) { 29 groups = [] 30 $("#users").select2("data").forEach(function (group) { 31 groups.push({ 32 name: group.text 33 }); 34 }) 35 // Validate our fields 36 var send_by_date = $("#send_by_date").val() 37 if (send_by_date != "") { 38 send_by_date = moment(send_by_date, "MMMM Do YYYY, h:mm a").utc().format() 39 } 40 campaign = { 41 name: $("#name").val(), 42 template: { 43 name: $("#template").select2("data")[0].text 44 }, 45 url: $("#url").val(), 46 page: { 47 name: $("#page").select2("data")[0].text 48 }, 49 smtp: { 50 name: $("#profile").select2("data")[0].text 51 }, 52 launch_date: moment($("#launch_date").val(), "MMMM Do YYYY, h:mm a").utc().format(), 53 send_by_date: send_by_date || null, 54 groups: groups, 55 } 56 // Submit the campaign 57 api.campaigns.post(campaign) 58 .success(function (data) { 59 resolve() 60 campaign = data 61 }) 62 .error(function (data) { 63 $("#modal\\.flashes").empty().append("<div style=\"text-align:center\" class=\"alert alert-danger\">\ 64 <i class=\"fa fa-exclamation-circle\"></i> " + data.responseJSON.message + "</div>") 65 swal.close() 66 }) 67 }) 68 } 69 }).then(function () { 70 swal( 71 'Campaign Scheduled!', 72 'This campaign has been scheduled for launch!', 73 'success' 74 ); 75 $('button:contains("OK")').on('click', function () { 76 window.location = "/campaigns/" + campaign.id.toString() 77 }) 78 }) 79 } 80 81 // Attempts to send a test email by POSTing to /campaigns/ 82 function sendTestEmail() { 83 var test_email_request = { 84 template: { 85 name: $("#template").select2("data")[0].text 86 }, 87 first_name: $("input[name=to_first_name]").val(), 88 last_name: $("input[name=to_last_name]").val(), 89 email: $("input[name=to_email]").val(), 90 position: $("input[name=to_position]").val(), 91 url: $("#url").val(), 92 page: { 93 name: $("#page").select2("data")[0].text 94 }, 95 smtp: { 96 name: $("#profile").select2("data")[0].text 97 } 98 } 99 btnHtml = $("#sendTestModalSubmit").html() 100 $("#sendTestModalSubmit").html('<i class="fa fa-spinner fa-spin"></i> Sending') 101 // Send the test email 102 api.send_test_email(test_email_request) 103 .success(function (data) { 104 $("#sendTestEmailModal\\.flashes").empty().append("<div style=\"text-align:center\" class=\"alert alert-success\">\ 105 <i class=\"fa fa-check-circle\"></i> Email Sent!</div>") 106 $("#sendTestModalSubmit").html(btnHtml) 107 }) 108 .error(function (data) { 109 $("#sendTestEmailModal\\.flashes").empty().append("<div style=\"text-align:center\" class=\"alert alert-danger\">\ 110 <i class=\"fa fa-exclamation-circle\"></i> " + data.responseJSON.message + "</div>") 111 $("#sendTestModalSubmit").html(btnHtml) 112 }) 113 } 114 115 function dismiss() { 116 $("#modal\\.flashes").empty(); 117 $("#name").val(""); 118 $("#template").val("").change(); 119 $("#page").val("").change(); 120 $("#url").val(""); 121 $("#profile").val("").change(); 122 $("#users").val("").change(); 123 $("#modal").modal('hide'); 124 } 125 126 function deleteCampaign(idx) { 127 swal({ 128 title: "Are you sure?", 129 text: "This will delete the campaign. This can't be undone!", 130 type: "warning", 131 animation: false, 132 showCancelButton: true, 133 confirmButtonText: "Delete " + campaigns[idx].name, 134 confirmButtonColor: "#428bca", 135 reverseButtons: true, 136 allowOutsideClick: false, 137 preConfirm: function () { 138 return new Promise(function (resolve, reject) { 139 api.campaignId.delete(campaigns[idx].id) 140 .success(function (msg) { 141 resolve() 142 }) 143 .error(function (data) { 144 reject(data.responseJSON.message) 145 }) 146 }) 147 } 148 }).then(function () { 149 swal( 150 'Campaign Deleted!', 151 'This campaign has been deleted!', 152 'success' 153 ); 154 $('button:contains("OK")').on('click', function () { 155 location.reload() 156 }) 157 }) 158 } 159 160 function setupOptions() { 161 api.groups.get() 162 .success(function (groups) { 163 if (groups.length == 0) { 164 modalError("No groups found!") 165 return false; 166 } else { 167 var group_s2 = $.map(groups, function (obj) { 168 obj.text = obj.name 169 return obj 170 }); 171 $("#users.form-control").select2({ 172 placeholder: "Select Groups", 173 data: group_s2, 174 }); 175 } 176 }); 177 api.templates.get() 178 .success(function (templates) { 179 if (templates.length == 0) { 180 modalError("No templates found!") 181 return false 182 } else { 183 var template_s2 = $.map(templates, function (obj) { 184 obj.text = obj.name 185 return obj 186 }); 187 var template_select = $("#template.form-control") 188 template_select.select2({ 189 placeholder: "Select a Template", 190 data: template_s2, 191 }); 192 if (templates.length === 1) { 193 template_select.val(template_s2[0].id) 194 template_select.trigger('change.select2') 195 } 196 } 197 }); 198 api.pages.get() 199 .success(function (pages) { 200 if (pages.length == 0) { 201 modalError("No pages found!") 202 return false 203 } else { 204 var page_s2 = $.map(pages, function (obj) { 205 obj.text = obj.name 206 return obj 207 }); 208 var page_select = $("#page.form-control") 209 page_select.select2({ 210 placeholder: "Select a Landing Page", 211 data: page_s2, 212 }); 213 if (pages.length === 1) { 214 page_select.val(page_s2[0].id) 215 page_select.trigger('change.select2') 216 } 217 } 218 }); 219 api.SMTP.get() 220 .success(function (profiles) { 221 if (profiles.length == 0) { 222 modalError("No profiles found!") 223 return false 224 } else { 225 var profile_s2 = $.map(profiles, function (obj) { 226 obj.text = obj.name 227 return obj 228 }); 229 var profile_select = $("#profile.form-control") 230 profile_select.select2({ 231 placeholder: "Select a Sending Profile", 232 data: profile_s2, 233 }).select2("val", profile_s2[0]); 234 if (profiles.length === 1) { 235 profile_select.val(profile_s2[0].id) 236 profile_select.trigger('change.select2') 237 } 238 } 239 }); 240 } 241 242 function edit(campaign) { 243 setupOptions(); 244 } 245 246 function copy(idx) { 247 setupOptions(); 248 // Set our initial values 249 api.campaignId.get(campaigns[idx].id) 250 .success(function (campaign) { 251 $("#name").val("Copy of " + campaign.name) 252 if (!campaign.template.id) { 253 $("#template").select2({ 254 placeholder: campaign.template.name 255 }); 256 } else { 257 $("#template").val(campaign.template.id.toString()); 258 $("#template").trigger("change.select2") 259 } 260 if (!campaign.page.id) { 261 $("#page").select2({ 262 placeholder: campaign.page.name 263 }); 264 } else { 265 $("#page").val(campaign.page.id.toString()); 266 $("#page").trigger("change.select2") 267 } 268 if (!campaign.smtp.id) { 269 $("#profile").select2({ 270 placeholder: campaign.smtp.name 271 }); 272 } else { 273 $("#profile").val(campaign.smtp.id.toString()); 274 $("#profile").trigger("change.select2") 275 } 276 $("#url").val(campaign.url) 277 }) 278 .error(function (data) { 279 $("#modal\\.flashes").empty().append("<div style=\"text-align:center\" class=\"alert alert-danger\">\ 280 <i class=\"fa fa-exclamation-circle\"></i> " + data.responseJSON.message + "</div>") 281 }) 282 } 283 284 $(document).ready(function () { 285 $("#launch_date").datetimepicker({ 286 "widgetPositioning": { 287 "vertical": "bottom" 288 }, 289 "showTodayButton": true, 290 "defaultDate": moment(), 291 "format": "MMMM Do YYYY, h:mm a" 292 }) 293 $("#send_by_date").datetimepicker({ 294 "widgetPositioning": { 295 "vertical": "bottom" 296 }, 297 "showTodayButton": true, 298 "useCurrent": false, 299 "format": "MMMM Do YYYY, h:mm a" 300 }) 301 // Setup multiple modals 302 // Code based on http://miles-by-motorcycle.com/static/bootstrap-modal/index.html 303 $('.modal').on('hidden.bs.modal', function (event) { 304 $(this).removeClass('fv-modal-stack'); 305 $('body').data('fv_open_modals', $('body').data('fv_open_modals') - 1); 306 }); 307 $('.modal').on('shown.bs.modal', function (event) { 308 // Keep track of the number of open modals 309 if (typeof ($('body').data('fv_open_modals')) == 'undefined') { 310 $('body').data('fv_open_modals', 0); 311 } 312 // if the z-index of this modal has been set, ignore. 313 if ($(this).hasClass('fv-modal-stack')) { 314 return; 315 } 316 $(this).addClass('fv-modal-stack'); 317 // Increment the number of open modals 318 $('body').data('fv_open_modals', $('body').data('fv_open_modals') + 1); 319 // Setup the appropriate z-index 320 $(this).css('z-index', 1040 + (10 * $('body').data('fv_open_modals'))); 321 $('.modal-backdrop').not('.fv-modal-stack').css('z-index', 1039 + (10 * $('body').data('fv_open_modals'))); 322 $('.modal-backdrop').not('fv-modal-stack').addClass('fv-modal-stack'); 323 }); 324 // Scrollbar fix - https://stackoverflow.com/questions/19305821/multiple-modals-overlay 325 $(document).on('hidden.bs.modal', '.modal', function () { 326 $('.modal:visible').length && $(document.body).addClass('modal-open'); 327 }); 328 $('#modal').on('hidden.bs.modal', function (event) { 329 dismiss() 330 }); 331 api.campaigns.summary() 332 .success(function (data) { 333 campaigns = data.campaigns 334 $("#loading").hide() 335 if (campaigns.length > 0) { 336 $("#campaignTable").show() 337 $("#campaignTableArchive").show() 338 339 campaignTableOriginal = $("#campaignTable").DataTable({ 340 columnDefs: [{ 341 orderable: false, 342 targets: "no-sort" 343 }], 344 order: [ 345 [1, "desc"] 346 ] 347 }); 348 campaignTableArchive = $("#campaignTableArchive").DataTable({ 349 columnDefs: [{ 350 orderable: false, 351 targets: "no-sort" 352 }], 353 order: [ 354 [1, "desc"] 355 ] 356 }); 357 $.each(campaigns, function (i, campaign) { 358 campaignTable = campaignTableOriginal 359 if (campaign.status === "Completed") { 360 campaignTable = campaignTableArchive 361 } 362 363 label = labels[campaign.status] || "label-default"; 364 365 //section for tooltips on the status of a campaign to show some quick stats 366 var launchDate; 367 if (moment(campaign.launch_date).isAfter(moment())) { 368 launchDate = "Scheduled to start: " + moment(campaign.launch_date).format('MMMM Do YYYY, h:mm:ss a') 369 var quickStats = launchDate + "<br><br>" + "Number of recipients: " + campaign.stats.total 370 } else { 371 launchDate = "Launch Date: " + moment(campaign.launch_date).format('MMMM Do YYYY, h:mm:ss a') 372 var quickStats = launchDate + "<br><br>" + "Number of recipients: " + campaign.stats.total + "<br><br>" + "Emails opened: " + campaign.stats.opened + "<br><br>" + "Emails clicked: " + campaign.stats.clicked + "<br><br>" + "Submitted Credentials: " + campaign.stats.submitted_data + "<br><br>" + "Errors : " + campaign.stats.error + "Reported : " + campaign.stats.reported 373 } 374 375 campaignTable.row.add([ 376 escapeHtml(campaign.name), 377 moment(campaign.created_date).format('MMMM Do YYYY, h:mm:ss a'), 378 "<span class=\"label " + label + "\" data-toggle=\"tooltip\" data-placement=\"right\" data-html=\"true\" title=\"" + quickStats + "\">" + campaign.status + "</span>", 379 "<div class='pull-right'><a class='btn btn-primary' href='/campaigns/" + campaign.id + "' data-toggle='tooltip' data-placement='left' title='View Results'>\ 380 <i class='fa fa-bar-chart'></i>\ 381 </a>\ 382 <span data-toggle='modal' data-backdrop='static' data-target='#modal'><button class='btn btn-primary' data-toggle='tooltip' data-placement='left' title='Copy Campaign' onclick='copy(" + i + ")'>\ 383 <i class='fa fa-copy'></i>\ 384 </button></span>\ 385 <button class='btn btn-danger' onclick='deleteCampaign(" + i + ")' data-toggle='tooltip' data-placement='left' title='Delete Campaign'>\ 386 <i class='fa fa-trash-o'></i>\ 387 </button></div>" 388 ]).draw() 389 $('[data-toggle="tooltip"]').tooltip() 390 }) 391 } else { 392 $("#emptyMessage").show() 393 } 394 }) 395 .error(function () { 396 $("#loading").hide() 397 errorFlash("Error fetching campaigns") 398 }) 399 // Select2 Defaults 400 $.fn.select2.defaults.set("width", "100%"); 401 $.fn.select2.defaults.set("dropdownParent", $("#modal_body")); 402 $.fn.select2.defaults.set("theme", "bootstrap"); 403 $.fn.select2.defaults.set("sorter", function (data) { 404 return data.sort(function (a, b) { 405 if (a.text.toLowerCase() > b.text.toLowerCase()) { 406 return 1; 407 } 408 if (a.text.toLowerCase() < b.text.toLowerCase()) { 409 return -1; 410 } 411 return 0; 412 }); 413 }) 414 })