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  })