diff --git a/MANIFEST.in b/MANIFEST.in
index 55e0a5d2..8bf5cfb2 100644
--- a/MANIFEST.in
+++ b/MANIFEST.in
@@ -6,3 +6,4 @@ include LICENSE
recursive-include bin *
recursive-include pwnagotchi *.py
recursive-include pwnagotchi *.yml
+recursive-include pwnagotchi *.*
diff --git a/pwnagotchi/ui/web/handler.py b/pwnagotchi/ui/web/handler.py
index 66a9a8e0..4986c0eb 100644
--- a/pwnagotchi/ui/web/handler.py
+++ b/pwnagotchi/ui/web/handler.py
@@ -13,77 +13,7 @@ from pwnagotchi import plugins
from flask import send_file
from flask import request
from flask import abort
-from flask import render_template_string
-
-STYLE = """
-.block {
- -webkit-appearance: button;
- -moz-appearance: button;
- appearance: button;
-
- display: block;
- cursor: pointer;
- text-align: center;
-}
-.pixelated {
- image-rendering:optimizeSpeed; /* Legal fallback */
- image-rendering:-moz-crisp-edges; /* Firefox */
- image-rendering:-o-crisp-edges; /* Opera */
- image-rendering:-webkit-optimize-contrast; /* Safari */
- image-rendering:optimize-contrast; /* CSS3 Proposed */
- image-rendering:crisp-edges; /* CSS4 Proposed */
- image-rendering:pixelated; /* CSS4 Proposed */
- -ms-interpolation-mode:nearest-neighbor; /* IE8+ */
-}
-"""
-
-SCRIPT = """
-window.onload = function() {
- var image = document.getElementById("ui");
- function updateImage() {
- image.src = image.src.split("?")[0] + "?" + new Date().getTime();
- }
- setInterval(updateImage, 1000);
-}
-"""
-
-INDEX = """
-
- {{ title }}
-
-
-
-
-

-
-
-
-
-
-
-
-
-"""
-
-STATUS_PAGE = """
-
- {{ title }}
-
-
-
-
-
- {{ message }}
-
-
-"""
+from flask import render_template, render_template_string
class Handler:
@@ -102,8 +32,8 @@ class Handler:
self._app.add_url_rule('/plugins//', 'plugins', self.plugins, methods=['GET', 'POST'])
def index(self):
- return render_template_string(INDEX, title=pwnagotchi.name(),
- other_mode='AUTO' if self._agent.mode == 'manual' else 'MANU')
+ return render_template('index', title=pwnagotchi.name(),
+ other_mode='AUTO' if self._agent.mode == 'manual' else 'MANU')
def plugins(self, name, subpath):
if name is None:
@@ -125,8 +55,8 @@ class Handler:
# serve a message and shuts down the unit
def shutdown(self):
try:
- return render_template_string(STATUS_PAGE, title=pwnagotchi.name(), go_back_after=60,
- message='Shutting down ...')
+ return render_template('status', title=pwnagotchi.name(), go_back_after=60,
+ message='Shutting down ...')
finally:
_thread.start_new_thread(pwnagotchi.shutdown, ())
@@ -137,8 +67,8 @@ class Handler:
mode = 'MANU'
try:
- return render_template_string(STATUS_PAGE, title=pwnagotchi.name(), go_back_after=30,
- message='Restart in %s mode ...' % mode)
+ return render_template('status', title=pwnagotchi.name(), go_back_after=30,
+ message='Restarting in %s mode ...' % mode)
finally:
_thread.start_new_thread(pwnagotchi.restart, (mode,))
diff --git a/pwnagotchi/ui/web/server.py b/pwnagotchi/ui/web/server.py
index 61f8b73e..7ab9a146 100644
--- a/pwnagotchi/ui/web/server.py
+++ b/pwnagotchi/ui/web/server.py
@@ -29,7 +29,12 @@ class Server:
def _http_serve(self):
if self._address is not None:
- app = Flask(__name__)
+ web_path = os.path.dirname(os.path.realpath(__file__))
+
+ app = Flask(__name__,
+ static_url_path='',
+ static_folder=os.path.join(web_path, 'static'),
+ template_folder=os.path.join(web_path, 'templates'))
app.secret_key = secrets.token_urlsafe(256)
if self._origin:
diff --git a/pwnagotchi/ui/web/static/css/style.css b/pwnagotchi/ui/web/static/css/style.css
new file mode 100644
index 00000000..060a984e
--- /dev/null
+++ b/pwnagotchi/ui/web/static/css/style.css
@@ -0,0 +1,42 @@
+.block {
+ -webkit-appearance: button;
+ -moz-appearance: button;
+ appearance: button;
+
+ display: block;
+ cursor: pointer;
+ text-align: center;
+}
+
+img#ui {
+ width:100%;
+}
+
+.full {
+ position: absolute;
+ top:0;
+ left:0;
+ width:100%;
+}
+
+.pixelated {
+ image-rendering:optimizeSpeed; /* Legal fallback */
+ image-rendering:-moz-crisp-edges; /* Firefox */
+ image-rendering:-o-crisp-edges; /* Opera */
+ image-rendering:-webkit-optimize-contrast; /* Safari */
+ image-rendering:optimize-contrast; /* CSS3 Proposed */
+ image-rendering:crisp-edges; /* CSS4 Proposed */
+ image-rendering:pixelated; /* CSS4 Proposed */
+ -ms-interpolation-mode:nearest-neighbor; /* IE8+ */
+}
+
+form.action {
+ display:inline;
+}
+
+div.status {
+ position: absolute;
+ top:0;
+ left:0;
+ width:100%;
+}
\ No newline at end of file
diff --git a/pwnagotchi/ui/web/static/js/refresh.js b/pwnagotchi/ui/web/static/js/refresh.js
new file mode 100644
index 00000000..24e77899
--- /dev/null
+++ b/pwnagotchi/ui/web/static/js/refresh.js
@@ -0,0 +1,7 @@
+window.onload = function() {
+ var image = document.getElementById("ui");
+ function updateImage() {
+ image.src = image.src.split("?")[0] + "?" + new Date().getTime();
+ }
+ setInterval(updateImage, 1000);
+}
\ No newline at end of file
diff --git a/pwnagotchi/ui/web/templates/index.html b/pwnagotchi/ui/web/templates/index.html
new file mode 100644
index 00000000..50ec1e25
--- /dev/null
+++ b/pwnagotchi/ui/web/templates/index.html
@@ -0,0 +1,29 @@
+
+
+ {{ title }}
+
+
+
+
+

+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/pwnagotchi/ui/web/templates/status.html b/pwnagotchi/ui/web/templates/status.html
new file mode 100644
index 00000000..ddeb8664
--- /dev/null
+++ b/pwnagotchi/ui/web/templates/status.html
@@ -0,0 +1,12 @@
+
+
+ {{ title }}
+
+
+
+
+
+ {{ message }}
+
+
+
\ No newline at end of file