commit
57034d9fc6
@ -1,35 +1,36 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
from http.server import HTTPServer, BaseHTTPRequestHandler
|
||||
from urllib.parse import parse_qsl
|
||||
|
||||
|
||||
HTML_FORM = """
|
||||
_HTML_FORM_TEMPLATE = """
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>Decryption</title>
|
||||
<style>
|
||||
body { text-align: center; padding: 150px; }
|
||||
h1 { font-size: 50px; }
|
||||
body { font: 20px Helvetica, sans-serif; color: #333; }
|
||||
article { display: block; text-align: center; width: 650px; margin: 0 auto;}
|
||||
input {
|
||||
body {{ text-align: center; padding: 150px; }}
|
||||
h1 {{ font-size: 50px; }}
|
||||
body {{ font: 20px Helvetica, sans-serif; color: #333; }}
|
||||
article {{ display: block; text-align: center; width: 650px; margin: 0 auto;}}
|
||||
input {{
|
||||
padding: 12px 20px;
|
||||
margin: 8px 0;
|
||||
box-sizing: border-box;
|
||||
border: 1px solid #ccc;
|
||||
}
|
||||
input[type=password] {
|
||||
}}
|
||||
input[type=password] {{
|
||||
width: 75%;
|
||||
font-size: 24px;
|
||||
}
|
||||
input[type=submit] {
|
||||
}}
|
||||
input[type=submit] {{
|
||||
cursor: pointer;
|
||||
width: 75%;
|
||||
}
|
||||
input[type=submit]:hover {
|
||||
}}
|
||||
input[type=submit]:hover {{
|
||||
background-color: #d9d9d9;
|
||||
}
|
||||
}}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
@ -39,7 +40,7 @@ HTML_FORM = """
|
||||
<p>Please provide the decryption password.</p>
|
||||
<div>
|
||||
<form action="/set-password" method="POST">
|
||||
<input type="password" id="password" name="password" value=""><br>
|
||||
{password_fields}
|
||||
<input type="submit" value="Submit">
|
||||
</form>
|
||||
</div>
|
||||
@ -48,6 +49,55 @@ HTML_FORM = """
|
||||
</html>
|
||||
"""
|
||||
|
||||
POST_RESPONSE = """
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<style>
|
||||
/* Center the loader */
|
||||
#loader {
|
||||
position: absolute;
|
||||
left: 50%;
|
||||
top: 50%;
|
||||
z-index: 1;
|
||||
width: 150px;
|
||||
height: 150px;
|
||||
margin: -75px 0 0 -75px;
|
||||
border: 16px solid #f3f3f3;
|
||||
border-radius: 50%;
|
||||
border-top: 16px solid #3498db;
|
||||
width: 120px;
|
||||
height: 120px;
|
||||
-webkit-animation: spin 2s linear infinite;
|
||||
animation: spin 2s linear infinite;
|
||||
}
|
||||
|
||||
@-webkit-keyframes spin {
|
||||
0% { -webkit-transform: rotate(0deg); }
|
||||
100% { -webkit-transform: rotate(360deg); }
|
||||
}
|
||||
|
||||
@keyframes spin {
|
||||
0% { transform: rotate(0deg); }
|
||||
100% { transform: rotate(360deg); }
|
||||
}
|
||||
|
||||
#myDiv {
|
||||
display: none;
|
||||
text-align: center;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body style="margin:0;">
|
||||
|
||||
<div id="loader"></div>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
"""
|
||||
|
||||
HTML_FORM = None
|
||||
|
||||
class SimpleHTTPRequestHandler(BaseHTTPRequestHandler):
|
||||
|
||||
@ -59,13 +109,19 @@ class SimpleHTTPRequestHandler(BaseHTTPRequestHandler):
|
||||
def do_POST(self):
|
||||
content_length = int(self.headers['Content-Length'])
|
||||
body = self.rfile.read(content_length)
|
||||
for mapping, password in parse_qsl(body.decode('UTF-8')):
|
||||
with open('/tmp/.pwnagotchi-secret-{}'.format(mapping), 'wt') as pwfile:
|
||||
pwfile.write(password)
|
||||
self.send_response(200)
|
||||
self.end_headers()
|
||||
password = body.decode('UTF-8').split('=')[1]
|
||||
self.wfile.write(POST_RESPONSE.encode())
|
||||
|
||||
with open('/tmp/.pwnagotchi-secret', 'wt') as pwfile:
|
||||
pwfile.write(password)
|
||||
|
||||
with open('/root/.pwnagotchi-crypted') as crypted_file:
|
||||
mappings = [line.split()[0] for line in crypted_file.readlines()]
|
||||
fields = ''.join(['<label for="{m}">Passphrase for {m}:</label>\n<input type="password" id="{m}" name="{m}" value=""><br>'.format(m=m)
|
||||
for m in mappings])
|
||||
HTML_FORM = _HTML_FORM_TEMPLATE.format(password_fields=fields)
|
||||
|
||||
httpd = HTTPServer(('0.0.0.0', 80), SimpleHTTPRequestHandler)
|
||||
httpd.serve_forever()
|
||||
|
@ -103,12 +103,11 @@ is_decrypted() {
|
||||
|
||||
# fail if not mounted
|
||||
if ! mountpoint -q "$mount" >/dev/null 2>&1; then
|
||||
if [ -f /tmp/.pwnagotchi-secret ]; then
|
||||
</tmp/.pwnagotchi-secret read -r SECRET
|
||||
if [ -f /tmp/.pwnagotchi-secret-"$mapping" ]; then
|
||||
</tmp/.pwnagotchi-secret-"$mapping" read -r SECRET
|
||||
if ! test -b /dev/disk/by-id/dm-uuid-*"$(cryptsetup luksUUID "$container" | tr -d -)"*; then
|
||||
if echo -n "$SECRET" | cryptsetup luksOpen -d- "$container" "$mapping" >/dev/null 2>&1; then
|
||||
echo "Container decrypted!"
|
||||
|
||||
fi
|
||||
fi
|
||||
|
||||
@ -151,8 +150,10 @@ EOF
|
||||
fi
|
||||
done </root/.pwnagotchi-crypted
|
||||
|
||||
# overwrite password
|
||||
>/tmp/.pwnagotchi-secret python3 -c 'print("A"*4096)'
|
||||
# overwrite passwords
|
||||
python3 -c 'print("A"*4096)' | tee /tmp/.pwnagotchi-secret-* >/dev/null
|
||||
# delete
|
||||
rm /tmp/.pwnagotchi-secret-*
|
||||
sync # flush
|
||||
|
||||
pkill wpa_supplicant
|
||||
|
@ -311,21 +311,17 @@
|
||||
|
||||
- name: check if user configuration exists
|
||||
stat:
|
||||
path: /etc/pwnagotchi/config.yml
|
||||
path: /etc/pwnagotchi/config.toml
|
||||
register: user_config
|
||||
|
||||
- name: create /etc/pwnagotchi/config.yml
|
||||
- name: create /etc/pwnagotchi/config.toml
|
||||
copy:
|
||||
dest: /etc/pwnagotchi/config.yml
|
||||
dest: /etc/pwnagotchi/config.toml
|
||||
content: |
|
||||
# Add your configuration overrides on this file any configuration changes done to default.yml will be lost!
|
||||
# Add your configuration overrides on this file any configuration changes done to default.toml will be lost!
|
||||
# Example:
|
||||
#
|
||||
# ui:
|
||||
# display:
|
||||
# type: 'inkyphat'
|
||||
# color: 'black'
|
||||
#
|
||||
# ui.display.enabled = true
|
||||
# ui.display.type = "waveshare_2"
|
||||
when: not user_config.stat.exists
|
||||
|
||||
- name: enable ssh on boot
|
||||
@ -372,15 +368,15 @@
|
||||
Hi! I'm a pwnagotchi, please take good care of me!
|
||||
Here are some basic things you need to know to raise me properly!
|
||||
|
||||
If you want to change my configuration, use /etc/pwnagotchi/config.yml
|
||||
If you want to change my configuration, use /etc/pwnagotchi/config.toml
|
||||
|
||||
All the configuration options can be found on /etc/pwnagotchi/default.yml,
|
||||
All the configuration options can be found on /etc/pwnagotchi/default.toml,
|
||||
but don't change this file because I will recreate it every time I'm restarted!
|
||||
|
||||
I'm managed by systemd. Here are some basic commands.
|
||||
|
||||
If you want to know what I'm doing, you can check my logs with the command
|
||||
journalctl -fu pwnagotchi
|
||||
tail -f /var/log/pwnagotchi.log
|
||||
|
||||
If you want to know if I'm running, you can use
|
||||
systemctl status pwnagotchi
|
||||
|
@ -1 +1 @@
|
||||
__version__ = '1.5.1'
|
||||
__version__ = '1.5.2'
|
||||
|
@ -44,6 +44,8 @@ def toggle_plugin(name, enable=True):
|
||||
global loaded, database
|
||||
|
||||
if pwnagotchi.config:
|
||||
if not name in pwnagotchi.config['main']['plugins']:
|
||||
pwnagotchi.config['main']['plugins'][name] = dict()
|
||||
pwnagotchi.config['main']['plugins'][name]['enabled'] = enable
|
||||
save_config(pwnagotchi.config, '/etc/pwnagotchi/config.toml')
|
||||
|
||||
|
@ -1,6 +1,7 @@
|
||||
import os
|
||||
import logging
|
||||
import threading
|
||||
from itertools import islice
|
||||
from time import sleep
|
||||
from datetime import datetime,timedelta
|
||||
from pwnagotchi import plugins
|
||||
@ -90,7 +91,7 @@ TEMPLATE = """
|
||||
{% endblock %}
|
||||
|
||||
{% block script %}
|
||||
var content = document.getElementById('content');
|
||||
var table = document.getElementById('table');
|
||||
var filter = document.getElementById('filter');
|
||||
var filterVal = filter.value.toUpperCase();
|
||||
|
||||
@ -154,10 +155,10 @@ TEMPLATE = """
|
||||
tr.className = colorClass;
|
||||
|
||||
if (filterVal.length > 0 && value.toUpperCase().indexOf(filterVal) == -1) {
|
||||
tr.style.visibility = "collapse";
|
||||
tr.style.display = "none";
|
||||
}
|
||||
|
||||
content.appendChild(tr);
|
||||
table.appendChild(tr);
|
||||
});
|
||||
position = messages.length - 1;
|
||||
}
|
||||
@ -193,25 +194,15 @@ TEMPLATE = """
|
||||
|
||||
function doneTyping() {
|
||||
document.body.style.cursor = 'progress';
|
||||
var table, tr, tds, td, i, txtValue;
|
||||
var tr, tds, td, i, txtValue;
|
||||
filterVal = filter.value.toUpperCase();
|
||||
table = document.getElementById("content");
|
||||
tr = table.getElementsByTagName("tr");
|
||||
for (i = 0; i < tr.length; i++) {
|
||||
tds = tr[i].getElementsByTagName("td");
|
||||
if (tds) {
|
||||
for (l = 0; l < tds.length; l++) {
|
||||
td = tds[l];
|
||||
if (td) {
|
||||
txtValue = td.textContent || td.innerText;
|
||||
if (txtValue.toUpperCase().indexOf(filterVal) > -1) {
|
||||
tr[i].style.visibility = "visible";
|
||||
break;
|
||||
} else {
|
||||
tr[i].style.visibility = "collapse";
|
||||
}
|
||||
}
|
||||
}
|
||||
for (i = 1; i < tr.length; i++) {
|
||||
txtValue = tr[i].textContent || tr[i].innerText;
|
||||
if (txtValue.toUpperCase().indexOf(filterVal) > -1) {
|
||||
tr[i].style.display = "table-row";
|
||||
} else {
|
||||
tr[i].style.display = "none";
|
||||
}
|
||||
}
|
||||
document.body.style.cursor = 'default';
|
||||
@ -225,7 +216,7 @@ TEMPLATE = """
|
||||
<span><input checked type="checkbox" id="autoscroll"></span>
|
||||
<span><label for="autoscroll"> Autoscroll to bottom</label><br></span>
|
||||
</div>
|
||||
<table id="content">
|
||||
<table id="table">
|
||||
<thead>
|
||||
<th>
|
||||
Time
|
||||
@ -273,7 +264,10 @@ class Logtail(plugins.Plugin):
|
||||
if path == 'stream':
|
||||
def generate():
|
||||
with open(self.config['main']['log']['path']) as f:
|
||||
yield f.read()
|
||||
# https://stackoverflow.com/questions/39549426/read-multiple-lines-from-a-file-batch-by-batch/39549901#39549901
|
||||
n = 1024
|
||||
for n_lines in iter(lambda: ''.join(islice(f, n)), ''):
|
||||
yield n_lines
|
||||
while True:
|
||||
yield f.readline()
|
||||
|
||||
|
@ -9,7 +9,7 @@ frame_lock = Lock()
|
||||
|
||||
def update_frame(img):
|
||||
global frame_lock, frame_path, frame_format
|
||||
if not os.path.exists(os.path.basename(frame_path)):
|
||||
os.makedirs(os.path.basename(frame_path))
|
||||
if not os.path.exists(os.path.dirname(frame_path)):
|
||||
os.makedirs(os.path.dirname(frame_path))
|
||||
with frame_lock:
|
||||
img.save(frame_path, format=frame_format)
|
||||
|
Loading…
x
Reference in New Issue
Block a user