misc: several improvements on the web ui

This commit is contained in:
Simone Margaritelli 2019-11-13 14:37:13 +01:00
parent 6e26463278
commit b1d8aa3ba1
14 changed files with 304 additions and 405 deletions

View File

@ -32,7 +32,10 @@ if __name__ == '__main__':
help="Enable debug logs.") help="Enable debug logs.")
parser.add_argument('--version', dest="version", action="store_true", default=False, parser.add_argument('--version', dest="version", action="store_true", default=False,
help="Prints the version.") help="Print the version.")
parser.add_argument('--print-config', dest="print_config", action="store_true", default=False,
help="Print the configuration.")
args = parser.parse_args() args = parser.parse_args()
@ -41,6 +44,10 @@ if __name__ == '__main__':
exit(0) exit(0)
config = utils.load_config(args) config = utils.load_config(args)
if args.print_config:
print(yaml.dump(config, default_flow_style=False))
exit(0)
utils.setup_logging(args, config) utils.setup_logging(args, config)
pwnagotchi.set_name(config['main']['name']) pwnagotchi.set_name(config['main']['name'])
@ -53,8 +60,6 @@ if __name__ == '__main__':
logging.info("%s@%s (v%s)" % (pwnagotchi.name(), agent.fingerprint(), pwnagotchi.version)) logging.info("%s@%s (v%s)" % (pwnagotchi.name(), agent.fingerprint(), pwnagotchi.version))
logging.debug("effective configuration:\n\n%s\n\n" % yaml.dump(config, default_flow_style=False))
for _, plugin in plugins.loaded.items(): for _, plugin in plugins.loaded.items():
logging.debug("plugin '%s' v%s" % (plugin.__class__.__name__, plugin.__version__)) logging.debug("plugin '%s' v%s" % (plugin.__class__.__name__, plugin.__version__))

View File

@ -12,8 +12,12 @@ API_ADDRESS = "http://127.0.0.1:8666/api/v1"
def is_connected(): def is_connected():
try: try:
socket.create_connection(("api.pwnagotchi.ai", 443), timeout=30) # check DNS
return True host = socket.gethostbyname('api.pwnagotchi.ai')
if host:
# check connectivity itself
socket.create_connection((host, 443), timeout=30)
return True
except: except:
pass pass
return False return False

View File

@ -119,12 +119,14 @@ class View(object):
def _refresh_handler(self): def _refresh_handler(self):
delay = 1.0 / self._config['ui']['fps'] delay = 1.0 / self._config['ui']['fps']
# logging.info("view refresh handler started with period of %.2fs" % delay)
while True: while True:
name = self._state.get('name') try:
self.set('name', name.rstrip('').strip() if '' in name else (name + '')) name = self._state.get('name')
self.update() self.set('name', name.rstrip('').strip() if '' in name else (name + ''))
self.update()
except Exception as e:
logging.warning("non fatal error while updating view: %s" % e)
time.sleep(delay) time.sleep(delay)
def set(self, key, value): def set(self, key, value):
@ -360,14 +362,15 @@ class View(object):
if self._frozen: if self._frozen:
return return
changes = self._state.changes(ignore=self._ignore_changes) state = self._state
changes = state.changes(ignore=self._ignore_changes)
if force or len(changes): if force or len(changes):
self._canvas = Image.new('1', (self._width, self._height), WHITE) self._canvas = Image.new('1', (self._width, self._height), WHITE)
drawer = ImageDraw.Draw(self._canvas) drawer = ImageDraw.Draw(self._canvas)
plugins.on('ui_update', self) plugins.on('ui_update', self)
for key, lv in self._state.items(): for key, lv in state.items():
lv.draw(self._canvas, drawer) lv.draw(self._canvas, drawer)
web.update_frame(self._canvas) web.update_frame(self._canvas)

View File

@ -3,6 +3,7 @@ import os
import base64 import base64
import _thread import _thread
import secrets import secrets
import json
from functools import wraps from functools import wraps
# https://stackoverflow.com/questions/14888799/disable-console-messages-in-flask-server # https://stackoverflow.com/questions/14888799/disable-console-messages-in-flask-server
@ -61,9 +62,11 @@ class Handler:
@wraps(f) @wraps(f)
def wrapper(*args, **kwargs): def wrapper(*args, **kwargs):
auth = request.authorization auth = request.authorization
if not auth or not auth.username or not auth.password or not self._check_creds(auth.username, auth.password): if not auth or not auth.username or not auth.password or not self._check_creds(auth.username,
auth.password):
return Response('Unauthorized', 401, {'WWW-Authenticate': 'Basic realm="Unauthorized"'}) return Response('Unauthorized', 401, {'WWW-Authenticate': 'Basic realm="Unauthorized"'})
return f(*args, **kwargs) return f(*args, **kwargs)
return wrapper return wrapper
def index(self): def index(self):
@ -82,6 +85,9 @@ class Handler:
error = None error = None
try: try:
if not grid.is_connected():
raise Exception('not connected')
inbox = grid.inbox(page, with_pager=True) inbox = grid.inbox(page, with_pager=True)
except Exception as e: except Exception as e:
logging.exception('error while reading pwnmail inbox') logging.exception('error while reading pwnmail inbox')
@ -106,7 +112,7 @@ class Handler:
return render_template('profile.html', return render_template('profile.html',
name=pwnagotchi.name(), name=pwnagotchi.name(),
fingerprint=self._agent.fingerprint(), fingerprint=self._agent.fingerprint(),
data=data, data=json.dumps(data, indent=2),
error=error) error=error)
def inbox_peers(self): def inbox_peers(self):
@ -129,6 +135,9 @@ class Handler:
error = None error = None
try: try:
if not grid.is_connected():
raise Exception('not connected')
message = grid.inbox_message(id) message = grid.inbox_message(id)
if message['data']: if message['data']:
message['data'] = base64.b64decode(message['data']).decode("utf-8") message['data'] = base64.b64decode(message['data']).decode("utf-8")
@ -151,6 +160,9 @@ class Handler:
error = None error = None
try: try:
if not grid.is_connected():
raise Exception('not connected')
grid.send_message(to, message) grid.send_message(to, message)
except Exception as e: except Exception as e:
error = str(e) error = str(e)
@ -158,6 +170,9 @@ class Handler:
return jsonify({"error": error}) return jsonify({"error": error})
def mark_message(self, id, mark): def mark_message(self, id, mark):
if not grid.is_connected():
abort(200)
logging.info("marking message %d as %s" % (int(id), mark)) logging.info("marking message %d as %s" % (int(id), mark))
grid.mark_message(id, mark) grid.mark_message(id, mark)
return redirect("/inbox") return redirect("/inbox")

View File

@ -35,6 +35,7 @@ class Server:
static_url_path='', static_url_path='',
static_folder=os.path.join(web_path, 'static'), static_folder=os.path.join(web_path, 'static'),
template_folder=os.path.join(web_path, 'templates')) template_folder=os.path.join(web_path, 'templates'))
app.secret_key = secrets.token_urlsafe(256) app.secret_key = secrets.token_urlsafe(256)
if self._origin: if self._origin:

View File

@ -1,22 +1,7 @@
form { .ui-image {
margin-block-end: 0; width: 100%;
} }
.content {
position: absolute;
top: 0;
left: 0;
width: 100vw;
height: 100vh;
height: calc(var(--vh, 1vh) * 100);
display: flex;
flex-direction: column;
}
/**
* make sure image is displayed without any blur
*/
.pixelated { .pixelated {
image-rendering: optimizeSpeed; /* Legal fallback */ image-rendering: optimizeSpeed; /* Legal fallback */
image-rendering: -moz-crisp-edges; /* Firefox */ image-rendering: -moz-crisp-edges; /* Firefox */
@ -33,33 +18,6 @@ form {
position: relative; position: relative;
} }
.ui-image {
position: absolute;
top: 0;
right: 0;
bottom: 0;
left: 0;
max-width: 100vw;
height: 100%;
object-fit: contain;
object-position: 50% 0;
}
.buttons-wrapper {
flex-shrink: 0;
display: flex;
flex-wrap: wrap;
padding: 0 16px;
}
.button {
border: 1px solid black;
border-radius: 4px;
font-size: 2em;
background: #f8b506;
margin: 16px;
}
div.status { div.status {
position: absolute; position: absolute;
top: 0; top: 0;

View File

@ -1,7 +0,0 @@
window.onload = function() {
var image = document.getElementById("ui");
function updateImage() {
image.src = image.src.split("?")[0] + "?" + new Date().getTime();
}
setInterval(updateImage, 1000);
}

View File

@ -0,0 +1,71 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>
{% block title %}
{% endblock %}
</title>
<link rel="stylesheet" href="/js/jquery.mobile/jquery.mobile-1.4.5.min.css"/>
<script type="text/javascript" src="/js/jquery-1.12.4.min.js"></script>
<script type="text/javascript" src="/js/jquery.mobile/jquery.mobile-1.4.5.min.js"></script>
<script type="text/javascript" src="/js/jquery.timeago.js"></script>
<script type="text/javascript" src="/js/jquery-qrcode-0.17.0.min.js"></script>
<link rel="stylesheet" type="text/css" href="/css/style.css"/>
<script type="text/javascript">
$.mobile.ajaxEnabled = false;
jQuery(document).ready(function() {
jQuery("time.timeago").timeago();
});
{% block script %}
{% endblock %}
</script>
</head>
<body>
<div data-role="page">
{% if error %}
<div id="error" class="error ui-content" data-role="popup" data-overlay-theme="a" data-theme="b">
<p>{{ error }}</p>
</div>
<script>
$(function(){
$("#error").popup("open");
});
</script>
{% endif %}
{% set navigation = [
( '/', 'home', 'eye', 'Home' ),
( '/inbox', 'inbox', 'bars', 'Inbox' ),
( '/inbox/new', 'new', 'mail', 'New' ),
( '/inbox/profile', 'profile', 'info', 'Profile' ),
( '/inbox/peers', 'peers', 'user', 'Peers' ),
] %}
{% set active_page = active_page|default('inbox') %}
<div data-role="footer">
<div data-role="navbar" data-iconpos="left">
<ul>
{% for href, id, icon, caption in navigation %}
<li>
<a href="{{ href }}" id="{{ id }}" data-icon="{{ icon }}" class="{{ 'ui-btn-active' if active_page == id }}">{{ caption }}</a>
</li>
{% endfor %}
</ul>
</div>
</div>
{% block content %}
{% endblock %}
</div>
</body>
</html>

View File

@ -1,81 +1,38 @@
<!DOCTYPE html> {% extends "base.html" %}
<html> {% set active_page = "inbox" %}
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>{{ name }} Inbox</title> {% block title %}
{{ name }} Inbox
{% endblock %}
<link rel="stylesheet" href="/js/jquery.mobile/jquery.mobile-1.4.5.min.css"/> {% block content %}
<script type="text/javascript" src="/js/jquery-1.12.4.min.js"></script> <ul class="inbox" data-role="listview" data-filter="true" data-filter-placeholder="Search inbox..." data-inset="true">
<script type="text/javascript" src="/js/jquery.mobile/jquery.mobile-1.4.5.min.js"></script> {% for message in inbox.messages %}
<script type="text/javascript" src="/js/jquery.timeago.js"></script> <li class="message">
<a href="/inbox/{{ message.id }}" class="{{ 'unread' if not message.seen_at else 'read' }}">
<h2>{{ message.sender_name }}@{{ message.sender }}</h2>
<p>
Received
<time class="timeago" datetime="{{ message.created_at }}">{{ message.created_at }}</time>
{% if message.seen_at %}, seen
<time class="timeago" datetime="{{ message.seen_at }}">{{ message.seen_at }}</time>
{% endif %}.
</p>
</a>
</li>
{% endfor %}
</ul>
<link rel="stylesheet" type="text/css" href="/css/style.css"/> {% if inbox.pages > 1 %}
<div data-role="navbar">
<script type="text/javascript"> <ul>
$.mobile.ajaxEnabled = false; {% if page > 1 %}
<li><a href="/inbox?p={{ page - 1 }}" class="ui-btn">Prev</a></li>
jQuery(document).ready(function() { {% endif %}
jQuery("time.timeago").timeago(); {% if page < inbox.pages %}
}); <li><a href="/inbox?p={{ page + 1 }}" class="ui-btn">Next</a></li>
</script> {% endif %}
</head>
<body>
<div data-role="page">
{% if error %}
<div class="error">{{ error }}</div>
{% else %}
{% if inbox.records == 0 %}
<small>Inbox is empty.</small>
{% else %}
<div data-role="footer">
<div data-role="navbar">
<ul>
<li><a href="/inbox" id="email" class="ui-btn-active" data-icon="bars">Inbox</a></li>
<li><a href="/inbox/new" id="new" data-icon="mail">New</a></li>
<li><a href="/inbox/profile" id="profile" data-icon="info">Profile</a></li>
<li><a href="/inbox/peers" id="peers" data-icon="user">Peers</a></li>
</ul>
</div>
</div>
<ul class="inbox" data-role="listview" data-filter="true" data-filter-placeholder="Search inbox..." data-inset="true">
{% for message in inbox.messages %}
<li class="message">
<a href="/inbox/{{ message.id }}" class="{{ 'unread' if not message.seen_at else 'read' }}">
<h2>{{ message.sender_name }}@{{ message.sender }}</h2>
<p>
Received
<time class="timeago" datetime="{{ message.created_at }}">{{ message.created_at }}</time>
{% if message.seen_at %}, seen
<time class="timeago" datetime="{{ message.seen_at }}">{{ message.seen_at }}</time>
{% endif %}.
</p>
</a>
</li>
{% endfor %}
</ul> </ul>
{% endif %}
{% if inbox.pages > 1 %}
<div data-role="navbar">
<ul>
{% if page > 1 %}
<li><a href="/inbox?p={{ page - 1 }}" class="ui-btn">Prev</a></li>
{% endif %}
{% if page < inbox.pages %}
<li><a href="/inbox?p={{ page + 1 }}" class="ui-btn">Next</a></li>
{% endif %}
</ul>
</div>
{% endif %}
{% endif %}
</div> </div>
{% endif %}
</body> {% endblock %}
</html>

View File

@ -1,35 +1,39 @@
<html> {% extends "base.html" %}
<head> {% set active_page = "home" %}
<title>{{ title }}</title>
<link rel="stylesheet" type="text/css" href="/css/style.css"/>
</head>
<body>
<div class="content">
<div class="image-wrapper">
<img class="ui-image pixelated" src="/ui" id="ui"/>
</div>
<div class="buttons-wrapper">
<form class="action" method="POST" action="/shutdown"
onsubmit="return confirm('This will halt the unit, continue?');">
<input type="submit" class="button" value="Shutdown"/>
<input type="hidden" name="csrf_token" value="{{ csrf_token() }}"/>
</form>
<form class="action" method="POST" action="/restart" {% block title %}
onsubmit="return confirm('This will restart the service in {{ other_mode }} mode, continue?');"> {{ title }}
<input type="submit" class="button" value="Restart in {{ other_mode }} mode"/> {% endblock %}
<input type="hidden" name="mode" value="{{ other_mode }}"/>
<input type="hidden" name="csrf_token" value="{{ csrf_token() }}"/>
</form>
<form class="action" method="GET" action="/inbox"> {% block script %}
<input type="submit" class="button" value="PwnMail"/> window.onload = function() {
</form> var image = document.getElementById("ui");
</div> function updateImage() {
image.src = image.src.split("?")[0] + "?" + new Date().getTime();
}
setInterval(updateImage, 1000);
}
{% endblock %}
{% block content %}
<img class="ui-image pixelated" src="/ui" id="ui"/>
<div data-role="navbar">
<ul>
<li>
<form class="action" method="post" action="/shutdown"
onsubmit="return confirm('this will halt the unit, continue?');">
<input type="submit" class="button ui-btn ui-corner-all" value="shutdown"/>
<input type="hidden" name="csrf_token" value="{{ csrf_token() }}"/>
</form>
</li>
<li>
<form class="action" method="post" action="/restart"
onsubmit="return confirm('this will restart the service in {{ other_mode }} mode, continue?');">
<input type="submit" class="button ui-btn ui-corner-all" value="restart in {{ other_mode }} mode"/>
<input type="hidden" name="mode" value="{{ other_mode }}"/>
<input type="hidden" name="csrf_token" value="{{ csrf_token() }}"/>
</form>
</li>
</ul>
</div> </div>
{% endblock %}
<script type="text/javascript" src="/js/refresh.js"></script>
<script type="text/javascript" src="/js/viewportHeight.js"></script>
</body>
</html>

View File

@ -1,70 +1,37 @@
<!DOCTYPE html> {% extends "base.html" %}
<html> {% set active_page = "" %}
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Message from {{ message.sender_name }}</title> {% block title %}
Message from {{ message.sender_name }}
{% endblock %}
<link rel="stylesheet" href="/js/jquery.mobile/jquery.mobile-1.4.5.min.css"/> {% block script %}
<script type="text/javascript" src="/js/jquery-1.12.4.min.js"></script> jQuery(document).ready(function() {
<script type="text/javascript" src="/js/jquery.mobile/jquery.mobile-1.4.5.min.js"></script> // mark the message as read
<script type="text/javascript" src="/js/jquery.timeago.js"></script> jQuery.get("/inbox/{{ message.id }}/seen", function(res){ console.log(res); });
});
{% endblock %}
<link rel="stylesheet" type="text/css" href="/css/style.css"/> {% block content %}
<p class="messagebody">
<script type="text/javascript">
$.mobile.ajaxEnabled = false;
jQuery(document).ready(function() {
jQuery("time.timeago").timeago();
// mark the message as read
jQuery.get("/inbox/{{ message.id }}/seen", function(res){
console.log(res);
});
});
</script>
</head>
<body>
<div data-role="page">
{% if error %}
<div class="error">{{ error }}</div>
{% else %}
<div data-role="footer">
<div data-role="navbar">
<ul>
<li><a href="/inbox" id="email" data-icon="back">Back</a></li>
<li><a href="/inbox/new?to={{ message.sender }}" id="reply" data-icon="edit">Reply</a></li>
<li><a href="/inbox/{{ message.id }}/deleted" id="delete" data-icon="delete"
onclick="return confirm('Are you sure?')">Delete</a></li>
</ul>
</div>
</div>
<p class="messagebody">
<span style="color: #888"> <span style="color: #888">
Message from {{ message.sender_name }}@{{ message.sender }}, received Message from {{ message.sender_name }}@{{ message.sender }}, sent
<time class="timeago" datetime="{{ message.created_at }}">{{ message.created_at }}</time> <time class="timeago" datetime="{{ message.created_at }}">{{ message.created_at }}</time>
{% if message.seen_at %}, seen {% if message.seen_at %}, seen
<time class="timeago" datetime="{{ message.seen_at }}">{{ message.seen_at }}</time>{% endif %}.</span> <time class="timeago" datetime="{{ message.seen_at }}">{{ message.seen_at }}</time>{% endif %}.</span>
<br/> <br/>
<br/> <br/>
{% if message.data %}
<span style="white-space: pre-line">{{ message.data }}</span>
{% else %}
<small>This message is empty.</small>
{% endif %}
</p>
{% if message.data %}
<span style="white-space: pre-line">{{ message.data }}</span>
{% else %}
<small>This message is empty.</small>
{% endif %} {% endif %}
</div> <br/>
<br/>
</body> <a href="/inbox/new?to={{ message.sender }}" class="ui-btn ui-icon-comment ui-btn-icon-left ui-shadow-icon">Reply</a>
</html> <a href="/inbox/{{ message.id }}/deleted" class="ui-btn ui-icon-delete ui-btn-icon-left ui-shadow-icon" onclick="return confirm('Are you sure?')">Delete</a>
</p>
{% endblock %}

View File

@ -1,81 +1,55 @@
<!DOCTYPE html> {% extends "base.html" %}
<html> {% set active_page = "new" %}
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
{% if to %} {% block title %}
<title>Reply to {{ to }}</title> {% if to %}
{% else %} title>Reply to {{ to }}
<title>New Message</title> {% else %}
{% endif %} New Message
{% endif %}
{% endblock %}
<link rel="stylesheet" href="/js/jquery.mobile/jquery.mobile-1.4.5.min.css"/> {% block script %}
<script type="text/javascript" src="/js/jquery-1.12.4.min.js"></script> $(function(){
<script type="text/javascript" src="/js/jquery.mobile/jquery.mobile-1.4.5.min.js"></script> $("#message_form").submit(function(e) {
<script type="text/javascript" src="/js/jquery.timeago.js"></script> e.preventDefault();
<link rel="stylesheet" type="text/css" href="/css/style.css"/> var form = $(this);
var url = form.attr('action');
<script type="text/javascript"> $.ajax({
$.mobile.ajaxEnabled = false; type: "POST",
url: url,
data: form.serialize(),
success: function(data) {
if( data.error ) {
if( data.error.indexOf('404') != -1 )
alert('Fingerprint not found.');
else if( data.error.indexOf('aborted') != -1 )
alert('Empty or invalid message.');
else
alert(data.error);
return;
}
$(function(){ alert("Message sent!");
$("#message_form").submit(function(e) { document.location.href = "/inbox";
e.preventDefault(); }
var form = $(this);
var url = form.attr('action');
$.ajax({
type: "POST",
url: url,
data: form.serialize(),
success: function(data) {
if( data.error ) {
if( data.error.indexOf('404') != -1 )
alert('Fingerprint not found.');
else if( data.error.indexOf('aborted') != -1 )
alert('Empty or invalid message.');
else
alert(data.error);
return;
}
alert("Message sent!");
document.location.href = "/inbox";
}
});
});
}); });
});
});
{% endblock %}
</script> {% block content %}
<div style="padding: 1em">
</head> <form id="message_form" method="POST" action="/inbox/send">
<body> <label for="to">To:</label>
<div data-role="page"> <input type="text" name="to" id="to" value="{{ to }}">
<div data-role="footer">
<div data-role="navbar">
<ul>
<li><a href="/inbox" id="email" data-icon="back">Back</a></li>
</ul>
</div>
</div>
<div style="padding: 1em">
<form id="message_form" method="POST" action="/inbox/send">
<label for="to">To:</label>
<input type="text" name="to" id="to" value="{{ to }}">
<label for="message">Message:</label>
<textarea cols="40" rows="8" name="message" id="message"></textarea>
<input type="hidden" name="csrf_token" value="{{ csrf_token() }}"/>
<input type="submit" class="button" value="Send"/>
</form>
</div>
<label for="message">Message:</label>
<textarea cols="40" rows="8" name="message" id="message"></textarea>
<input type="hidden" name="csrf_token" value="{{ csrf_token() }}"/>
<input type="submit" class="button" value="Send"/>
</form>
</div> </div>
{% endblock %}
</body>
</html>

View File

@ -1,49 +1,21 @@
<!DOCTYPE html> {% extends "base.html" %}
<html> {% set active_page = "peers" %}
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>{{ name }} friends</title> {% block title %}
{{ name }} Friends
{% endblock %}
<link rel="stylesheet" href="/js/jquery.mobile/jquery.mobile-1.4.5.min.css"/> {% block content %}
<script type="text/javascript" src="/js/jquery-1.12.4.min.js"></script> <ul class="peers" data-role="listview" data-filter="true" data-filter-placeholder="Search peers..." data-inset="true">
<script type="text/javascript" src="/js/jquery.mobile/jquery.mobile-1.4.5.min.js"></script> {% for peer in peers %}
<script type="text/javascript" src="/js/jquery.timeago.js"></script> <li class="peer">
<script type="text/javascript" src="/js/jquery-qrcode-0.17.0.min.js"></script> <a href="/inbox/new?to={{ peer.fingerprint }}">
<h2>{{ peer.advertisement.face }} {{ peer.advertisement.name }}@{{ peer.fingerprint }}</h2>
<link rel="stylesheet" type="text/css" href="/css/style.css"/> <p>
Pwned {{ peer.advertisement.pwnd_tot }} networks, {{ peer.encounters }} encounters.
<script type="text/javascript"> </p>
$.mobile.ajaxEnabled = false; </a>
</script> </li>
{% endfor %}
</head> </ul>
<body> {% endblock %}
<div data-role="page">
<div data-role="footer">
<div data-role="navbar">
<ul>
<li><a href="/inbox" id="email" data-icon="back">Back</a></li>
</ul>
</div>
</div>
<ul class="peers" data-role="listview" data-filter="true" data-filter-placeholder="Search peers..." data-inset="true">
{% for peer in peers %}
<li class="peer">
<a href="/inbox/new?to={{ peer.fingerprint }}">
<h2>{{ peer.advertisement.face }} {{ peer.advertisement.name }}@{{ peer.fingerprint }}</h2>
<p>
Pwned {{ peer.advertisement.pwnd_tot }} networks, {{ peer.encounters }} encounters.
</p>
</a>
</li>
{% endfor %}
</ul>
</div>
</body>
</html>

View File

@ -1,60 +1,35 @@
<!DOCTYPE html> {% extends "base.html" %}
<html> {% set active_page = "profile" %}
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Profile</title> {% block title %}
Profile
{% endblock %}
<link rel="stylesheet" href="/js/jquery.mobile/jquery.mobile-1.4.5.min.css"/> {% block script %}
<script type="text/javascript" src="/js/jquery-1.12.4.min.js"></script> $(function(){
<script type="text/javascript" src="/js/jquery.mobile/jquery.mobile-1.4.5.min.js"></script> $('#qrcode').qrcode({
<script type="text/javascript" src="/js/jquery.timeago.js"></script> render: 'div',
<script type="text/javascript" src="/js/jquery-qrcode-0.17.0.min.js"></script> mode: 0,
size: 400,
fontname: 'sans',
fontcolor: '#000'
});
});
{% endblock %}
<link rel="stylesheet" type="text/css" href="/css/style.css"/> {% block content %}
<div style="padding: 1em">
<label for="name">Name</label>
<h4 id="name">{{ name }}</h4>
<script type="text/javascript"> <label for="fingerprint">Fingerprint</label>
$.mobile.ajaxEnabled = false; <h4 id="fingerprint">
$(function(){ <a href="https://pwnagotchi.ai/pwnfile/#{{ fingerprint }}" target="_blank">{{ fingerprint }}</a>
$('#qrcode').qrcode({ </h4>
render: 'div', <div id="qrcode"></div>
mode: 0,
size: 400,
fontname: 'sans',
fontcolor: '#000'
});
});
</script>
</head>
<body>
<div data-role="page">
<div data-role="footer">
<div data-role="navbar">
<ul>
<li><a href="/inbox" id="email" data-icon="back">Back</a></li>
</ul>
</div>
</div>
<div style="padding: 1em">
<label for="name">Name</label>
<h4 id="name">{{ name }}</h4>
<label for="fingerprint">Fingerprint</label>
<h4 id="fingerprint">
<a href="https://pwnagotchi.ai/pwnfile/#{{ fingerprint }}" target="_blank">{{ fingerprint }}</a>
</h4>
<div id="qrcode"></div>
<br/>
<label for="data">Data</label>
<pre><code id="data">{{ data }}</code></pre>
</div>
<br/>
<label for="data">Data</label>
<pre><code id="data">{{ data }}</code></pre>
</div> </div>
{% endblock %}
</body>
</html>