Merge branch 'ux-update' of https://github.com/micahflee/onionshare into ux_update_fix_shutdown_timer

This commit is contained in:
Miguel Jacq 2018-02-11 17:15:52 +11:00
commit ed179922d4
No known key found for this signature in database
GPG key ID: EEA4341C6D97A0B6
15 changed files with 214 additions and 120 deletions

View file

@ -201,6 +201,7 @@ Section "install"
File "${BINPATH}\share\html\index.html" File "${BINPATH}\share\html\index.html"
SetOutPath "$INSTDIR\share\images" SetOutPath "$INSTDIR\share\images"
File "${BINPATH}\share\images\favicon.ico"
File "${BINPATH}\share\images\file_delete.png" File "${BINPATH}\share\images\file_delete.png"
File "${BINPATH}\share\images\logo.png" File "${BINPATH}\share\images\logo.png"
File "${BINPATH}\share\images\logo_transparent.png" File "${BINPATH}\share\images\logo_transparent.png"
@ -209,7 +210,8 @@ Section "install"
File "${BINPATH}\share\images\server_stopped.png" File "${BINPATH}\share\images\server_stopped.png"
File "${BINPATH}\share\images\server_working.png" File "${BINPATH}\share\images\server_working.png"
File "${BINPATH}\share\images\settings.png" File "${BINPATH}\share\images\settings.png"
File "${BINPATH}\share\images\settings_inactive.png" File "${BINPATH}\share\images\web_file.png"
File "${BINPATH}\share\images\web_folder.png"
SetOutPath "$INSTDIR\share\locale" SetOutPath "$INSTDIR\share\locale"
File "${BINPATH}\share\locale\cs.json" File "${BINPATH}\share\locale\cs.json"
@ -380,6 +382,7 @@ FunctionEnd
Delete "$INSTDIR\share\html\404.html" Delete "$INSTDIR\share\html\404.html"
Delete "$INSTDIR\share\html\denied.html" Delete "$INSTDIR\share\html\denied.html"
Delete "$INSTDIR\share\html\index.html" Delete "$INSTDIR\share\html\index.html"
Delete "$INSTDIR\share\images\favicon.ico"
Delete "$INSTDIR\share\images\file_delete.png" Delete "$INSTDIR\share\images\file_delete.png"
Delete "$INSTDIR\share\images\logo.png" Delete "$INSTDIR\share\images\logo.png"
Delete "$INSTDIR\share\images\logo_transparent.png" Delete "$INSTDIR\share\images\logo_transparent.png"
@ -388,7 +391,8 @@ FunctionEnd
Delete "$INSTDIR\share\images\server_stopped.png" Delete "$INSTDIR\share\images\server_stopped.png"
Delete "$INSTDIR\share\images\server_working.png" Delete "$INSTDIR\share\images\server_working.png"
Delete "$INSTDIR\share\images\settings.png" Delete "$INSTDIR\share\images\settings.png"
Delete "$INSTDIR\share\images\settings_inactive.png" Delete "$INSTDIR\share\images\web_file.png"
Delete "$INSTDIR\share\images\web_folder.png"
Delete "$INSTDIR\share\license.txt" Delete "$INSTDIR\share\license.txt"
Delete "$INSTDIR\share\locale\cs.json" Delete "$INSTDIR\share\locale\cs.json"
Delete "$INSTDIR\share\locale\de.json" Delete "$INSTDIR\share\locale\de.json"

View file

@ -26,6 +26,7 @@ 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
@ -125,6 +126,12 @@ def add_request(request_type, path, data=None):
}) })
# Load and base64 encode images to pass into templates
favicon_b64 = base64.b64encode(open(common.get_resource_path('images/favicon.ico'), 'rb').read()).decode()
logo_b64 = base64.b64encode(open(common.get_resource_path('images/logo.png'), 'rb').read()).decode()
folder_b64 = base64.b64encode(open(common.get_resource_path('images/web_folder.png'), 'rb').read()).decode()
file_b64 = base64.b64encode(open(common.get_resource_path('images/web_file.png'), 'rb').read()).decode()
slug = None slug = None
@ -206,7 +213,10 @@ def index(slug_candidate):
global stay_open, download_in_progress global stay_open, download_in_progress
deny_download = not stay_open and download_in_progress deny_download = not stay_open and download_in_progress
if deny_download: if deny_download:
r = make_response(render_template_string(open(common.get_resource_path('html/denied.html')).read())) r = make_response(render_template_string(
open(common.get_resource_path('html/denied.html')).read(),
favicon_b64=favicon_b64
))
for header, value in security_headers: for header, value in security_headers:
r.headers.set(header, value) r.headers.set(header, value)
return r return r
@ -215,6 +225,10 @@ def index(slug_candidate):
r = make_response(render_template_string( r = make_response(render_template_string(
open(common.get_resource_path('html/index.html')).read(), open(common.get_resource_path('html/index.html')).read(),
favicon_b64=favicon_b64,
logo_b64=logo_b64,
folder_b64=folder_b64,
file_b64=file_b64,
slug=slug, slug=slug,
file_info=file_info, file_info=file_info,
filename=os.path.basename(zip_filename), filename=os.path.basename(zip_filename),
@ -243,7 +257,10 @@ def download(slug_candidate):
global stay_open, download_in_progress, done global stay_open, download_in_progress, done
deny_download = not stay_open and download_in_progress deny_download = not stay_open and download_in_progress
if deny_download: if deny_download:
r = make_response(render_template_string(open(common.get_resource_path('html/denied.html')).read())) r = make_response(render_template_string(
open(common.get_resource_path('html/denied.html')).read(),
favicon_b64=favicon_b64
))
for header,value in security_headers: for header,value in security_headers:
r.headers.set(header, value) r.headers.set(header, value)
return r return r
@ -355,7 +372,10 @@ def page_not_found(e):
force_shutdown() force_shutdown()
print(strings._('error_rate_limit')) print(strings._('error_rate_limit'))
r = make_response(render_template_string(open(common.get_resource_path('html/404.html')).read()), 404) r = make_response(render_template_string(
open(common.get_resource_path('html/404.html')).read(),
favicon_b64=favicon_b64
), 404)
for header, value in security_headers: for header, value in security_headers:
r.headers.set(header, value) r.headers.set(header, value)
return r return r

View file

@ -145,7 +145,8 @@ class FileList(QtWidgets.QListWidget):
count = len(event.mimeData().urls()) count = len(event.mimeData().urls())
self.drop_count.setText('+{}'.format(count)) self.drop_count.setText('+{}'.format(count))
self.drop_count.setGeometry(self.width() - 60, self.height() - 40, 50, 30) size_hint = self.drop_count.sizeHint()
self.drop_count.setGeometry(self.width() - size_hint.width() - 10, self.height() - size_hint.height() - 10, size_hint.width(), size_hint.height())
self.drop_count.show() self.drop_count.show()
event.accept() event.accept()
else: else:
@ -207,15 +208,24 @@ class FileList(QtWidgets.QListWidget):
icon = ip.icon(fileinfo) icon = ip.icon(fileinfo)
if os.path.isfile(filename): if os.path.isfile(filename):
size = common.human_readable_filesize(fileinfo.size()) size_bytes = fileinfo.size()
size_readable = common.human_readable_filesize(size_bytes)
else: else:
size = common.human_readable_filesize(common.dir_size(filename)) size_bytes = common.dir_size(filename)
item_name = '{0:s} ({1:s})'.format(basename, size) size_readable = common.human_readable_filesize(size_bytes)
# Create a new item # Create a new item
item = QtWidgets.QListWidgetItem(item_name) item = QtWidgets.QListWidgetItem()
item.setToolTip(size)
item.setIcon(icon) item.setIcon(icon)
item.size_bytes = size_bytes
# Item's name and size labels
item_name = QtWidgets.QLabel(basename)
item_name.setWordWrap(False)
item_name.setSizePolicy(QtWidgets.QSizePolicy.Ignored, QtWidgets.QSizePolicy.Fixed)
item_name.setStyleSheet('QLabel { color: #000000; font-size: 13px; }')
item_size = QtWidgets.QLabel(size_readable)
item_size.setStyleSheet('QLabel { color: #666666; font-size: 11px; }')
# Item's delete button # Item's delete button
def delete_item(): def delete_item():
@ -229,16 +239,22 @@ class FileList(QtWidgets.QListWidget):
item.item_button.setFlat(True) item.item_button.setFlat(True)
item.item_button.setIcon( QtGui.QIcon(common.get_resource_path('images/file_delete.png')) ) item.item_button.setIcon( QtGui.QIcon(common.get_resource_path('images/file_delete.png')) )
item.item_button.clicked.connect(delete_item) item.item_button.clicked.connect(delete_item)
item.item_button.setSizePolicy(QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Fixed)
# Create an item widget to display on the item # Create the item's widget and layouts
item_widget_layout = QtWidgets.QHBoxLayout() item_vlayout = QtWidgets.QVBoxLayout()
item_widget_layout.addStretch() item_vlayout.addWidget(item_name)
item_widget_layout.addWidget(item.item_button) item_vlayout.addWidget(item_size)
item_widget = QtWidgets.QWidget() item_hlayout = QtWidgets.QHBoxLayout()
item_widget.setLayout(item_widget_layout) item_hlayout.addLayout(item_vlayout)
item_hlayout.addWidget(item.item_button)
widget = QtWidgets.QWidget()
widget.setLayout(item_hlayout)
item.setSizeHint(widget.sizeHint())
self.addItem(item) self.addItem(item)
self.setItemWidget(item, item_widget) self.setItemWidget(item, widget)
self.files_updated.emit() self.files_updated.emit()
@ -252,12 +268,17 @@ class FileSelection(QtWidgets.QVBoxLayout):
super(FileSelection, self).__init__() super(FileSelection, self).__init__()
self.server_on = False self.server_on = False
# file list # Info label
self.info_label = QtWidgets.QLabel()
self.info_label.setStyleSheet('QLabel { font-size: 12px; color: #666666; }')
# File list
self.file_list = FileList() self.file_list = FileList()
self.file_list.currentItemChanged.connect(self.update) self.file_list.currentItemChanged.connect(self.update)
self.file_list.files_dropped.connect(self.update) self.file_list.files_dropped.connect(self.update)
self.file_list.files_updated.connect(self.update)
# buttons # Buttons
self.add_button = QtWidgets.QPushButton(strings._('gui_add', True)) self.add_button = QtWidgets.QPushButton(strings._('gui_add', True))
self.add_button.clicked.connect(self.add) self.add_button.clicked.connect(self.add)
self.delete_button = QtWidgets.QPushButton(strings._('gui_delete', True)) self.delete_button = QtWidgets.QPushButton(strings._('gui_delete', True))
@ -267,7 +288,8 @@ class FileSelection(QtWidgets.QVBoxLayout):
button_layout.addWidget(self.add_button) button_layout.addWidget(self.add_button)
button_layout.addWidget(self.delete_button) button_layout.addWidget(self.delete_button)
# add the widgets # Add the widgets
self.addWidget(self.info_label)
self.addWidget(self.file_list) self.addWidget(self.file_list)
self.addLayout(button_layout) self.addLayout(button_layout)
@ -277,6 +299,20 @@ class FileSelection(QtWidgets.QVBoxLayout):
""" """
Update the GUI elements based on the current state. Update the GUI elements based on the current state.
""" """
# Update the info label
file_count = self.file_list.count()
if file_count == 0:
self.info_label.hide()
else:
total_size_bytes = 0
for index in range(self.file_list.count()):
item = self.file_list.item(index)
total_size_bytes += item.size_bytes
total_size_readable = common.human_readable_filesize(total_size_bytes)
self.info_label.setText(strings._('gui_file_info', True).format(file_count, total_size_readable))
self.info_label.show()
# All buttons should be hidden if the server is on # All buttons should be hidden if the server is on
if self.server_on: if self.server_on:
self.add_button.hide() self.add_button.hide()

View file

@ -156,16 +156,10 @@ class OnionShareGui(QtWidgets.QMainWindow):
self.server_share_status_label.setStyleSheet('QLabel { font-style: italic; color: #666666; padding: 2px; }') self.server_share_status_label.setStyleSheet('QLabel { font-style: italic; color: #666666; padding: 2px; }')
self.status_bar.insertWidget(0, self.server_share_status_label) self.status_bar.insertWidget(0, self.server_share_status_label)
# Persistent URL notification
self.persistent_url_label = QtWidgets.QLabel(strings._('persistent_url_in_use', True))
self.persistent_url_label.setStyleSheet('font-weight: bold; color: #333333;')
self.persistent_url_label.hide()
# Primary action layout # Primary action layout
primary_action_layout = QtWidgets.QVBoxLayout() primary_action_layout = QtWidgets.QVBoxLayout()
primary_action_layout.addWidget(self.server_status) primary_action_layout.addWidget(self.server_status)
primary_action_layout.addWidget(self.filesize_warning) primary_action_layout.addWidget(self.filesize_warning)
primary_action_layout.addWidget(self.persistent_url_label)
primary_action_layout.addWidget(self.downloads_container) primary_action_layout.addWidget(self.downloads_container)
self.primary_action = QtWidgets.QWidget() self.primary_action = QtWidgets.QWidget()
self.primary_action.setLayout(primary_action_layout) self.primary_action.setLayout(primary_action_layout)
@ -204,7 +198,6 @@ class OnionShareGui(QtWidgets.QMainWindow):
self.check_for_updates() self.check_for_updates()
def update_primary_action(self): def update_primary_action(self):
common.log('OnionShareGui', 'update_primary_action')
# Resize window # Resize window
self.adjustSize() self.adjustSize()
@ -426,9 +419,6 @@ class OnionShareGui(QtWidgets.QMainWindow):
self.stop_server() self.stop_server()
self.start_server_error(strings._('gui_server_started_after_timeout')) self.start_server_error(strings._('gui_server_started_after_timeout'))
if self.settings.get('save_private_key'):
self.persistent_url_label.show()
def start_server_error(self, error): def start_server_error(self, error):
""" """
If there's an error when trying to start the onion service If there's an error when trying to start the onion service
@ -460,7 +450,6 @@ class OnionShareGui(QtWidgets.QMainWindow):
# Remove ephemeral service, but don't disconnect from Tor # Remove ephemeral service, but don't disconnect from Tor
self.onion.cleanup(stop_tor=False) self.onion.cleanup(stop_tor=False)
self.filesize_warning.hide() self.filesize_warning.hide()
self.persistent_url_label.hide()
self.stop_server_finished.emit() self.stop_server_finished.emit()
self.set_server_active(False) self.set_server_active(False)
@ -599,11 +588,10 @@ class OnionShareGui(QtWidgets.QMainWindow):
""" """
Disable the Settings button while an OnionShare server is active. Disable the Settings button while an OnionShare server is active.
""" """
self.settings_button.setEnabled(not active)
if active: if active:
self.settings_button.setIcon( QtGui.QIcon(common.get_resource_path('images/settings_inactive.png')) ) self.settings_button.hide()
else: else:
self.settings_button.setIcon( QtGui.QIcon(common.get_resource_path('images/settings.png')) ) self.settings_button.show()
# Disable settings menu action when server is active # Disable settings menu action when server is active
self.settingsAction.setEnabled(not active) self.settingsAction.setEnabled(not active)

View file

@ -127,10 +127,15 @@ class ServerStatus(QtWidgets.QWidget):
if self.status == self.STATUS_STARTED: if self.status == self.STATUS_STARTED:
self.url_description.show() self.url_description.show()
if self.settings.get('close_after_first_download'): if self.settings.get('save_private_key'):
self.url_label.setText(strings._('gui_url_label_persistent', True))
self.url_label.setToolTip(strings._('gui_url_persistence_warning', True))
elif self.settings.get('close_after_first_download'):
self.url_label.setText(strings._('gui_url_label_one_time', True)) self.url_label.setText(strings._('gui_url_label_one_time', True))
self.url_label.setToolTip('')
else: else:
self.url_label.setText(strings._('gui_url_label', True)) self.url_label.setText(strings._('gui_url_label', True))
self.url_label.setToolTip('')
self.url_label.show() self.url_label.show()
self.url.setText('http://{0:s}/{1:s}'.format(self.app.onion_host, self.web.slug)) self.url.setText('http://{0:s}/{1:s}'.format(self.app.onion_host, self.web.slug))

View file

@ -86,12 +86,14 @@ class SettingsDialog(QtWidgets.QDialog):
stealth_details.setWordWrap(True) stealth_details.setWordWrap(True)
stealth_details.setTextInteractionFlags(QtCore.Qt.TextBrowserInteraction) stealth_details.setTextInteractionFlags(QtCore.Qt.TextBrowserInteraction)
stealth_details.setOpenExternalLinks(True) stealth_details.setOpenExternalLinks(True)
stealth_details.setMinimumSize(stealth_details.sizeHint())
self.stealth_checkbox = QtWidgets.QCheckBox() self.stealth_checkbox = QtWidgets.QCheckBox()
self.stealth_checkbox.setCheckState(QtCore.Qt.Unchecked) self.stealth_checkbox.setCheckState(QtCore.Qt.Unchecked)
self.stealth_checkbox.setText(strings._("gui_settings_stealth_option", True)) self.stealth_checkbox.setText(strings._("gui_settings_stealth_option", True))
hidservauth_details = QtWidgets.QLabel(strings._('gui_settings_stealth_hidservauth_string', True)) hidservauth_details = QtWidgets.QLabel(strings._('gui_settings_stealth_hidservauth_string', True))
hidservauth_details.setWordWrap(True) hidservauth_details.setWordWrap(True)
hidservauth_details.setMinimumSize(hidservauth_details.sizeHint())
hidservauth_details.hide() hidservauth_details.hide()
self.hidservauth_copy_button = QtWidgets.QPushButton(strings._('gui_copy_hidservauth', True)) self.hidservauth_copy_button = QtWidgets.QPushButton(strings._('gui_copy_hidservauth', True))

View file

@ -2,6 +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" />
<style type="text/css"> <style type="text/css">
body { body {
background-color: #FFC4D5; background-color: #FFC4D5;

View file

@ -2,6 +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" />
<style> <style>
body { body {
background-color: #222222; background-color: #222222;
@ -15,4 +16,4 @@
<body> <body>
<p>OnionShare download in progress</p> <p>OnionShare download in progress</p>
</body> </body>
</html> </html>

View file

@ -2,104 +2,137 @@
<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" />
<style type="text/css"> <style type="text/css">
body { .clearfix:after {
background-color: #222222; content: ".";
color: #ffffff; display: block;
text-align: center; clear: both;
font-family: sans-serif; visibility: hidden;
padding: 5em 1em; line-height: 0;
} height: 0;
.button { }
-moz-box-shadow:inset 0px 1px 0px 0px #cae3fc;
-webkit-box-shadow:inset 0px 1px 0px 0px #cae3fc;
box-shadow:inset 0px 1px 0px 0px #cae3fc;
background:-webkit-gradient( linear, left top, left bottom, color-stop(0.05, #79bbff), color-stop(1, #4197ee) );
background:-moz-linear-gradient( center top, #79bbff 5%, #4197ee 100% );
filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#79bbff', endColorstr='#4197ee');
background-color:#79bbff;
-webkit-border-top-left-radius:12px;
-moz-border-radius-topleft:12px;
border-top-left-radius:12px;
-webkit-border-top-right-radius:12px;
-moz-border-radius-topright:12px;
border-top-right-radius:12px;
-webkit-border-bottom-right-radius:12px;
-moz-border-radius-bottomright:12px;
border-bottom-right-radius:12px;
-webkit-border-bottom-left-radius:12px;
-moz-border-radius-bottomleft:12px;
border-bottom-left-radius:12px;
text-indent:0;
border:1px solid #469df5;
display:inline-block;
color:#ffffff;
font-size:29px;
font-weight:bold;
font-style:normal;
height:50px;
line-height:50px;
text-decoration:none;
text-align:center;
text-shadow:1px 1px 0px #287ace;
padding: 0 20px;
}
.button:hover {
background:-webkit-gradient( linear, left top, left bottom, color-stop(0.05, #4197ee), color-stop(1, #79bbff) );
background:-moz-linear-gradient( center top, #4197ee 5%, #79bbff 100% );
filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#4197ee', endColorstr='#79bbff');
background-color:#4197ee;
}.button:active {
position:relative;
top:1px;
}
.download-size { body {
color: #999999; margin: 0;
} font-family: Helvetica;
.download-description { }
padding: 10px;
} header {
.file-list { border-bottom: 1px solid rgba(0, 0, 0, 0.1);
margin: 50px auto 0 auto; background: #fcfcfc;
padding: 10px; background: -webkit-linear-gradient(top, #fcfcfc 0%, #f2f2f2 100%);
text-align: left; padding: 0.8rem;
background-color: #333333; }
}
.file-list th { header .logo {
padding: 5px; vertical-align: middle;
font-weight: bold; width: 45px;
color: #999999; height: 45px;
} }
.file-list td {
padding: 5px; header h1 {
} display: inline-block;
margin: 0 0 0 0.5rem;
vertical-align: middle;
font-weight: normal;
font-size: 1.5rem;
color: #666666;
}
header .right {
float: right;
font-size: .75rem;
}
header .right ul li {
display: inline;
margin: 0 0 0 .5rem;
font-size: 1rem;
}
header .button {
color: #ffffff;
background-color: #4e064f;
padding: 10px;
border-radius: 5px;
text-decoration: none;
margin-left: 1rem;
cursor: pointer;
}
table.file-list {
width: 100%;
margin: 0 auto;
border-collapse: collapse;
}
table.file-list th {
text-align: left;
text-transform: uppercase;
font-weight: normal;
color: #666666;
padding: 0.5rem;
}
table.file-list tr {
border-bottom: 1px solid #e0e0e0;
}
table.file-list td {
white-space: nowrap;
padding: 0.5rem 10rem 0.5rem 0.8rem;
}
table.file-list td img {
vertical-align: middle;
margin-right: 0.5rem;
}
table.file-list td:last-child {
width: 100%;
}
</style> </style>
<meta name="onionshare-filename" content="{{ filename }}"> <meta name="onionshare-filename" content="{{ filename }}">
<meta name="onionshare-filesize" content="{{ filesize }}"> <meta name="onionshare-filesize" content="{{ filesize }}">
</head> </head>
<body> <body>
<p><a class="button" href='/{{ slug }}/download'>{{ filename }} &#x25BC;</a></p>
<p class="download-size"><strong title="{{ filesize }} bytes">{{ filesize_human }} (compressed)</strong></p> <header class="clearfix">
<p class="download-description">This zip file contains the following contents:</p> <div class="right">
<ul>
<li>Total size: <strong>{{ filesize_human }}</strong> (compressed)</li>
<li><a class="button" href='/{{ slug }}/download'>Download Files</a></li>
</ul>
</div>
<img class="logo" src="data:image/png;base64,{{logo_b64}}" title="OnionShare">
<h1>OnionShare</h1>
</header>
<table class="file-list"> <table class="file-list">
<tr> <tr>
<th>Type</th> <th>Filename</th>
<th>Name</th>
<th>Size</th> <th>Size</th>
<th></th>
</tr> </tr>
{% for info in file_info.dirs %} {% for info in file_info.dirs %}
<tr> <tr>
<td><img width="30" height="30" title="" alt="" src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAB4AAAAeCAYAAAA7MK6iAAAABmJLR0QA/wD/AP+gvaeTAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAAB3RJTUUH3ggbFCQXOpwjbQAAAM5JREFUSMftlksOwyAMRDFCbNjkDL1kz9K75Cq9AZF3kYIM7oqoP/KpcFK1mRUrnsbW2Fbq0N+JiPhZRMS1OZAfzLzocwCAGmC9V2Vhjduarj8CzynGqIwxsDl4SXV267E4uFTN33X8deCxDyV1XXeRYJo1UUDEa9M0pxoRK+b4HiqRcz3nVAJKRK+TSxqaGbrkNKUkBn0oNSK2+T0MA1dau9NzO4QwuvPen1lAxQtEsq/vNpSWhvZ9v/3IRMTWOQezkyuEoKy14tfHoU11A6Mr5AxrpuMVAAAAAElFTkSuQmCC" /></td> <td>
<td>{{ info.basename }}</td> <img width="30" height="30" title="" alt="" src="data:image/png;base64,{{ folder_b64 }}" />
{{ info.basename }}
</td>
<td>{{ info.size_human }}</td> <td>{{ info.size_human }}</td>
<td></td>
</tr> </tr>
{% endfor %} {% endfor %}
{% for info in file_info.files %} {% for info in file_info.files %}
<tr> <tr>
<td><img width="30" height="30" title="" alt="" src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAB4AAAAeCAYAAAA7MK6iAAAABmJLR0QA/wD/AP+gvaeTAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAAB3RJTUUH3ggbFCQqYvRvfAAAAJFJREFUSMftlUkOwCAIAEWJ//+uIUivtYmtG7VN8KYHRhlA5zYtuB6klCTG2BcEAHrBeN4ws3jvX3lxQZmFiogMgVesVrhKXlvgakKf4KqVdAdXL+Ea3O8aILh0GnUMEhjtw9mLbUv1tx33fgItynBVoN+k2hybY3Nsjg08Bs45q4GYuQ4OIQARLYcSkUPEoiUP4j5IFasKOnUAAAAASUVORK5CYII=" /></td> <td>
<td>{{ info.basename }}</td> <img width="30" height="30" title="" alt="" src="data:image/png;base64,{{ file_b64 }}" />
{{ info.basename }}
</td>
<td>{{ info.size_human }}</td> <td>{{ info.size_human }}</td>
<td></td>
</tr> </tr>
{% endfor %} {% endfor %}
</table> </table>

BIN
share/images/favicon.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 513 B

BIN
share/images/web_file.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 251 B

BIN
share/images/web_folder.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 338 B

View file

@ -133,11 +133,13 @@
"gui_server_timeout_expired": "The chosen timeout has already expired.\nPlease update the timeout and then you may start sharing.", "gui_server_timeout_expired": "The chosen timeout has already expired.\nPlease update the timeout and then you may start sharing.",
"share_via_onionshare": "Share via OnionShare", "share_via_onionshare": "Share via OnionShare",
"gui_save_private_key_checkbox": "Use a persistent address\n(unchecking will delete any saved address)", "gui_save_private_key_checkbox": "Use a persistent address\n(unchecking will delete any saved address)",
"persistent_url_in_use": "This share is using a persistent address",
"gui_url_description": "<b>Anyone</b> with this link can <b>download</b> your files using <b>Tor Browser</b>:", "gui_url_description": "<b>Anyone</b> with this link can <b>download</b> your files using <b>Tor Browser</b>:",
"gui_url_label": "Your Download Address", "gui_url_label": "Your Download Address",
"gui_url_label_persistent": "Your <strong>Persistent</strong> Download Address <em>(what's this?)</em>",
"gui_url_label_one_time": "Your One-Time Download Address", "gui_url_label_one_time": "Your One-Time Download Address",
"gui_url_persistence_warning": "Every share will have the same URL.<br><br>If you want to go back to using one-time URLs, turn off persistence in the Settings.",
"gui_status_indicator_stopped": "Ready to Share", "gui_status_indicator_stopped": "Ready to Share",
"gui_status_indicator_working": "Starting...", "gui_status_indicator_working": "Starting...",
"gui_status_indicator_started": "Sharing" "gui_status_indicator_started": "Sharing",
"gui_file_info": "{} Files, {}"
} }

View file

@ -1,13 +1,15 @@
import sys
# Force tests to look for resources in the source code tree
sys.onionshare_dev_mode = True
import os import os
import shutil import shutil
import sys
import tempfile import tempfile
import pytest import pytest
from onionshare import common from onionshare import common
@pytest.fixture @pytest.fixture
def temp_dir_1024(): def temp_dir_1024():
""" Create a temporary directory that has a single file of a """ Create a temporary directory that has a single file of a