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