github.com/Ne0nd0g/gophish@v0.7.1-0.20190220040016-11493024a07d/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({ 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 () { 104 swal( 105 'Template Deleted!', 106 'This template has been deleted!', 107 'success' 108 ); 109 $('button:contains("OK")').on('click', function () { 110 location.reload() 111 }) 112 }) 113 } 114 115 function deleteTemplate(idx) { 116 if (confirm("Delete " + templates[idx].name + "?")) { 117 api.templateId.delete(templates[idx].id) 118 .success(function (data) { 119 successFlash(data.message) 120 load() 121 }) 122 } 123 } 124 125 function attach(files) { 126 attachmentsTable = $("#attachmentsTable").DataTable({ 127 destroy: true, 128 "order": [ 129 [1, "asc"] 130 ], 131 columnDefs: [{ 132 orderable: false, 133 targets: "no-sort" 134 }, { 135 sClass: "datatable_hidden", 136 targets: [3, 4] 137 }] 138 }); 139 $.each(files, function (i, file) { 140 var reader = new FileReader(); 141 /* Make this a datatable */ 142 reader.onload = function (e) { 143 var icon = icons[file.type] || "fa-file-o" 144 // Add the record to the modal 145 attachmentsTable.row.add([ 146 '<i class="fa ' + icon + '"></i>', 147 escapeHtml(file.name), 148 '<span class="remove-row"><i class="fa fa-trash-o"></i></span>', 149 reader.result.split(",")[1], 150 file.type || "application/octet-stream" 151 ]).draw() 152 } 153 reader.onerror = function (e) { 154 console.log(e) 155 } 156 reader.readAsDataURL(file) 157 }) 158 } 159 160 function edit(idx) { 161 $("#modalSubmit").unbind('click').click(function () { 162 save(idx) 163 }) 164 $("#attachmentUpload").unbind('click').click(function () { 165 this.value = null 166 }) 167 $("#html_editor").ckeditor() 168 setupAutocomplete(CKEDITOR.instances["html_editor"]) 169 $("#attachmentsTable").show() 170 attachmentsTable = $('#attachmentsTable').DataTable({ 171 destroy: true, 172 "order": [ 173 [1, "asc"] 174 ], 175 columnDefs: [{ 176 orderable: false, 177 targets: "no-sort" 178 }, { 179 sClass: "datatable_hidden", 180 targets: [3, 4] 181 }] 182 }); 183 var template = { 184 attachments: [] 185 } 186 if (idx != -1) { 187 template = templates[idx] 188 $("#name").val(template.name) 189 $("#subject").val(template.subject) 190 $("#html_editor").val(template.html) 191 $("#text_editor").val(template.text) 192 $.each(template.attachments, function (i, file) { 193 var icon = icons[file.type] || "fa-file-o" 194 // Add the record to the modal 195 attachmentsTable.row.add([ 196 '<i class="fa ' + icon + '"></i>', 197 escapeHtml(file.name), 198 '<span class="remove-row"><i class="fa fa-trash-o"></i></span>', 199 file.content, 200 file.type || "application/octet-stream" 201 ]).draw() 202 }) 203 if (template.html.indexOf("{{.Tracker}}") != -1) { 204 $("#use_tracker_checkbox").prop("checked", true) 205 } else { 206 $("#use_tracker_checkbox").prop("checked", false) 207 } 208 209 } 210 // Handle Deletion 211 $("#attachmentsTable").unbind('click').on("click", "span>i.fa-trash-o", function () { 212 attachmentsTable.row($(this).parents('tr')) 213 .remove() 214 .draw(); 215 }) 216 } 217 218 function copy(idx) { 219 $("#modalSubmit").unbind('click').click(function () { 220 save(-1) 221 }) 222 $("#attachmentUpload").unbind('click').click(function () { 223 this.value = null 224 }) 225 $("#html_editor").ckeditor() 226 $("#attachmentsTable").show() 227 attachmentsTable = $('#attachmentsTable').DataTable({ 228 destroy: true, 229 "order": [ 230 [1, "asc"] 231 ], 232 columnDefs: [{ 233 orderable: false, 234 targets: "no-sort" 235 }, { 236 sClass: "datatable_hidden", 237 targets: [3, 4] 238 }] 239 }); 240 var template = { 241 attachments: [] 242 } 243 template = templates[idx] 244 $("#name").val("Copy of " + template.name) 245 $("#subject").val(template.subject) 246 $("#html_editor").val(template.html) 247 $("#text_editor").val(template.text) 248 $.each(template.attachments, function (i, file) { 249 var icon = icons[file.type] || "fa-file-o" 250 // Add the record to the modal 251 attachmentsTable.row.add([ 252 '<i class="fa ' + icon + '"></i>', 253 escapeHtml(file.name), 254 '<span class="remove-row"><i class="fa fa-trash-o"></i></span>', 255 file.content, 256 file.type || "application/octet-stream" 257 ]).draw() 258 }) 259 // Handle Deletion 260 $("#attachmentsTable").unbind('click').on("click", "span>i.fa-trash-o", function () { 261 attachmentsTable.row($(this).parents('tr')) 262 .remove() 263 .draw(); 264 }) 265 if (template.html.indexOf("{{.Tracker}}") != -1) { 266 $("#use_tracker_checkbox").prop("checked", true) 267 } else { 268 $("#use_tracker_checkbox").prop("checked", false) 269 } 270 } 271 272 function importEmail() { 273 raw = $("#email_content").val() 274 convert_links = $("#convert_links_checkbox").prop("checked") 275 if (!raw) { 276 modalError("No Content Specified!") 277 } else { 278 api.import_email({ 279 content: raw, 280 convert_links: convert_links 281 }) 282 .success(function (data) { 283 $("#text_editor").val(data.text) 284 $("#html_editor").val(data.html) 285 $("#subject").val(data.subject) 286 // If the HTML is provided, let's open that view in the editor 287 if (data.html) { 288 CKEDITOR.instances["html_editor"].setMode('wysiwyg') 289 $('.nav-tabs a[href="#html"]').click() 290 } 291 $("#importEmailModal").modal("hide") 292 }) 293 .error(function (data) { 294 modalError(data.responseJSON.message) 295 }) 296 } 297 } 298 299 function load() { 300 $("#templateTable").hide() 301 $("#emptyMessage").hide() 302 $("#loading").show() 303 api.templates.get() 304 .success(function (ts) { 305 templates = ts 306 $("#loading").hide() 307 if (templates.length > 0) { 308 $("#templateTable").show() 309 templateTable = $("#templateTable").DataTable({ 310 destroy: true, 311 columnDefs: [{ 312 orderable: false, 313 targets: "no-sort" 314 }] 315 }); 316 templateTable.clear() 317 $.each(templates, function (i, template) { 318 templateTable.row.add([ 319 escapeHtml(template.name), 320 moment(template.modified_date).format('MMMM Do YYYY, h:mm:ss a'), 321 "<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 + ")'>\ 322 <i class='fa fa-pencil'></i>\ 323 </button></span>\ 324 <span data-toggle='modal' data-target='#modal'><button class='btn btn-primary' data-toggle='tooltip' data-placement='left' title='Copy Template' onclick='copy(" + i + ")'>\ 325 <i class='fa fa-copy'></i>\ 326 </button></span>\ 327 <button class='btn btn-danger' data-toggle='tooltip' data-placement='left' title='Delete Template' onclick='deleteTemplate(" + i + ")'>\ 328 <i class='fa fa-trash-o'></i>\ 329 </button></div>" 330 ]).draw() 331 }) 332 $('[data-toggle="tooltip"]').tooltip() 333 } else { 334 $("#emptyMessage").show() 335 } 336 }) 337 .error(function () { 338 $("#loading").hide() 339 errorFlash("Error fetching templates") 340 }) 341 } 342 343 $(document).ready(function () { 344 // Setup multiple modals 345 // Code based on http://miles-by-motorcycle.com/static/bootstrap-modal/index.html 346 $('.modal').on('hidden.bs.modal', function (event) { 347 $(this).removeClass('fv-modal-stack'); 348 $('body').data('fv_open_modals', $('body').data('fv_open_modals') - 1); 349 }); 350 $('.modal').on('shown.bs.modal', function (event) { 351 // Keep track of the number of open modals 352 if (typeof ($('body').data('fv_open_modals')) == 'undefined') { 353 $('body').data('fv_open_modals', 0); 354 } 355 // if the z-index of this modal has been set, ignore. 356 if ($(this).hasClass('fv-modal-stack')) { 357 return; 358 } 359 $(this).addClass('fv-modal-stack'); 360 // Increment the number of open modals 361 $('body').data('fv_open_modals', $('body').data('fv_open_modals') + 1); 362 // Setup the appropriate z-index 363 $(this).css('z-index', 1040 + (10 * $('body').data('fv_open_modals'))); 364 $('.modal-backdrop').not('.fv-modal-stack').css('z-index', 1039 + (10 * $('body').data('fv_open_modals'))); 365 $('.modal-backdrop').not('fv-modal-stack').addClass('fv-modal-stack'); 366 }); 367 $.fn.modal.Constructor.prototype.enforceFocus = function () { 368 $(document) 369 .off('focusin.bs.modal') // guard against infinite focus loop 370 .on('focusin.bs.modal', $.proxy(function (e) { 371 if ( 372 this.$element[0] !== e.target && !this.$element.has(e.target).length 373 // CKEditor compatibility fix start. 374 && 375 !$(e.target).closest('.cke_dialog, .cke').length 376 // CKEditor compatibility fix end. 377 ) { 378 this.$element.trigger('focus'); 379 } 380 }, this)); 381 }; 382 // Scrollbar fix - https://stackoverflow.com/questions/19305821/multiple-modals-overlay 383 $(document).on('hidden.bs.modal', '.modal', function () { 384 $('.modal:visible').length && $(document.body).addClass('modal-open'); 385 }); 386 $('#modal').on('hidden.bs.modal', function (event) { 387 dismiss() 388 }); 389 $("#importEmailModal").on('hidden.bs.modal', function (event) { 390 $("#email_content").val("") 391 }) 392 CKEDITOR.on('dialogDefinition', function (ev) { 393 // Take the dialog name and its definition from the event data. 394 var dialogName = ev.data.name; 395 var dialogDefinition = ev.data.definition; 396 397 // Check if the definition is from the dialog window you are interested in (the "Link" dialog window). 398 if (dialogName == 'link') { 399 dialogDefinition.minWidth = 500 400 dialogDefinition.minHeight = 100 401 402 // Remove the linkType field 403 var infoTab = dialogDefinition.getContents('info'); 404 infoTab.get('linkType').hidden = true; 405 } 406 }); 407 load() 408 409 })