github.com/merlinepedra/gophish1@v0.9.0/static/js/src/app/templates.js (about) 1 var templates = [] 2 var icons = { 3 "application/vnd.ms-excel": "fa-file-excel-o", 4 "text/plain": "fa-file-text-o", 5 "image/gif": "fa-file-image-o", 6 "image/png": "fa-file-image-o", 7 "application/pdf": "fa-file-pdf-o", 8 "application/x-zip-compressed": "fa-file-archive-o", 9 "application/x-gzip": "fa-file-archive-o", 10 "application/vnd.openxmlformats-officedocument.presentationml.presentation": "fa-file-powerpoint-o", 11 "application/vnd.openxmlformats-officedocument.wordprocessingml.document": "fa-file-word-o", 12 "application/octet-stream": "fa-file-o", 13 "application/x-msdownload": "fa-file-o" 14 } 15 16 // Save attempts to POST to /templates/ 17 function save(idx) { 18 var template = { 19 attachments: [] 20 } 21 template.name = $("#name").val() 22 template.subject = $("#subject").val() 23 template.html = CKEDITOR.instances["html_editor"].getData(); 24 // Fix the URL Scheme added by CKEditor (until we can remove it from the plugin) 25 template.html = template.html.replace(/https?:\/\/{{\.URL}}/gi, "{{.URL}}") 26 // If the "Add Tracker Image" checkbox is checked, add the tracker 27 if ($("#use_tracker_checkbox").prop("checked")) { 28 if (template.html.indexOf("{{.Tracker}}") == -1 && 29 template.html.indexOf("{{.TrackingUrl}}") == -1) { 30 template.html = template.html.replace("</body>", "{{.Tracker}}</body>") 31 } 32 } else { 33 // Otherwise, remove the tracker 34 template.html = template.html.replace("{{.Tracker}}</body>", "</body>") 35 } 36 template.text = $("#text_editor").val() 37 // Add the attachments 38 $.each($("#attachmentsTable").DataTable().rows().data(), function (i, target) { 39 template.attachments.push({ 40 name: unescapeHtml(target[1]), 41 content: target[3], 42 type: target[4], 43 }) 44 }) 45 46 if (idx != -1) { 47 template.id = templates[idx].id 48 api.templateId.put(template) 49 .success(function (data) { 50 successFlash("Template edited successfully!") 51 load() 52 dismiss() 53 }) 54 .error(function (data) { 55 modalError(data.responseJSON.message) 56 }) 57 } else { 58 // Submit the template 59 api.templates.post(template) 60 .success(function (data) { 61 successFlash("Template added successfully!") 62 load() 63 dismiss() 64 }) 65 .error(function (data) { 66 modalError(data.responseJSON.message) 67 }) 68 } 69 } 70 71 function dismiss() { 72 $("#modal\\.flashes").empty() 73 $("#attachmentsTable").dataTable().DataTable().clear().draw() 74 $("#name").val("") 75 $("#subject").val("") 76 $("#text_editor").val("") 77 $("#html_editor").val("") 78 $("#modal").modal('hide') 79 } 80 81 var deleteTemplate = function (idx) { 82 Swal.fire({ 83 title: "Are you sure?", 84 text: "This will delete the template. This can't be undone!", 85 type: "warning", 86 animation: false, 87 showCancelButton: true, 88 confirmButtonText: "Delete " + escapeHtml(templates[idx].name), 89 confirmButtonColor: "#428bca", 90 reverseButtons: true, 91 allowOutsideClick: false, 92 preConfirm: function () { 93 return new Promise(function (resolve, reject) { 94 api.templateId.delete(templates[idx].id) 95 .success(function (msg) { 96 resolve() 97 }) 98 .error(function (data) { 99 reject(data.responseJSON.message) 100 }) 101 }) 102 } 103 }).then(function (result) { 104 if(result.value) { 105 Swal.fire( 106 'Template Deleted!', 107 'This template has been deleted!', 108 'success' 109 ); 110 } 111 $('button:contains("OK")').on('click', function () { 112 location.reload() 113 }) 114 }) 115 } 116 117 function deleteTemplate(idx) { 118 if (confirm("Delete " + templates[idx].name + "?")) { 119 api.templateId.delete(templates[idx].id) 120 .success(function (data) { 121 successFlash(data.message) 122 load() 123 }) 124 } 125 } 126 127 function attach(files) { 128 attachmentsTable = $("#attachmentsTable").DataTable({ 129 destroy: true, 130 "order": [ 131 [1, "asc"] 132 ], 133 columnDefs: [{ 134 orderable: false, 135 targets: "no-sort" 136 }, { 137 sClass: "datatable_hidden", 138 targets: [3, 4] 139 }] 140 }); 141 $.each(files, function (i, file) { 142 var reader = new FileReader(); 143 /* Make this a datatable */ 144 reader.onload = function (e) { 145 var icon = icons[file.type] || "fa-file-o" 146 // Add the record to the modal 147 attachmentsTable.row.add([ 148 '<i class="fa ' + icon + '"></i>', 149 escapeHtml(file.name), 150 '<span class="remove-row"><i class="fa fa-trash-o"></i></span>', 151 reader.result.split(",")[1], 152 file.type || "application/octet-stream" 153 ]).draw() 154 } 155 reader.onerror = function (e) { 156 console.log(e) 157 } 158 reader.readAsDataURL(file) 159 }) 160 } 161 162 function edit(idx) { 163 $("#modalSubmit").unbind('click').click(function () { 164 save(idx) 165 }) 166 $("#attachmentUpload").unbind('click').click(function () { 167 this.value = null 168 }) 169 $("#html_editor").ckeditor() 170 setupAutocomplete(CKEDITOR.instances["html_editor"]) 171 $("#attachmentsTable").show() 172 attachmentsTable = $('#attachmentsTable').DataTable({ 173 destroy: true, 174 "order": [ 175 [1, "asc"] 176 ], 177 columnDefs: [{ 178 orderable: false, 179 targets: "no-sort" 180 }, { 181 sClass: "datatable_hidden", 182 targets: [3, 4] 183 }] 184 }); 185 var template = { 186 attachments: [] 187 } 188 if (idx != -1) { 189 template = templates[idx] 190 $("#name").val(template.name) 191 $("#subject").val(template.subject) 192 $("#html_editor").val(template.html) 193 $("#text_editor").val(template.text) 194 $.each(template.attachments, function (i, file) { 195 var icon = icons[file.type] || "fa-file-o" 196 // Add the record to the modal 197 attachmentsTable.row.add([ 198 '<i class="fa ' + icon + '"></i>', 199 escapeHtml(file.name), 200 '<span class="remove-row"><i class="fa fa-trash-o"></i></span>', 201 file.content, 202 file.type || "application/octet-stream" 203 ]).draw() 204 }) 205 if (template.html.indexOf("{{.Tracker}}") != -1) { 206 $("#use_tracker_checkbox").prop("checked", true) 207 } else { 208 $("#use_tracker_checkbox").prop("checked", false) 209 } 210 211 } 212 // Handle Deletion 213 $("#attachmentsTable").unbind('click').on("click", "span>i.fa-trash-o", function () { 214 attachmentsTable.row($(this).parents('tr')) 215 .remove() 216 .draw(); 217 }) 218 } 219 220 function copy(idx) { 221 $("#modalSubmit").unbind('click').click(function () { 222 save(-1) 223 }) 224 $("#attachmentUpload").unbind('click').click(function () { 225 this.value = null 226 }) 227 $("#html_editor").ckeditor() 228 $("#attachmentsTable").show() 229 attachmentsTable = $('#attachmentsTable').DataTable({ 230 destroy: true, 231 "order": [ 232 [1, "asc"] 233 ], 234 columnDefs: [{ 235 orderable: false, 236 targets: "no-sort" 237 }, { 238 sClass: "datatable_hidden", 239 targets: [3, 4] 240 }] 241 }); 242 var template = { 243 attachments: [] 244 } 245 template = templates[idx] 246 $("#name").val("Copy of " + template.name) 247 $("#subject").val(template.subject) 248 $("#html_editor").val(template.html) 249 $("#text_editor").val(template.text) 250 $.each(template.attachments, function (i, file) { 251 var icon = icons[file.type] || "fa-file-o" 252 // Add the record to the modal 253 attachmentsTable.row.add([ 254 '<i class="fa ' + icon + '"></i>', 255 escapeHtml(file.name), 256 '<span class="remove-row"><i class="fa fa-trash-o"></i></span>', 257 file.content, 258 file.type || "application/octet-stream" 259 ]).draw() 260 }) 261 // Handle Deletion 262 $("#attachmentsTable").unbind('click').on("click", "span>i.fa-trash-o", function () { 263 attachmentsTable.row($(this).parents('tr')) 264 .remove() 265 .draw(); 266 }) 267 if (template.html.indexOf("{{.Tracker}}") != -1) { 268 $("#use_tracker_checkbox").prop("checked", true) 269 } else { 270 $("#use_tracker_checkbox").prop("checked", false) 271 } 272 } 273 274 function importEmail() { 275 raw = $("#email_content").val() 276 convert_links = $("#convert_links_checkbox").prop("checked") 277 if (!raw) { 278 modalError("No Content Specified!") 279 } else { 280 api.import_email({ 281 content: raw, 282 convert_links: convert_links 283 }) 284 .success(function (data) { 285 $("#text_editor").val(data.text) 286 $("#html_editor").val(data.html) 287 $("#subject").val(data.subject) 288 // If the HTML is provided, let's open that view in the editor 289 if (data.html) { 290 CKEDITOR.instances["html_editor"].setMode('wysiwyg') 291 $('.nav-tabs a[href="#html"]').click() 292 } 293 $("#importEmailModal").modal("hide") 294 }) 295 .error(function (data) { 296 modalError(data.responseJSON.message) 297 }) 298 } 299 } 300 301 function load() { 302 $("#templateTable").hide() 303 $("#emptyMessage").hide() 304 $("#loading").show() 305 api.templates.get() 306 .success(function (ts) { 307 templates = ts 308 $("#loading").hide() 309 if (templates.length > 0) { 310 $("#templateTable").show() 311 templateTable = $("#templateTable").DataTable({ 312 destroy: true, 313 columnDefs: [{ 314 orderable: false, 315 targets: "no-sort" 316 }] 317 }); 318 templateTable.clear() 319 $.each(templates, function (i, template) { 320 templateTable.row.add([ 321 escapeHtml(template.name), 322 moment(template.modified_date).format('MMMM Do YYYY, h:mm:ss a'), 323 "<div class='pull-right'><span data-toggle='modal' data-backdrop='static' data-target='#modal'><button class='btn btn-primary' data-toggle='tooltip' data-placement='left' title='Edit Template' onclick='edit(" + i + ")'>\ 324 <i class='fa fa-pencil'></i>\ 325 </button></span>\ 326 <span data-toggle='modal' data-target='#modal'><button class='btn btn-primary' data-toggle='tooltip' data-placement='left' title='Copy Template' onclick='copy(" + i + ")'>\ 327 <i class='fa fa-copy'></i>\ 328 </button></span>\ 329 <button class='btn btn-danger' data-toggle='tooltip' data-placement='left' title='Delete Template' onclick='deleteTemplate(" + i + ")'>\ 330 <i class='fa fa-trash-o'></i>\ 331 </button></div>" 332 ]).draw() 333 }) 334 $('[data-toggle="tooltip"]').tooltip() 335 } else { 336 $("#emptyMessage").show() 337 } 338 }) 339 .error(function () { 340 $("#loading").hide() 341 errorFlash("Error fetching templates") 342 }) 343 } 344 345 $(document).ready(function () { 346 // Setup multiple modals 347 // Code based on http://miles-by-motorcycle.com/static/bootstrap-modal/index.html 348 $('.modal').on('hidden.bs.modal', function (event) { 349 $(this).removeClass('fv-modal-stack'); 350 $('body').data('fv_open_modals', $('body').data('fv_open_modals') - 1); 351 }); 352 $('.modal').on('shown.bs.modal', function (event) { 353 // Keep track of the number of open modals 354 if (typeof ($('body').data('fv_open_modals')) == 'undefined') { 355 $('body').data('fv_open_modals', 0); 356 } 357 // if the z-index of this modal has been set, ignore. 358 if ($(this).hasClass('fv-modal-stack')) { 359 return; 360 } 361 $(this).addClass('fv-modal-stack'); 362 // Increment the number of open modals 363 $('body').data('fv_open_modals', $('body').data('fv_open_modals') + 1); 364 // Setup the appropriate z-index 365 $(this).css('z-index', 1040 + (10 * $('body').data('fv_open_modals'))); 366 $('.modal-backdrop').not('.fv-modal-stack').css('z-index', 1039 + (10 * $('body').data('fv_open_modals'))); 367 $('.modal-backdrop').not('fv-modal-stack').addClass('fv-modal-stack'); 368 }); 369 $.fn.modal.Constructor.prototype.enforceFocus = function () { 370 $(document) 371 .off('focusin.bs.modal') // guard against infinite focus loop 372 .on('focusin.bs.modal', $.proxy(function (e) { 373 if ( 374 this.$element[0] !== e.target && !this.$element.has(e.target).length 375 // CKEditor compatibility fix start. 376 && 377 !$(e.target).closest('.cke_dialog, .cke').length 378 // CKEditor compatibility fix end. 379 ) { 380 this.$element.trigger('focus'); 381 } 382 }, this)); 383 }; 384 // Scrollbar fix - https://stackoverflow.com/questions/19305821/multiple-modals-overlay 385 $(document).on('hidden.bs.modal', '.modal', function () { 386 $('.modal:visible').length && $(document.body).addClass('modal-open'); 387 }); 388 $('#modal').on('hidden.bs.modal', function (event) { 389 dismiss() 390 }); 391 $("#importEmailModal").on('hidden.bs.modal', function (event) { 392 $("#email_content").val("") 393 }) 394 CKEDITOR.on('dialogDefinition', function (ev) { 395 // Take the dialog name and its definition from the event data. 396 var dialogName = ev.data.name; 397 var dialogDefinition = ev.data.definition; 398 399 // Check if the definition is from the dialog window you are interested in (the "Link" dialog window). 400 if (dialogName == 'link') { 401 dialogDefinition.minWidth = 500 402 dialogDefinition.minHeight = 100 403 404 // Remove the linkType field 405 var infoTab = dialogDefinition.getContents('info'); 406 infoTab.get('linkType').hidden = true; 407 } 408 }); 409 load() 410 411 })