Create separate templates and static folder, and make the web app use both of these. Yay, now we have real static resources
@ -4,7 +4,8 @@ include BUILD.md
|
|||||||
include share/*
|
include share/*
|
||||||
include share/images/*
|
include share/images/*
|
||||||
include share/locale/*
|
include share/locale/*
|
||||||
include share/html/*
|
include share/templates/*
|
||||||
|
include share/static/*
|
||||||
include install/onionshare.desktop
|
include install/onionshare.desktop
|
||||||
include install/onionshare.appdata.xml
|
include install/onionshare.appdata.xml
|
||||||
include install/onionshare80.xpm
|
include install/onionshare80.xpm
|
||||||
|
@ -20,7 +20,8 @@ a = Analysis(
|
|||||||
('../share/torrc_template-windows', 'share'),
|
('../share/torrc_template-windows', 'share'),
|
||||||
('../share/images/*', 'share/images'),
|
('../share/images/*', 'share/images'),
|
||||||
('../share/locale/*', 'share/locale'),
|
('../share/locale/*', 'share/locale'),
|
||||||
('../share/html/*', 'share/html')
|
('../share/templates/*', 'share/templates'),
|
||||||
|
('../share/static/*', 'share/static')
|
||||||
],
|
],
|
||||||
hiddenimports=[],
|
hiddenimports=[],
|
||||||
hookspath=[],
|
hookspath=[],
|
||||||
|
@ -26,12 +26,11 @@ import queue
|
|||||||
import socket
|
import socket
|
||||||
import sys
|
import sys
|
||||||
import tempfile
|
import tempfile
|
||||||
import base64
|
|
||||||
from distutils.version import LooseVersion as Version
|
from distutils.version import LooseVersion as Version
|
||||||
from urllib.request import urlopen
|
from urllib.request import urlopen
|
||||||
|
|
||||||
from flask import (
|
from flask import (
|
||||||
Flask, Response, request, render_template_string, abort, make_response,
|
Flask, Response, request, render_template, abort, make_response,
|
||||||
__version__ as flask_version
|
__version__ as flask_version
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -43,7 +42,9 @@ class Web(object):
|
|||||||
"""
|
"""
|
||||||
def __init__(self, debug, stay_open, gui_mode, receive_mode=False):
|
def __init__(self, debug, stay_open, gui_mode, receive_mode=False):
|
||||||
# The flask app
|
# The flask app
|
||||||
self.app = Flask(__name__)
|
self.app = Flask(__name__,
|
||||||
|
static_folder=common.get_resource_path('static'),
|
||||||
|
template_folder=common.get_resource_path('templates'))
|
||||||
|
|
||||||
# Debug mode?
|
# Debug mode?
|
||||||
if debug:
|
if debug:
|
||||||
@ -88,12 +89,6 @@ class Web(object):
|
|||||||
self.REQUEST_RATE_LIMIT = 5
|
self.REQUEST_RATE_LIMIT = 5
|
||||||
self.q = queue.Queue()
|
self.q = queue.Queue()
|
||||||
|
|
||||||
# Load and base64 encode images to pass into templates
|
|
||||||
self.favicon_b64 = self.base64_image('favicon.ico')
|
|
||||||
self.logo_b64 = self.base64_image('logo.png')
|
|
||||||
self.folder_b64 = self.base64_image('web_folder.png')
|
|
||||||
self.file_b64 = self.base64_image('web_file.png')
|
|
||||||
|
|
||||||
self.slug = None
|
self.slug = None
|
||||||
|
|
||||||
self.download_count = 0
|
self.download_count = 0
|
||||||
@ -137,29 +132,18 @@ class Web(object):
|
|||||||
# currently a download
|
# currently a download
|
||||||
deny_download = not self.stay_open and self.download_in_progress
|
deny_download = not self.stay_open and self.download_in_progress
|
||||||
if deny_download:
|
if deny_download:
|
||||||
r = make_response(render_template_string(
|
r = make_response(render_template('denied.html'))
|
||||||
open(common.get_resource_path('html/denied.html')).read(),
|
return self.add_security_headers(r)
|
||||||
favicon_b64=self.favicon_b64
|
|
||||||
))
|
|
||||||
for header, value in self.security_headers:
|
|
||||||
r.headers.set(header, value)
|
|
||||||
return r
|
|
||||||
|
|
||||||
# If download is allowed to continue, serve download page
|
# If download is allowed to continue, serve download page
|
||||||
r = make_response(render_template_string(
|
r = make_response(render_template(
|
||||||
open(common.get_resource_path('html/send.html')).read(),
|
'send.html',
|
||||||
favicon_b64=self.favicon_b64,
|
|
||||||
logo_b64=self.logo_b64,
|
|
||||||
folder_b64=self.folder_b64,
|
|
||||||
file_b64=self.file_b64,
|
|
||||||
slug=self.slug,
|
slug=self.slug,
|
||||||
file_info=self.file_info,
|
file_info=self.file_info,
|
||||||
filename=os.path.basename(self.zip_filename),
|
filename=os.path.basename(self.zip_filename),
|
||||||
filesize=self.zip_filesize,
|
filesize=self.zip_filesize,
|
||||||
filesize_human=common.human_readable_filesize(self.zip_filesize)))
|
filesize_human=common.human_readable_filesize(self.zip_filesize)))
|
||||||
for header, value in self.security_headers:
|
return self.add_security_headers(r)
|
||||||
r.headers.set(header, value)
|
|
||||||
return r
|
|
||||||
|
|
||||||
@self.app.route("/<slug_candidate>/download")
|
@self.app.route("/<slug_candidate>/download")
|
||||||
def download(slug_candidate):
|
def download(slug_candidate):
|
||||||
@ -172,13 +156,8 @@ class Web(object):
|
|||||||
# currently a download
|
# currently a download
|
||||||
deny_download = not self.stay_open and self.download_in_progress
|
deny_download = not self.stay_open and self.download_in_progress
|
||||||
if deny_download:
|
if deny_download:
|
||||||
r = make_response(render_template_string(
|
r = make_response(render_template('denied.html'))
|
||||||
open(common.get_resource_path('html/denied.html')).read(),
|
return self.add_security_headers(r)
|
||||||
favicon_b64=self.favicon_b64
|
|
||||||
))
|
|
||||||
for header,value in self.security_headers:
|
|
||||||
r.headers.set(header, value)
|
|
||||||
return r
|
|
||||||
|
|
||||||
# each download has a unique id
|
# each download has a unique id
|
||||||
download_id = self.download_count
|
download_id = self.download_count
|
||||||
@ -261,8 +240,7 @@ class Web(object):
|
|||||||
r = Response(generate())
|
r = Response(generate())
|
||||||
r.headers.set('Content-Length', self.zip_filesize)
|
r.headers.set('Content-Length', self.zip_filesize)
|
||||||
r.headers.set('Content-Disposition', 'attachment', filename=basename)
|
r.headers.set('Content-Disposition', 'attachment', filename=basename)
|
||||||
for header,value in self.security_headers:
|
r = self.add_security_headers(r)
|
||||||
r.headers.set(header, value)
|
|
||||||
# guess content type
|
# guess content type
|
||||||
(content_type, _) = mimetypes.guess_type(basename, strict=False)
|
(content_type, _) = mimetypes.guess_type(basename, strict=False)
|
||||||
if content_type is not None:
|
if content_type is not None:
|
||||||
@ -278,15 +256,10 @@ class Web(object):
|
|||||||
self.check_slug_candidate(slug_candidate)
|
self.check_slug_candidate(slug_candidate)
|
||||||
|
|
||||||
# If download is allowed to continue, serve download page
|
# If download is allowed to continue, serve download page
|
||||||
r = make_response(render_template_string(
|
r = make_response(render_template(
|
||||||
open(common.get_resource_path('html/receive.html')).read(),
|
'receive.html',
|
||||||
favicon_b64=self.favicon_b64,
|
|
||||||
logo_b64=self.logo_b64,
|
|
||||||
slug=self.slug))
|
slug=self.slug))
|
||||||
for header, value in self.security_headers:
|
return self.add_security_headers(r)
|
||||||
r.headers.set(header, value)
|
|
||||||
return r
|
|
||||||
|
|
||||||
|
|
||||||
def common_routes(self):
|
def common_routes(self):
|
||||||
"""
|
"""
|
||||||
@ -306,13 +279,8 @@ class Web(object):
|
|||||||
self.force_shutdown()
|
self.force_shutdown()
|
||||||
print(strings._('error_rate_limit'))
|
print(strings._('error_rate_limit'))
|
||||||
|
|
||||||
r = make_response(render_template_string(
|
r = make_response(render_template('404.html'), 404)
|
||||||
open(common.get_resource_path('html/404.html')).read(),
|
return self.add_security_headers(r)
|
||||||
favicon_b64=self.favicon_b64
|
|
||||||
), 404)
|
|
||||||
for header, value in self.security_headers:
|
|
||||||
r.headers.set(header, value)
|
|
||||||
return r
|
|
||||||
|
|
||||||
@self.app.route("/<slug_candidate>/shutdown")
|
@self.app.route("/<slug_candidate>/shutdown")
|
||||||
def shutdown(slug_candidate):
|
def shutdown(slug_candidate):
|
||||||
@ -323,6 +291,14 @@ class Web(object):
|
|||||||
self.force_shutdown()
|
self.force_shutdown()
|
||||||
return ""
|
return ""
|
||||||
|
|
||||||
|
def add_security_headers(self, r):
|
||||||
|
"""
|
||||||
|
Add security headers to a request
|
||||||
|
"""
|
||||||
|
for header, value in self.security_headers:
|
||||||
|
r.headers.set(header, value)
|
||||||
|
return r
|
||||||
|
|
||||||
def set_file_info(self, filenames, processed_size_callback=None):
|
def set_file_info(self, filenames, processed_size_callback=None):
|
||||||
"""
|
"""
|
||||||
Using the list of filenames being shared, fill in details that the web
|
Using the list of filenames being shared, fill in details that the web
|
||||||
@ -362,12 +338,6 @@ class Web(object):
|
|||||||
return True
|
return True
|
||||||
return filename.endswith(('.html', '.htm', '.xml', '.xhtml'))
|
return filename.endswith(('.html', '.htm', '.xml', '.xhtml'))
|
||||||
|
|
||||||
def base64_image(self, filename):
|
|
||||||
"""
|
|
||||||
Base64-encode an image file to use data URIs in the web app
|
|
||||||
"""
|
|
||||||
return base64.b64encode(open(common.get_resource_path('images/{}'.format(filename)), 'rb').read()).decode()
|
|
||||||
|
|
||||||
def add_request(self, request_type, path, data=None):
|
def add_request(self, request_type, path, data=None):
|
||||||
"""
|
"""
|
||||||
Add a request to the queue, to communicate with the GUI.
|
Add a request to the queue, to communicate with the GUI.
|
||||||
|
3
setup.py
@ -52,7 +52,8 @@ data_files=[
|
|||||||
(os.path.join(sys.prefix, 'share/onionshare'), file_list('share')),
|
(os.path.join(sys.prefix, 'share/onionshare'), file_list('share')),
|
||||||
(os.path.join(sys.prefix, 'share/onionshare/images'), file_list('share/images')),
|
(os.path.join(sys.prefix, 'share/onionshare/images'), file_list('share/images')),
|
||||||
(os.path.join(sys.prefix, 'share/onionshare/locale'), file_list('share/locale')),
|
(os.path.join(sys.prefix, 'share/onionshare/locale'), file_list('share/locale')),
|
||||||
(os.path.join(sys.prefix, 'share/onionshare/html'), file_list('share/html')),
|
(os.path.join(sys.prefix, 'share/onionshare/templates'), file_list('share/templates')),
|
||||||
|
(os.path.join(sys.prefix, 'share/onionshare/static'), file_list('share/static'))
|
||||||
]
|
]
|
||||||
if platform.system() != 'OpenBSD':
|
if platform.system() != 'OpenBSD':
|
||||||
data_files.append(('/usr/share/nautilus-python/extensions/', ['install/scripts/onionshare-nautilus.py']))
|
data_files.append(('/usr/share/nautilus-python/extensions/', ['install/scripts/onionshare-nautilus.py']))
|
||||||
|
Before Width: | Height: | Size: 4.2 KiB After Width: | Height: | Size: 4.2 KiB |
BIN
share/static/logo.png
Normal file
After Width: | Height: | Size: 3.7 KiB |
Before Width: | Height: | Size: 251 B After Width: | Height: | Size: 251 B |
Before Width: | Height: | Size: 338 B After Width: | Height: | Size: 338 B |
@ -2,7 +2,7 @@
|
|||||||
<html>
|
<html>
|
||||||
<head>
|
<head>
|
||||||
<title>Error 404</title>
|
<title>Error 404</title>
|
||||||
<link href="data:image/x-icon;base64,{{favicon_b64}}" rel="icon" type="image/x-icon" />
|
<link href="/static/favicon.ico" rel="icon" type="image/x-icon" />
|
||||||
<style type="text/css">
|
<style type="text/css">
|
||||||
body {
|
body {
|
||||||
background-color: #FFC4D5;
|
background-color: #FFC4D5;
|
@ -2,7 +2,7 @@
|
|||||||
<html>
|
<html>
|
||||||
<head>
|
<head>
|
||||||
<title>OnionShare</title>
|
<title>OnionShare</title>
|
||||||
<link href="data:image/x-icon;base64,{{favicon_b64}}" rel="icon" type="image/x-icon" />
|
<link href="/static/favicon.ico" rel="icon" type="image/x-icon" />
|
||||||
<style>
|
<style>
|
||||||
body {
|
body {
|
||||||
background-color: #222222;
|
background-color: #222222;
|
@ -2,7 +2,7 @@
|
|||||||
<html>
|
<html>
|
||||||
<head>
|
<head>
|
||||||
<title>OnionShare</title>
|
<title>OnionShare</title>
|
||||||
<link href="data:image/x-icon;base64,{{favicon_b64}}" rel="icon" type="image/x-icon" />
|
<link href="/static/favicon.ico" rel="icon" type="image/x-icon" />
|
||||||
<style type="text/css">
|
<style type="text/css">
|
||||||
.clearfix:after {
|
.clearfix:after {
|
||||||
content: ".";
|
content: ".";
|
||||||
@ -97,7 +97,7 @@
|
|||||||
<body>
|
<body>
|
||||||
|
|
||||||
<header class="clearfix">
|
<header class="clearfix">
|
||||||
<img class="logo" src="data:image/png;base64,{{logo_b64}}" title="OnionShare">
|
<img class="logo" src="/static/logo.png" title="OnionShare">
|
||||||
<h1>OnionShare</h1>
|
<h1>OnionShare</h1>
|
||||||
</header>
|
</header>
|
||||||
|
|
@ -2,7 +2,7 @@
|
|||||||
<html>
|
<html>
|
||||||
<head>
|
<head>
|
||||||
<title>OnionShare</title>
|
<title>OnionShare</title>
|
||||||
<link href="data:image/x-icon;base64,{{favicon_b64}}" rel="icon" type="image/x-icon" />
|
<link href="/static/favicon.ico" rel="icon" type="image/x-icon" />
|
||||||
<style type="text/css">
|
<style type="text/css">
|
||||||
.clearfix:after {
|
.clearfix:after {
|
||||||
content: ".";
|
content: ".";
|
||||||
@ -105,7 +105,7 @@
|
|||||||
<li><a class="button" href='/{{ slug }}/download'>Download Files</a></li>
|
<li><a class="button" href='/{{ slug }}/download'>Download Files</a></li>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
<img class="logo" src="data:image/png;base64,{{logo_b64}}" title="OnionShare">
|
<img class="logo" src="/static/logo.png" title="OnionShare">
|
||||||
<h1>OnionShare</h1>
|
<h1>OnionShare</h1>
|
||||||
</header>
|
</header>
|
||||||
|
|
||||||
@ -118,7 +118,7 @@
|
|||||||
{% for info in file_info.dirs %}
|
{% for info in file_info.dirs %}
|
||||||
<tr>
|
<tr>
|
||||||
<td>
|
<td>
|
||||||
<img width="30" height="30" title="" alt="" src="data:image/png;base64,{{ folder_b64 }}" />
|
<img width="30" height="30" title="" alt="" src="/static/web_folder.png" />
|
||||||
{{ info.basename }}
|
{{ info.basename }}
|
||||||
</td>
|
</td>
|
||||||
<td>{{ info.size_human }}</td>
|
<td>{{ info.size_human }}</td>
|
||||||
@ -128,7 +128,7 @@
|
|||||||
{% for info in file_info.files %}
|
{% for info in file_info.files %}
|
||||||
<tr>
|
<tr>
|
||||||
<td>
|
<td>
|
||||||
<img width="30" height="30" title="" alt="" src="data:image/png;base64,{{ file_b64 }}" />
|
<img width="30" height="30" title="" alt="" src="/static/web_file.png" />
|
||||||
{{ info.basename }}
|
{{ info.basename }}
|
||||||
</td>
|
</td>
|
||||||
<td>{{ info.size_human }}</td>
|
<td>{{ info.size_human }}</td>
|