First step

This commit is contained in:
dadav 2019-11-03 17:08:45 +01:00
parent 3e1f3d5eec
commit 0aaeeb8011
2 changed files with 52 additions and 110 deletions

View File

@ -15,6 +15,11 @@ class Example(plugins.Plugin):
def __init__(self):
logging.debug("example plugin created")
# called when http://<host>:<port>/plugins/<plugin>/ is called
# must return a response
def on_webhook(self, path, args, req_method):
pass
# called when the plugin is loaded
def on_loaded(self):
logging.warning("WARNING: this plugin should be disabled! options = " % self.options)

View File

@ -8,6 +8,11 @@ import logging
import pwnagotchi
from pwnagotchi.agent import Agent
from pwnagotchi import plugins
from flask import Flask
from flask import send_file
from flask import request
from flask import abort
from flask_cors import CORS
frame_path = '/root/pwnagotchi.png'
frame_format = 'PNG'
@ -88,141 +93,73 @@ STATUS_PAGE = """<html>
</html>"""
class Handler(BaseHTTPRequestHandler):
AllowedOrigin = None # CORS headers are not sent
class Handler:
def __init__(self, app):
self._app = app
self._app.add_url_rule('/', 'index', self.index)
self._app.add_url_rule('/ui', 'ui', self.ui)
self._app.add_url_rule('/shutdown', 'shutdown', self.shutdown, methods=['POST'])
# plugins
self._app.add_url_rule('/plugins', 'plugins', self.plugins, strict_slashes=False, defaults={'name': None, 'subpath': None})
self._app.add_url_rule('/plugins/<name>', 'plugins', self.plugins, strict_slashes=False, methods=['GET','POST'], defaults={'subpath': None})
self._app.add_url_rule('/plugins/<name>/<path:subpath>', 'plugins', self.plugins, methods=['GET','POST'])
# suppress internal logging
def log_message(self, format, *args):
return
def _send_cors_headers(self):
# misc security
self.send_header("X-Frame-Options", "DENY")
self.send_header("X-Content-Type-Options", "nosniff")
self.send_header("X-XSS-Protection", "1; mode=block")
self.send_header("Referrer-Policy", "same-origin")
# cors
if Handler.AllowedOrigin:
self.send_header("Access-Control-Allow-Origin", Handler.AllowedOrigin)
self.send_header('Access-Control-Allow-Credentials', 'true')
self.send_header("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS")
self.send_header("Access-Control-Allow-Headers",
"Accept, Content-Type, Content-Length, Accept-Encoding, X-CSRF-Token, Authorization")
self.send_header("Vary", "Origin")
def index(self):
return INDEX % (pwnagotchi.name(), 1000)
# just render some html in a 200 response
def _html(self, html):
self.send_response(200)
self._send_cors_headers()
self.send_header('Content-type', 'text/html')
self.end_headers()
try:
self.wfile.write(bytes(html, "utf8"))
except:
def plugins(self, name, subpath):
if name is None:
# show plugins overview
pass
else:
# call plugin on_webhook
arguments = request.args
req_method = request.method
# need to return something here
if name in plugins.loaded and hasattr(plugins.loaded[name], 'on_webhook'):
return plugins.loaded[name].on_webhook(subpath, args=arguments, req_method=req_method)
abort(500)
# serve the main html page
def _index(self):
other_mode = 'AUTO' if Agent.INSTANCE.mode == 'manual' else 'MANU'
self._html(INDEX % (
pwnagotchi.name(),
other_mode,
other_mode,
1000))
# serve a message and shuts down the unit
def _shutdown(self):
self._html(STATUS_PAGE % (pwnagotchi.name(), 'Shutting down ...'))
def shutdown(self):
pwnagotchi.shutdown()
# serve a message and restart the unit in the other mode
def _restart(self):
other_mode = 'AUTO' if Agent.INSTANCE.mode == 'manual' else 'MANU'
self._html(STATUS_PAGE % (pwnagotchi.name(), 'Restart in %s mode ...' % other_mode))
pwnagotchi.restart(other_mode)
return SHUTDOWN % pwnagotchi.name()
# serve the PNG file with the display image
def _image(self):
global frame_lock, frame_path, frame_ctype
def ui(self):
global frame_lock, frame_path
with frame_lock:
self.send_response(200)
self._send_cors_headers()
self.send_header('Content-type', frame_ctype)
self.end_headers()
try:
with open(frame_path, 'rb') as fp:
shutil.copyfileobj(fp, self.wfile)
except:
pass
# check the Origin header vs CORS
def _is_allowed(self):
if not Handler.AllowedOrigin or Handler.AllowedOrigin == '*':
return True
# TODO: FIX doesn't work with GET requests same-origin
origin = self.headers.get('origin')
if not origin:
logging.warning("request with no Origin header from %s" % self.address_string())
return False
if origin != Handler.AllowedOrigin:
logging.warning("request with blocked Origin from %s: %s" % (self.address_string(), origin))
return False
return True
def do_OPTIONS(self):
self.send_response(200)
self._send_cors_headers()
self.end_headers()
def do_POST(self):
if not self._is_allowed():
return
elif self.path.startswith('/shutdown'):
self._shutdown()
elif self.path.startswith('/restart'):
self._restart()
else:
self.send_response(404)
def do_GET(self):
if not self._is_allowed():
return
elif self.path == '/':
self._index()
elif self.path.startswith('/ui'):
self._image()
elif self.path.startswith('/plugins'):
matches = re.match(r'\/plugins\/([^\/]+)(\/.*)?', self.path)
if matches:
groups = matches.groups()
plugin_name = groups[0]
right_path = groups[1] if len(groups) == 2 else None
plugins.one(plugin_name, 'webhook', self, right_path)
else:
self.send_response(404)
return send_file(frame_path, mimetype='image/png')
class Server(object):
class Server:
def __init__(self, config):
self._enabled = config['video']['enabled']
self._port = config['video']['port']
self._address = config['video']['address']
self._httpd = None
self._origin = None
if 'origin' in config['video']:
Handler.AllowedOrigin = config['video']['origin']
self._origin = config['video']['origin']
if self._enabled:
_thread.start_new_thread(self._http_serve, ())
def _http_serve(self):
if self._address is not None:
self._httpd = HTTPServer((self._address, self._port), Handler)
logging.info("web ui available at http://%s:%d/" % (self._address, self._port))
self._httpd.serve_forever()
app = Flask(__name__)
if self._origin:
CORS(app, resources={r"*": {"origins": self._origin}})
Handler(app)
app.run(host=self._address, port=self._port, debug=False)
else:
logging.info("could not get ip of usb0, video server not starting")