From 301a3d99cf42c1583c310c3f4dbc590e1da168b7 Mon Sep 17 00:00:00 2001
From: dadav <33197631+dadav@users.noreply.github.com>
Date: Sun, 19 Jan 2020 11:11:13 +0100
Subject: [PATCH 1/2] add session logs

---
 pwnagotchi/plugins/default/session-stats.py | 219 ++++++++++++--------
 1 file changed, 138 insertions(+), 81 deletions(-)

diff --git a/pwnagotchi/plugins/default/session-stats.py b/pwnagotchi/plugins/default/session-stats.py
index 96a9d50..2d4a6d9 100644
--- a/pwnagotchi/plugins/default/session-stats.py
+++ b/pwnagotchi/plugins/default/session-stats.py
@@ -1,8 +1,10 @@
 import os
 import logging
 import threading
-from datetime import datetime
+from time import sleep
+from datetime import datetime,timedelta
 from pwnagotchi import plugins
+from pwnagotchi.utils import StatusFile
 from flask import render_template_string
 from flask import jsonify
 
@@ -31,86 +33,110 @@ TEMPLATE = """
 
 {% block script %}
     $(document).ready(function(){
-      var ajaxDataRenderer = function(url, plot, options) {
-	var ret = null;
-	$.ajax({
-	  async: false,
-	  url: url,
-	  dataType:"json",
-	  success: function(data) {
-	    ret = data;
-	  }
-	});
-	return ret;
-      };
-
-      function loadData(url, elm, title) {
-          var data = ajaxDataRenderer(url);
-          var plot_os = $.jqplot(elm, data.values,{
-            title: title,
-            stackSeries: true,
-            seriesDefaults: {
-                showMarker: false,
-                fill: true,
-                fillAndStroke: true
-            },
-            legend: {
-                show: true,
-                renderer: $.jqplot.EnhancedLegendRenderer,
-                placement: 'outsideGrid',
-                labels: data.labels,
-                location: 's',
-                rendererOptions: {
-                  numberRows: '2',
-                },
-                rowSpacing: '0px'
-            },
-            axes:{
-                xaxis:{
-                    renderer:$.jqplot.DateAxisRenderer,
-                    tickOptions:{formatString:'%H:%M:%S'}
-                },
-                yaxis:{
-                    min: 0,
-                    tickOptions:{formatString:'%.2f'}
-                }
-            },
-            highlighter: {
-                show: true,
-                sizeAdjust: 7.5
-            },
-            cursor:{
-                show: true,
-                tooltipLocation:'sw'
+        var ajaxDataRenderer = function(url, plot, options) {
+        var ret = null;
+        $.ajax({
+            async: false,
+            url: url,
+            dataType:"json",
+            success: function(data) {
+                ret = data;
             }
-          }).replot({
-            axes:{
-                xaxis:{
-                    renderer:$.jqplot.DateAxisRenderer,
-                    tickOptions:{formatString:'%H:%M:%S'}
-                },
-                yaxis:{
-                    min: 0,
-                    tickOptions:{formatString:'%.2f'}
-                }
+        });
+        return ret;
+        };
+
+    function loadFiles(url, elm) {
+        var data = ajaxDataRenderer(url);
+        var x = document.getElementById(elm);
+        $.each(data['files'], function( index, value ) {
+            var option = document.createElement("option");
+            option.text = value;
+            x.add(option);
+        });
+    }
+
+    function loadData(url, elm, title, fill) {
+        var data = ajaxDataRenderer(url);
+        var plot_os = $.jqplot(elm, data.values,{
+        title: title,
+        stackSeries: fill,
+        seriesDefaults: {
+            showMarker: !fill,
+            fill: fill,
+            fillAndStroke: fill
+        },
+        legend: {
+            show: true,
+            renderer: $.jqplot.EnhancedLegendRenderer,
+            placement: 'outsideGrid',
+            labels: data.labels,
+            location: 's',
+            rendererOptions: {
+                numberRows: '2',
+            },
+            rowSpacing: '0px'
+        },
+        axes:{
+            xaxis:{
+                renderer:$.jqplot.DateAxisRenderer,
+                tickOptions:{formatString:'%H:%M:%S'}
+            },
+            yaxis:{
+                min: 0,
+                tickOptions:{formatString:'%.2f'}
             }
-            });
-      }
+        },
+        highlighter: {
+            show: true,
+            sizeAdjust: 7.5
+        },
+        cursor:{
+            show: true,
+            tooltipLocation:'sw'
+        }
+        }).replot({
+        axes:{
+            xaxis:{
+                renderer:$.jqplot.DateAxisRenderer,
+                tickOptions:{formatString:'%H:%M:%S'}
+            },
+            yaxis:{
+                min: 0,
+                tickOptions:{formatString:'%.2f'}
+            }
+        }
+        });
+    }
 
-      function loadAll() {
-          loadData('/plugins/session-stats/os', 'chart_os', 'OS')
-          loadData('/plugins/session-stats/temp', 'chart_temp', 'Temp')
-          loadData('/plugins/session-stats/nums', 'chart_nums', 'Wifi')
-          loadData('/plugins/session-stats/duration', 'chart_duration', 'Sleeping')
-          loadData('/plugins/session-stats/epoch', 'chart_epoch', 'Epochs')
-      }
+    function loadSessionFiles() {
+        loadFiles('/plugins/session-stats/session', 'session');
+        $("#session").change(function() {
+            loadSessionData();
+        });
+    }
 
-      loadAll();
-      setInterval(loadAll, 60000);
+    function loadSessionData() {
+        var x = document.getElementById("session");
+        var session = x.options[x.selectedIndex].text;
+        loadData('/plugins/session-stats/os' + '?session=' + session, 'chart_os', 'OS', false)
+        loadData('/plugins/session-stats/temp' + '?session=' + session, 'chart_temp', 'Temp', false)
+        loadData('/plugins/session-stats/nums' + '?session=' + session, 'chart_nums', 'Wifi', true)
+        loadData('/plugins/session-stats/duration' + '?session=' + session, 'chart_duration', 'Sleeping', true)
+        loadData('/plugins/session-stats/epoch' + '?session=' + session, 'chart_epoch', 'Epochs', false)
+    }
+
+
+    loadSessionFiles();
+    loadSessionData();
+    setInterval(loadSessionData, 60000);
     });
 {% endblock %}
 
 {% block content %}
+    <select id="session" style="width:100%;">
+        <option selected>Current</option>
+    </select>
     <div id="chart_os" style="height:400px;width:100%; "></div>
     <div id="chart_temp" style="height:400px;width:100%; "></div>
     <div id="chart_nums" style="height:400px;width:100%; "></div>
@@ -119,6 +145,25 @@ TEMPLATE = """
 {% endblock %}
 """
 
+class GhettoClock:
+    def __init__(self):
+        self.lock = threading.Lock()
+        self._track = datetime.now()
+        self._counter_thread = threading.Thread(target=self.counter)
+        self._counter_thread.daemon = True
+        self._counter_thread.start()
+
+    def counter(self):
+        while True:
+            with self.lock:
+                self._track += timedelta(seconds=1)
+            sleep(1)
+
+    def now(self):
+        with self.lock:
+            return self._track
+
+
 class SessionStats(plugins.Plugin):
     __author__ = '33197631+dadav@users.noreply.github.com'
     __version__ = '0.1.0'
@@ -126,17 +171,23 @@ class SessionStats(plugins.Plugin):
     __description__ = 'This plugin displays stats of the current session.'
 
     def __init__(self):
-        self.ready = False
         self.lock = threading.Lock()
         self.options = dict()
         self.stats = dict()
+        self.clock = GhettoClock()
 
     def on_loaded(self):
         """
         Gets called when the plugin gets loaded
         """
+        # this has to happen in "loaded" because the options are not yet
+        # available in the __init__
+        os.makedirs(self.options['save_directory'], exist_ok=True)
+        self.session_name = "stats_{}.json".format(self.clock.now().strftime("%Y_%m_%d_%H_%M"))
+        self.session = StatusFile(os.path.join(self.options['save_directory'],
+                                               self.session_name),
+                                  data_format='json')
         logging.info("Session-stats plugin loaded.")
-        self.ready = True
 
     def on_unloaded(self, ui):
         pass
@@ -146,7 +197,8 @@ class SessionStats(plugins.Plugin):
         Save the epoch_data to self.stats
         """
         with self.lock:
-            self.stats[datetime.now().strftime("%H:%M:%S")] = epoch_data
+            self.stats[self.clock.now().strftime("%H:%M:%S")] = epoch_data
+            self.session.update(data={'data': self.stats})
 
     @staticmethod
     def extract_key_values(data, subkeys):
@@ -162,6 +214,8 @@ class SessionStats(plugins.Plugin):
         if not path or path == "/":
             return render_template_string(TEMPLATE)
 
+        session_param = request.args.get('session')
+
         if path == "os":
             extract_keys = ['cpu_load','mem_usage',]
         elif path == "temp":
@@ -184,12 +238,15 @@ class SessionStats(plugins.Plugin):
             ]
         elif path == "epoch":
             extract_keys = [
-                'blind_for_epochs',
-                'inactive_for_epochs',
                 'active_for_epochs',
+                'blind_for_epochs',
             ]
-
-
+        elif path == "session":
+            return jsonify({'files': os.listdir(self.options['save_directory'])})
 
         with self.lock:
-            return jsonify(SessionStats.extract_key_values(self.stats, extract_keys))
+            data = self.stats
+            if session_param and session_param != 'Current':
+                file_stats = StatusFile(os.path.join(self.options['save_directory'], session_param), data_format='json')
+                data = file_stats.data_field_or('data', default=dict())
+            return jsonify(SessionStats.extract_key_values(data, extract_keys))

From 665ad938b4c512de9c4419e073a4d30ecac883f2 Mon Sep 17 00:00:00 2001
From: dadav <33197631+dadav@users.noreply.github.com>
Date: Sun, 19 Jan 2020 11:14:05 +0100
Subject: [PATCH 2/2] add save_directory variable

---
 pwnagotchi/defaults.toml | 1 +
 1 file changed, 1 insertion(+)

diff --git a/pwnagotchi/defaults.toml b/pwnagotchi/defaults.toml
index 45cff59..5f2137f 100644
--- a/pwnagotchi/defaults.toml
+++ b/pwnagotchi/defaults.toml
@@ -105,6 +105,7 @@ main.plugins.led.patterns.peer_detected = "oo  oo  oo oo  oo  oo  oo"
 main.plugins.led.patterns.peer_lost = "oo  oo  oo oo  oo  oo  oo"
 
 main.plugins.session-stats.enabled = true
+main.plugins.session-stats.save_directory = "/var/tmp/pwnagotchi/sessions/"
 
 main.log.path = "/var/log/pwnagotchi.log"
 main.log.rotation.enabled = true