1 // Alert icon and window
3 // Requires js-storage and jquery be loaded prior
5 // dragorn@kismetwireless.net
6 // MIT/GPL License (pick one); the web ui code is licensed more
7 // freely than GPL to reflect the generally MIT-licensed nature
8 // of the web/jquery environment
12 var local_uri_prefix = "";
13 if (typeof(KISMET_URI_PREFIX) !== 'undefined')
14 local_uri_prefix = KISMET_URI_PREFIX;
21 var options = base_options;
31 var alertclick = null;
33 // Last time from the server
36 // Last time we closed the alert window
37 var last_closed_time = 0;
41 var alert_list = new Array();
45 function update_tooltips() {
49 var total_plural = 's';
51 for (var x = 0; x < alert_list.length; x++) {
52 if (alert_list[x]['kismet.alert.timestamp'] <= last_closed_time) {
59 var num_total = alert_list.length - num_new;
69 element.tooltipster('content', 'No alerts');
71 element.tooltipster('content', num_total + ' old alert' + total_plural);
75 element.tooltipster('content', num_new + ' alert' + new_plural);
77 element.tooltipster('content', num_new + ' alert' + new_plural + ' ' + num_total + ' old alert' + total_plural);
82 // Close the alert panel if we click outside it
83 var close_dialog_outside = function(e) {
85 (e != null && $(e.target).closest('#alertdialog').length == 0)) {
88 last_closed_time = last_time;
90 storage.set('jquery.kismet.alert.last_closed', last_closed_time);
97 // Un-flag the alert button
98 alertbg.removeClass('ka-top-bg-alert');
100 // Remove the handler
101 $('body').off('click', close_dialog_outside);
105 // Don't pass the click on
106 e.stopImmediatePropagation();
111 var open_dialog = function(e) {
112 if (dialog != null) {
113 close_dialog_outside(e);
115 e.stopImmediatePropagation();
119 var fullscreen = false;
122 var nominal_h = ($(window).height() / 3) * 2;
126 if ($(window).width() < 450) {
127 nominal_w = $(window).width() - 5;
128 nominal_h = $(window).height() - 5;
136 "autoposition": "RIGHT"
141 // Position under the element
142 var off_y = (nominal_h / 2) + (element.outerHeight() / 2) + 3;
144 // left-ish of the icon
145 var off_x = (nominal_w / 5) * 2;
148 // Where the outer border lands
149 var outerborder = off_x + (nominal_w / 2);
161 // Make the list of alerts
162 var listholder = $('<div>', {
163 class: "ka-alert-list",
167 for (var x = 0; x < options.max_backlog; x++) {
169 class: "ka-alert-line"
171 listholder.append(d);
174 var alert_popup_content =
176 class: "ka-dialog-content"
180 class: "ka-dialog-header"
184 class: "fa fa-bell ka-header-icon"
189 class: "ka-header-text"
196 .on('click', function() {
197 close_dialog_outside(null);
201 class: "ka-header-close jsglyph jsglyph-close"
209 class: "ka-dialog-main"
213 class: "ka-dialog-center",
218 class: "fa fa-bell-slash ka-big-icon"
223 class: "ka-dialog-center ka-no-text"
225 .text("No alerts to show!")
232 class: "ka-dialog-footer"
236 class: "ka-bottom-text"
241 id: 'ka-alert-show-all'
243 .on('click', function() {
244 populate_alert_content(alert_popup_content, true);
246 .text("No previous alerts")
253 $('.ka-header-close', alert_popup_content).show();
255 populate_alert_content(alert_popup_content);
265 content: alert_popup_content,
268 $("body").on("click", close_dialog_outside);
270 e.stopImmediatePropagation();
273 var merge_alerts = function(alerts) {
274 alertbg.addClass('ka-top-bg-alert');
276 $.merge(alerts, alert_list);
277 alert_list = alerts.slice(0, options.max_backlog);
279 // Is the dialog showing? Update it if it is
280 if (dialog != null) {
281 populate_alert_content(dialog.content);
287 var alert_refresh = function(fetchtime = last_time) {
288 $.get(local_uri_prefix + "alerts/wrapped/last-time/" + fetchtime + "/alerts.json")
289 .done(function(data) {
290 data = kismet.sanitizeObject(data);
292 // Reverse, combine in the data var, slice and assign to the alert list
293 data['kismet.alert.list'].reverse();
294 merge_alerts(data['kismet.alert.list']);
298 var populate_alert_content = function(c, showall = false) {
299 var divs = $('div.ka-alert-line', c);
302 last_closed_time = 0;
303 storage.set('jquery.kismet.alert.last_closed', last_closed_time);
306 // If the top alert is older (or equal) to the last time we closed the
307 // alert popup, then we don't have any new alerts
308 if (alert_list.length == 0) {
309 $('div#ka-dialog-none', c).show();
310 $('div#ka-alert-list', c).hide();
311 $('a#ka-alert-show-all', c).text("No alerts...");
315 // Are we showing all alerts, or do we have new ones?
316 if (alert_list.length > 0 &&
317 alert_list[0]['kismet.alert.timestamp'] > last_closed_time) {
318 $('div#ka-dialog-none', c).hide();
319 $('div#ka-alert-list', c).show();
321 // Set the txt at the bottom to something sane
322 $('a#ka-alert-show-all', c).text("Showing all alerts...");
324 // Clear all the divs
328 for (var x = 0; x < alert_list.length; x++) {
329 // Stop when we get to old ones
330 if (alert_list[x]['kismet.alert.timestamp'] <= last_closed_time) {
331 // Set the text to 'show all'
332 $('a#ka-alert-show-all', c).text("Show all previous alerts...");
338 var ds = (new Date(alert_list[x]['kismet.alert.timestamp'] * 1000).toString()).substring(4, 25);
340 // Build the content of each alert line
343 class: "ka-alert-line-header"
347 class: "fa fa-bell ka-alert-line-icon"
352 class: "ka-alert-line-date"
358 class: "ka-alert-line-type"
360 .html(kismet.censorMAC(alert_list[x]['kismet.alert.header']))
364 class: "ka-alert-line-text"
366 .html(kismet.censorMAC(alert_list[x]['kismet.alert.text']))
370 class: "ka-alert-line-footer"
374 class: "ka-alert-line-address"
376 .html(kismet_ui_base.renderMac(alert_list[x]['kismet.alert.source_mac']))
380 class: "fa fa-arrow-right ka-alert-line-arrow"
385 class: "ka-alert-line-address"
387 .html(kismet_ui_base.renderMac(alert_list[x]['kismet.alert.dest_mac']))
397 $('div#ka-dialog-none', c).show();
398 $('div#ka-alert-list', c).hide();
400 $('a#ka-alert-show-all', c).text("Show all previous alerts...");
404 $.fn.alert = function(data, inopt) {
405 // Get the stored value if one exists
406 storage = Storages.localStorage;
408 if (storage.isSet('jquery.kismet.alert.last_closed'))
409 last_closed_time = storage.get('jquery.kismet.alert.last_closed');
413 element.addClass('ka-top-icon');
415 options = $.extend(base_options, inopt);
417 alertbg = $('i.background', this);
418 if (alertbg.length == 0) {
420 class: "background fa fa-square fa-stack-2x ka-top-bg-normal"
424 alerticon = $('i.icon', this);
425 if (alerticon.length == 0) {
426 alerticon = $('<i>', {
427 class: "icon fa fa-bell fa-inverse fa-stack-1x"
431 alertnum = $('span.number', this);
432 if (alertnum.length == 0) {
433 alertnum = $('<span>', {
434 class: "number fa fa-stack-1x"
438 // Make the headerbar icon
439 var alertholder = $('span.fa-stack', this);
441 if (alertholder.length != 0) {
444 alertholder = $('<span>', {
449 alertholder.append(alertbg);
450 alertholder.append(alerticon);
451 alertholder.append(alertnum);
453 // Build the wrapper around the header button
455 alertclick = $('a.alertbutton', this);
457 if (alertclick.length != 0) {
461 alertclick = $('<a>', {
465 .on('click', open_dialog);
467 alertclick.append(alertholder);
468 element.append(alertclick);
470 element.tooltipster({
476 kismet_ui_base.SubscribeEventbus("ALERT", [], function(data) {
477 data = kismet.sanitizeObject(data);
478 merge_alerts([data]);