mirror of
https://github.com/onionshare/onionshare.git
synced 2024-12-24 23:09:42 -05:00
refactored GUI to use a second flask server for communication
This commit is contained in:
parent
9daa475cc0
commit
67ea5b5c2c
@ -2,4 +2,5 @@ include LICENSE
|
|||||||
include README.md
|
include README.md
|
||||||
include onionshare/*.html
|
include onionshare/*.html
|
||||||
include onionshare/strings.json
|
include onionshare/strings.json
|
||||||
include onionshare_gui/html/*
|
include onionshare_gui/templates/*
|
||||||
|
include onionshare_gui/static/*
|
||||||
|
@ -1,14 +0,0 @@
|
|||||||
<!DOCTYPE html>
|
|
||||||
<html>
|
|
||||||
<head>
|
|
||||||
<link rel="stylesheet" type="text/css" media="all" href="style.css" />
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<h1><span id="basename"></span></h1>
|
|
||||||
<div id="output"></div>
|
|
||||||
<button class="button" id="copy-button">Copy URL</button>
|
|
||||||
|
|
||||||
<script src="jquery-1.11.1.min.js"></script>
|
|
||||||
<script src="onionshare.js"></script>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
@ -1,24 +0,0 @@
|
|||||||
function send(msg) {
|
|
||||||
document.title = "null";
|
|
||||||
document.title = msg;
|
|
||||||
}
|
|
||||||
|
|
||||||
function init(basename, strings) {
|
|
||||||
$('#basename').html(basename).show();
|
|
||||||
}
|
|
||||||
|
|
||||||
function url_is_set() {
|
|
||||||
$('#copy-button')
|
|
||||||
.click(function(){
|
|
||||||
send('copy_url');
|
|
||||||
})
|
|
||||||
.show();
|
|
||||||
}
|
|
||||||
|
|
||||||
function update(msg) {
|
|
||||||
var $line = $('<p></p>').append(msg);
|
|
||||||
$('#output').append($line);
|
|
||||||
|
|
||||||
// scroll to bottom
|
|
||||||
$('#output').scrollTop($('#output').height());
|
|
||||||
}
|
|
@ -1,13 +1,5 @@
|
|||||||
import onionshare, webgui
|
import onionshare, webapp
|
||||||
import os, sys, time, json, gtk, gobject, thread
|
import threading, gtk, gobject, webkit, os, sys
|
||||||
|
|
||||||
url = None
|
|
||||||
|
|
||||||
class Global(object):
|
|
||||||
quit = False
|
|
||||||
@classmethod
|
|
||||||
def set_quit(cls, *args, **kwargs):
|
|
||||||
cls.quit = True
|
|
||||||
|
|
||||||
def alert(msg, type=gtk.MESSAGE_INFO):
|
def alert(msg, type=gtk.MESSAGE_INFO):
|
||||||
dialog = gtk.MessageDialog(
|
dialog = gtk.MessageDialog(
|
||||||
@ -48,84 +40,67 @@ def select_file(strings):
|
|||||||
basename = os.path.basename(filename)
|
basename = os.path.basename(filename)
|
||||||
return filename, basename
|
return filename, basename
|
||||||
|
|
||||||
|
def start_webapp(webapp_port, onionshare_port, filename, onion_host):
|
||||||
|
webapp.onionshare = onionshare
|
||||||
|
webapp.onionshare_port = onionshare_port
|
||||||
|
webapp.filename = filename
|
||||||
|
webapp.onion_host = onion_host
|
||||||
|
webapp.app.run(port=webapp_port)
|
||||||
|
|
||||||
|
def launch_window(webapp_port, onionshare_port):
|
||||||
|
def on_destroy(widget, data=None):
|
||||||
|
onionshare.tails_close_port(onionshare_port)
|
||||||
|
gtk.main_quit()
|
||||||
|
|
||||||
|
window = gtk.Window()
|
||||||
|
window.set_title('OnionShare')
|
||||||
|
window.resize(550, 300)
|
||||||
|
window.set_resizable(False)
|
||||||
|
window.connect('destroy', on_destroy)
|
||||||
|
|
||||||
|
box = gtk.VBox(homogeneous=False, spacing=0)
|
||||||
|
window.add(box)
|
||||||
|
|
||||||
|
browser = webkit.WebView()
|
||||||
|
box.pack_start(browser, expand=True, fill=True, padding=0)
|
||||||
|
|
||||||
|
window.show_all()
|
||||||
|
|
||||||
|
# wait half a second for server to start
|
||||||
|
gobject.timeout_add(500, browser.open, 'http://127.0.0.1:{0}/'.format(webapp_port))
|
||||||
|
|
||||||
|
gtk.main()
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
global url
|
onionshare.strings = onionshare.load_strings()
|
||||||
strings = onionshare.load_strings()
|
|
||||||
|
|
||||||
# try starting hidden service
|
# try starting hidden service
|
||||||
port = onionshare.choose_port()
|
onionshare_port = onionshare.choose_port()
|
||||||
try:
|
try:
|
||||||
onion_host = onionshare.start_hidden_service(port)
|
onion_host = onionshare.start_hidden_service(onionshare_port)
|
||||||
except onionshare.NoTor as e:
|
except onionshare.NoTor as e:
|
||||||
alert(e.args[0], gtk.MESSAGE_ERROR)
|
alert(e.args[0], gtk.MESSAGE_ERROR)
|
||||||
return
|
return
|
||||||
onionshare.tails_open_port(port)
|
onionshare.tails_open_port(onionshare_port)
|
||||||
|
|
||||||
# select file to share
|
# select file to share
|
||||||
filename, basename = select_file(strings)
|
filename, basename = select_file(onionshare.strings)
|
||||||
if not filename:
|
if not filename:
|
||||||
return
|
return
|
||||||
|
|
||||||
# open the window, launching webkit browser
|
# start the gui web server
|
||||||
webgui.start_gtk_thread()
|
webapp_port = onionshare.choose_port()
|
||||||
browser, web_recv, web_send = webgui.sync_gtk_msg(webgui.launch_window)(
|
t = threading.Thread(target=start_webapp, kwargs={
|
||||||
title="OnionShare | {0}".format(basename),
|
'webapp_port': webapp_port,
|
||||||
quit_function=Global.set_quit,
|
'onionshare_port': onionshare_port,
|
||||||
echo=False)
|
'filename': filename,
|
||||||
|
'onion_host': onion_host
|
||||||
|
})
|
||||||
|
t.daemon = True
|
||||||
|
t.start()
|
||||||
|
|
||||||
# clipboard
|
# launch the window
|
||||||
clipboard = gtk.clipboard_get(gtk.gdk.SELECTION_CLIPBOARD)
|
launch_window(webapp_port, onionshare_port)
|
||||||
def set_clipboard():
|
|
||||||
global url
|
|
||||||
clipboard.set_text(url)
|
|
||||||
web_send("update('{0}')".format('Copied secret URL to clipboard.'))
|
|
||||||
|
|
||||||
# the async nature of things requires startup to be split into multiple functions
|
|
||||||
def startup_async():
|
|
||||||
global url
|
|
||||||
filehash, filesize = onionshare.file_crunching(filename)
|
|
||||||
onionshare.set_file_info(filename, filehash, filesize)
|
|
||||||
url = 'http://{0}/{1}'.format(onion_host, onionshare.slug)
|
|
||||||
web_send("update('{0}')".format(strings['give_this_url'].replace('\'', '\\\'')))
|
|
||||||
web_send("update('<strong>{0}</strong>')".format(url))
|
|
||||||
web_send("url_is_set()")
|
|
||||||
|
|
||||||
# clipboard needs a bit of time before copying url
|
|
||||||
gobject.timeout_add(500, set_clipboard)
|
|
||||||
|
|
||||||
def startup_sync():
|
|
||||||
web_send("init('{0}', {1});".format(basename, json.dumps(strings)))
|
|
||||||
web_send("update('{0}')".format(strings['calculating_sha1']))
|
|
||||||
|
|
||||||
# run other startup in the background
|
|
||||||
thread_crunch = thread.start_new_thread(startup_async, ())
|
|
||||||
|
|
||||||
# start the web server
|
|
||||||
thread_web = thread.start_new_thread(onionshare.app.run, (), {"port": port})
|
|
||||||
|
|
||||||
gobject.timeout_add(500, startup_sync)
|
|
||||||
|
|
||||||
# main loop
|
|
||||||
last_second = time.time()
|
|
||||||
uptime_seconds = 1
|
|
||||||
clicks = 0
|
|
||||||
while not Global.quit:
|
|
||||||
|
|
||||||
current_time = time.time()
|
|
||||||
again = False
|
|
||||||
msg = web_recv()
|
|
||||||
if msg:
|
|
||||||
again = True
|
|
||||||
|
|
||||||
# check msg for messages from the browser
|
|
||||||
if msg == 'copy_url':
|
|
||||||
set_clipboard()
|
|
||||||
|
|
||||||
if not again:
|
|
||||||
time.sleep(0.1)
|
|
||||||
|
|
||||||
# shutdown
|
|
||||||
onionshare.tails_close_port(port)
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
main()
|
main()
|
||||||
|
BIN
onionshare_gui/static/loader_large.gif
Normal file
BIN
onionshare_gui/static/loader_large.gif
Normal file
Binary file not shown.
After Width: | Height: | Size: 37 KiB |
Before Width: | Height: | Size: 8.3 KiB After Width: | Height: | Size: 8.3 KiB |
47
onionshare_gui/static/onionshare.js
Normal file
47
onionshare_gui/static/onionshare.js
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
$(function(){
|
||||||
|
onionshare = {}
|
||||||
|
|
||||||
|
function update($msg) {
|
||||||
|
var $line = $('<p></p>').append($msg);
|
||||||
|
$('#output').append($line);
|
||||||
|
|
||||||
|
// scroll to bottom
|
||||||
|
$('#output').scrollTop($('#output').height());
|
||||||
|
}
|
||||||
|
|
||||||
|
function linebreak() {
|
||||||
|
update($('<hr>'));
|
||||||
|
}
|
||||||
|
|
||||||
|
function copy_to_clipboard() {
|
||||||
|
$.ajax({
|
||||||
|
url: '/copy_url',
|
||||||
|
success: function(data, textStatus, jqXHR){
|
||||||
|
update('Copied secret URL to clipboard.');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
$('#copy-button').click(copy_to_clipboard);
|
||||||
|
|
||||||
|
// start onionshare
|
||||||
|
$.ajax({
|
||||||
|
url: '/start_onionshare',
|
||||||
|
success: function(data, textStatus, jqXHR){
|
||||||
|
onionshare = JSON.parse(data);
|
||||||
|
|
||||||
|
$('#basename').html(onionshare.basename);
|
||||||
|
update("Sharing file: "+onionshare.basename+" ("+onionshare.filesize+" bytes)");
|
||||||
|
update("SHA1 checksum: "+onionshare.filehash);
|
||||||
|
linebreak();
|
||||||
|
update(onionshare.strings['give_this_url']);
|
||||||
|
update($('<strong>').html(onionshare.url));
|
||||||
|
linebreak();
|
||||||
|
copy_to_clipboard();
|
||||||
|
$('#copy-button').show();
|
||||||
|
|
||||||
|
$('#loading').hide();
|
||||||
|
$('#content').show();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
@ -84,3 +84,18 @@ p {
|
|||||||
background-position: top left;
|
background-position: top left;
|
||||||
background-repeat: no-repeat;
|
background-repeat: no-repeat;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#loading {
|
||||||
|
width: 550px;
|
||||||
|
height: 300px;
|
||||||
|
background-color: #333333;
|
||||||
|
background-image: url('/static/loader_large.gif');
|
||||||
|
background-repeat: no-repeat;
|
||||||
|
background-position: center center;
|
||||||
|
}
|
||||||
|
|
||||||
|
#content {
|
||||||
|
width: 550px;
|
||||||
|
height: 300px;
|
||||||
|
display: none;
|
||||||
|
}
|
17
onionshare_gui/templates/index.html
Normal file
17
onionshare_gui/templates/index.html
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<link rel="stylesheet" type="text/css" media="all" href="static/style.css" />
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div id="loading"></div>
|
||||||
|
<div id="content">
|
||||||
|
<h1><span id="basename"></span></h1>
|
||||||
|
<div id="output"></div>
|
||||||
|
<button class="button" id="copy-button">Copy URL</button>-
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<script src="static/jquery-1.11.1.min.js"></script>
|
||||||
|
<script src="static/onionshare.js"></script>
|
||||||
|
</body>
|
||||||
|
</html>
|
46
onionshare_gui/webapp.py
Normal file
46
onionshare_gui/webapp.py
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
from flask import Flask, render_template
|
||||||
|
import threading, json, os, gtk
|
||||||
|
|
||||||
|
onionshare = None
|
||||||
|
onionshare_port = None
|
||||||
|
filename = None
|
||||||
|
onion_host = None
|
||||||
|
|
||||||
|
clipboard = gtk.clipboard_get(gtk.gdk.SELECTION_CLIPBOARD)
|
||||||
|
url = None
|
||||||
|
|
||||||
|
app = Flask(__name__, template_folder='./templates')
|
||||||
|
|
||||||
|
@app.route("/")
|
||||||
|
def index():
|
||||||
|
return render_template('index.html')
|
||||||
|
|
||||||
|
@app.route("/start_onionshare")
|
||||||
|
def start_onionshare():
|
||||||
|
global onionshare, onionshare_port, filename, onion_host, url
|
||||||
|
|
||||||
|
url = 'http://{0}/{1}'.format(onion_host, onionshare.slug)
|
||||||
|
|
||||||
|
basename = os.path.basename(filename)
|
||||||
|
filehash, filesize = onionshare.file_crunching(filename)
|
||||||
|
onionshare.set_file_info(filename, filehash, filesize)
|
||||||
|
|
||||||
|
# start onionshare service in new thread
|
||||||
|
t = threading.Thread(target=onionshare.app.run, kwargs={'port': onionshare_port})
|
||||||
|
t.daemon = True
|
||||||
|
t.start()
|
||||||
|
|
||||||
|
return json.dumps({
|
||||||
|
'strings': onionshare.strings,
|
||||||
|
'basename': basename,
|
||||||
|
'filehash': filehash,
|
||||||
|
'filesize': filesize,
|
||||||
|
'url': url
|
||||||
|
})
|
||||||
|
|
||||||
|
@app.route("/copy_url")
|
||||||
|
def copy_url():
|
||||||
|
global clipboard
|
||||||
|
clipboard.set_text(url)
|
||||||
|
return ''
|
||||||
|
|
@ -1,79 +0,0 @@
|
|||||||
import time, Queue, thread, gtk, gobject, os, webkit
|
|
||||||
|
|
||||||
def async_gtk_msg(fun):
|
|
||||||
def worker((function, args, kwargs)):
|
|
||||||
apply(function, args, kwargs)
|
|
||||||
|
|
||||||
def fun2(*args, **kwargs):
|
|
||||||
gobject.idle_add(worker, (fun, args, kwargs))
|
|
||||||
|
|
||||||
return fun2
|
|
||||||
|
|
||||||
def sync_gtk_msg(fun):
|
|
||||||
class NoResult: pass
|
|
||||||
|
|
||||||
def worker((R, function, args, kwargs)):
|
|
||||||
R.result = apply(function, args, kwargs)
|
|
||||||
|
|
||||||
def fun2(*args, **kwargs):
|
|
||||||
class R: result = NoResult
|
|
||||||
gobject.idle_add(worker, (R, fun, args, kwargs))
|
|
||||||
while R.result is NoResult: time.sleep(0.01)
|
|
||||||
return R.result
|
|
||||||
|
|
||||||
return fun2
|
|
||||||
|
|
||||||
def launch_window(title='OnionShare', quit_function=None, echo=True):
|
|
||||||
window = gtk.Window()
|
|
||||||
window.set_title(title)
|
|
||||||
browser = webkit.WebView()
|
|
||||||
|
|
||||||
box = gtk.VBox(homogeneous=False, spacing=0)
|
|
||||||
window.add(box)
|
|
||||||
|
|
||||||
if quit_function is not None:
|
|
||||||
window.connect('destroy', quit_function)
|
|
||||||
|
|
||||||
box.pack_start(browser, expand=True, fill=True, padding=0)
|
|
||||||
|
|
||||||
window.set_default_size(600, 600)
|
|
||||||
window.set_resizable(False)
|
|
||||||
window.show_all()
|
|
||||||
|
|
||||||
message_queue = Queue.Queue()
|
|
||||||
|
|
||||||
def callback_wrapper(widget, frame, title):
|
|
||||||
if title != 'null':
|
|
||||||
message_queue.put(title)
|
|
||||||
browser.connect('title-changed', callback_wrapper)
|
|
||||||
|
|
||||||
browser.open('file://'+os.path.abspath(os.path.dirname(__file__))+'/html/index.html')
|
|
||||||
|
|
||||||
def web_recv():
|
|
||||||
if message_queue.empty():
|
|
||||||
return None
|
|
||||||
else:
|
|
||||||
msg = message_queue.get()
|
|
||||||
if echo: print '>>>', msg
|
|
||||||
return msg
|
|
||||||
|
|
||||||
def web_send(msg):
|
|
||||||
if echo: print '<<<', msg
|
|
||||||
async_gtk_msg(browser.execute_script)(msg)
|
|
||||||
|
|
||||||
return browser, web_recv, web_send
|
|
||||||
|
|
||||||
|
|
||||||
def start_gtk_thread():
|
|
||||||
# Start GTK in its own thread:
|
|
||||||
gtk.gdk.threads_init()
|
|
||||||
thread.start_new_thread(gtk.main, ())
|
|
||||||
|
|
||||||
def kill_gtk_thread():
|
|
||||||
async_gtk_msg(gtk.main_quit)()
|
|
||||||
|
|
||||||
def main():
|
|
||||||
if not select_file():
|
|
||||||
return
|
|
||||||
|
|
||||||
launch_browser()
|
|
Loading…
Reference in New Issue
Block a user