2015-08-16 11:51:00 +02:00
|
|
|
import re
|
|
|
|
import os
|
|
|
|
import cgi
|
|
|
|
import sys
|
|
|
|
import math
|
|
|
|
import time
|
2016-03-09 15:30:04 +01:00
|
|
|
import json
|
2015-08-16 11:51:00 +02:00
|
|
|
try:
|
|
|
|
import cStringIO as StringIO
|
|
|
|
except:
|
|
|
|
import StringIO
|
|
|
|
|
|
|
|
|
|
|
|
from Config import config
|
|
|
|
from Plugin import PluginManager
|
|
|
|
from Debug import Debug
|
|
|
|
|
|
|
|
plugin_dir = "plugins/Sidebar"
|
|
|
|
media_dir = plugin_dir + "/media"
|
|
|
|
sys.path.append(plugin_dir) # To able to load geoip lib
|
|
|
|
|
|
|
|
loc_cache = {}
|
|
|
|
|
|
|
|
|
|
|
|
@PluginManager.registerTo("UiRequest")
|
|
|
|
class UiRequestPlugin(object):
|
|
|
|
# Inject our resources to end of original file streams
|
|
|
|
def actionUiMedia(self, path):
|
|
|
|
if path == "/uimedia/all.js" or path == "/uimedia/all.css":
|
|
|
|
# First yield the original file and header
|
|
|
|
body_generator = super(UiRequestPlugin, self).actionUiMedia(path)
|
|
|
|
for part in body_generator:
|
|
|
|
yield part
|
|
|
|
|
|
|
|
# Append our media file to the end
|
|
|
|
ext = re.match(".*(js|css)$", path).group(1)
|
|
|
|
plugin_media_file = "%s/all.%s" % (media_dir, ext)
|
|
|
|
if config.debug:
|
|
|
|
# If debugging merge *.css to all.css and *.js to all.js
|
|
|
|
from Debug import DebugMedia
|
|
|
|
DebugMedia.merge(plugin_media_file)
|
|
|
|
for part in self.actionFile(plugin_media_file, send_header=False):
|
|
|
|
yield part
|
|
|
|
elif path.startswith("/uimedia/globe/"): # Serve WebGL globe files
|
|
|
|
file_name = re.match(".*/(.*)", path).group(1)
|
|
|
|
plugin_media_file = "%s-globe/%s" % (media_dir, file_name)
|
|
|
|
if config.debug and path.endswith("all.js"):
|
|
|
|
# If debugging merge *.css to all.css and *.js to all.js
|
|
|
|
from Debug import DebugMedia
|
|
|
|
DebugMedia.merge(plugin_media_file)
|
|
|
|
for part in self.actionFile(plugin_media_file):
|
|
|
|
yield part
|
|
|
|
else:
|
|
|
|
for part in super(UiRequestPlugin, self).actionUiMedia(path):
|
|
|
|
yield part
|
|
|
|
|
|
|
|
|
|
|
|
@PluginManager.registerTo("UiWebsocket")
|
|
|
|
class UiWebsocketPlugin(object):
|
|
|
|
|
|
|
|
def sidebarRenderPeerStats(self, body, site):
|
|
|
|
connected = len([peer for peer in site.peers.values() if peer.connection and peer.connection.connected])
|
|
|
|
connectable = len([peer_id for peer_id in site.peers.keys() if not peer_id.endswith(":0")])
|
Version 0.3.5, Rev830, Full Tor mode support with hidden services, Onion stats in Sidebar, GeoDB download fix using Tor, Gray out disabled sites in Stats page, Tor hidden service status in stat page, Benchmark sha256, Skyts tracker out expodie in, 2 new tracker using ZeroNet protocol, Keep SSL cert option between restarts, SSL Certificate pinning support for connections, Site lock support for connections, Certificate pinned connections using implicit SSL, Flood protection whitelist support, Foreign keys support for DB layer, Not support for SQL query helper, 0 length file get bugfix, Pex onion address support, Faster port testing, Faster uPnP port opening, Need connections more often on owned sites, Delay ZeroHello startup message if port check or Tor manager not ready yet, Use lockfiles to avoid double start, Save original socket on proxy monkey patching to get ability to connect localhost directly, Handle atomic write errors, Broken gevent https workaround helper, Rsa crypt functions, Plugin to Bootstrap using ZeroNet protocol
2016-01-05 00:20:52 +01:00
|
|
|
onion = len([peer_id for peer_id in site.peers.keys() if ".onion" in peer_id])
|
2015-08-16 11:51:00 +02:00
|
|
|
peers_total = len(site.peers)
|
|
|
|
if peers_total:
|
|
|
|
percent_connected = float(connected) / peers_total
|
|
|
|
percent_connectable = float(connectable) / peers_total
|
Rev957, Sidebar displays onion peers in graph, Sidebar display bad file retry number, Sidebar site Update/Pause/Delete, Ratelimit sidebar update, Encoded typo, Fix onion findHashId, More retry for bad files, Log file path errors, Testcase for self findhashIds, Testcase for Tor findHashId, Better Tor version parse, UiWebsocket callback on update/pause/resume/delete, Skip invalid postMessage messages
2016-03-09 00:48:57 +01:00
|
|
|
percent_onion = float(onion) / peers_total
|
2015-08-16 11:51:00 +02:00
|
|
|
else:
|
Rev957, Sidebar displays onion peers in graph, Sidebar display bad file retry number, Sidebar site Update/Pause/Delete, Ratelimit sidebar update, Encoded typo, Fix onion findHashId, More retry for bad files, Log file path errors, Testcase for self findhashIds, Testcase for Tor findHashId, Better Tor version parse, UiWebsocket callback on update/pause/resume/delete, Skip invalid postMessage messages
2016-03-09 00:48:57 +01:00
|
|
|
percent_connectable = percent_connected = percent_onion = 0
|
2015-08-16 11:51:00 +02:00
|
|
|
body.append("""
|
|
|
|
<li>
|
|
|
|
<label>Peers</label>
|
|
|
|
<ul class='graph'>
|
|
|
|
<li style='width: 100%' class='total back-black' title="Total peers"></li>
|
|
|
|
<li style='width: {percent_connectable:.0%}' class='connectable back-blue' title='Connectable peers'></li>
|
Rev957, Sidebar displays onion peers in graph, Sidebar display bad file retry number, Sidebar site Update/Pause/Delete, Ratelimit sidebar update, Encoded typo, Fix onion findHashId, More retry for bad files, Log file path errors, Testcase for self findhashIds, Testcase for Tor findHashId, Better Tor version parse, UiWebsocket callback on update/pause/resume/delete, Skip invalid postMessage messages
2016-03-09 00:48:57 +01:00
|
|
|
<li style='width: {percent_onion:.0%}' class='connected back-purple' title='Onion'></li>
|
2015-08-16 11:51:00 +02:00
|
|
|
<li style='width: {percent_connected:.0%}' class='connected back-green' title='Connected peers'></li>
|
|
|
|
</ul>
|
|
|
|
<ul class='graph-legend'>
|
|
|
|
<li class='color-green'><span>connected:</span><b>{connected}</b></li>
|
|
|
|
<li class='color-blue'><span>Connectable:</span><b>{connectable}</b></li>
|
Version 0.3.5, Rev830, Full Tor mode support with hidden services, Onion stats in Sidebar, GeoDB download fix using Tor, Gray out disabled sites in Stats page, Tor hidden service status in stat page, Benchmark sha256, Skyts tracker out expodie in, 2 new tracker using ZeroNet protocol, Keep SSL cert option between restarts, SSL Certificate pinning support for connections, Site lock support for connections, Certificate pinned connections using implicit SSL, Flood protection whitelist support, Foreign keys support for DB layer, Not support for SQL query helper, 0 length file get bugfix, Pex onion address support, Faster port testing, Faster uPnP port opening, Need connections more often on owned sites, Delay ZeroHello startup message if port check or Tor manager not ready yet, Use lockfiles to avoid double start, Save original socket on proxy monkey patching to get ability to connect localhost directly, Handle atomic write errors, Broken gevent https workaround helper, Rsa crypt functions, Plugin to Bootstrap using ZeroNet protocol
2016-01-05 00:20:52 +01:00
|
|
|
<li class='color-purple'><span>Onion:</span><b>{onion}</b></li>
|
2015-08-16 11:51:00 +02:00
|
|
|
<li class='color-black'><span>Total:</span><b>{peers_total}</b></li>
|
|
|
|
</ul>
|
|
|
|
</li>
|
|
|
|
""".format(**locals()))
|
|
|
|
|
|
|
|
def sidebarRenderTransferStats(self, body, site):
|
|
|
|
recv = float(site.settings.get("bytes_recv", 0)) / 1024 / 1024
|
|
|
|
sent = float(site.settings.get("bytes_sent", 0)) / 1024 / 1024
|
|
|
|
transfer_total = recv + sent
|
|
|
|
if transfer_total:
|
|
|
|
percent_recv = recv / transfer_total
|
|
|
|
percent_sent = sent / transfer_total
|
|
|
|
else:
|
|
|
|
percent_recv = 0.5
|
|
|
|
percent_sent = 0.5
|
|
|
|
body.append("""
|
|
|
|
<li>
|
|
|
|
<label>Data transfer</label>
|
|
|
|
<ul class='graph graph-stacked'>
|
|
|
|
<li style='width: {percent_recv:.0%}' class='received back-yellow' title="Received bytes"></li>
|
|
|
|
<li style='width: {percent_sent:.0%}' class='sent back-green' title="Sent bytes"></li>
|
|
|
|
</ul>
|
|
|
|
<ul class='graph-legend'>
|
|
|
|
<li class='color-yellow'><span>Received:</span><b>{recv:.2f}MB</b></li>
|
|
|
|
<li class='color-green'<span>Sent:</span><b>{sent:.2f}MB</b></li>
|
|
|
|
</ul>
|
|
|
|
</li>
|
|
|
|
""".format(**locals()))
|
|
|
|
|
|
|
|
def sidebarRenderFileStats(self, body, site):
|
|
|
|
body.append("<li><label>Files</label><ul class='graph graph-stacked'>")
|
|
|
|
|
|
|
|
extensions = (
|
|
|
|
("html", "yellow"),
|
|
|
|
("css", "orange"),
|
|
|
|
("js", "purple"),
|
|
|
|
("image", "green"),
|
|
|
|
("json", "blue"),
|
|
|
|
("other", "white"),
|
|
|
|
("total", "black")
|
|
|
|
)
|
|
|
|
# Collect stats
|
|
|
|
size_filetypes = {}
|
|
|
|
size_total = 0
|
|
|
|
for content in site.content_manager.contents.values():
|
|
|
|
if "files" not in content:
|
|
|
|
continue
|
|
|
|
for file_name, file_details in content["files"].items():
|
|
|
|
size_total += file_details["size"]
|
|
|
|
ext = file_name.split(".")[-1]
|
|
|
|
size_filetypes[ext] = size_filetypes.get(ext, 0) + file_details["size"]
|
|
|
|
size_other = size_total
|
|
|
|
|
|
|
|
# Bar
|
|
|
|
for extension, color in extensions:
|
|
|
|
if extension == "total":
|
|
|
|
continue
|
|
|
|
if extension == "other":
|
|
|
|
size = size_other
|
|
|
|
elif extension == "image":
|
|
|
|
size = size_filetypes.get("jpg", 0) + size_filetypes.get("png", 0) + size_filetypes.get("gif", 0)
|
|
|
|
size_other -= size
|
|
|
|
else:
|
|
|
|
size = size_filetypes.get(extension, 0)
|
|
|
|
size_other -= size
|
2016-01-15 19:50:02 +01:00
|
|
|
if size_total == 0:
|
|
|
|
percent = 0
|
|
|
|
else:
|
|
|
|
percent = 100 * (float(size) / size_total)
|
2016-03-06 19:28:22 +01:00
|
|
|
percent = math.floor(percent * 100) / 100 # Floor to 2 digits
|
|
|
|
body.append(
|
|
|
|
u"""<li style='width: %.2f%%' class='%s back-%s' title="%s"></li>""" %
|
|
|
|
(percent, extension, color, extension)
|
|
|
|
)
|
2015-08-16 11:51:00 +02:00
|
|
|
|
|
|
|
# Legend
|
|
|
|
body.append("</ul><ul class='graph-legend'>")
|
|
|
|
for extension, color in extensions:
|
|
|
|
if extension == "other":
|
|
|
|
size = size_other
|
|
|
|
elif extension == "image":
|
|
|
|
size = size_filetypes.get("jpg", 0) + size_filetypes.get("png", 0) + size_filetypes.get("gif", 0)
|
|
|
|
elif extension == "total":
|
|
|
|
size = size_total
|
|
|
|
else:
|
|
|
|
size = size_filetypes.get(extension, 0)
|
|
|
|
|
|
|
|
if extension == "js":
|
|
|
|
title = "javascript"
|
|
|
|
else:
|
|
|
|
title = extension
|
|
|
|
|
|
|
|
if size > 1024 * 1024 * 10: # Format as mB is more than 10mB
|
|
|
|
size_formatted = "%.0fMB" % (size / 1024 / 1024)
|
|
|
|
else:
|
|
|
|
size_formatted = "%.0fkB" % (size / 1024)
|
|
|
|
|
2015-10-27 01:26:02 +01:00
|
|
|
body.append(u"<li class='color-%s'><span>%s:</span><b>%s</b></li>" % (color, title, size_formatted))
|
2015-08-16 11:51:00 +02:00
|
|
|
|
|
|
|
body.append("</ul></li>")
|
|
|
|
|
|
|
|
def getFreeSpace(self):
|
|
|
|
free_space = 0
|
|
|
|
if "statvfs" in dir(os): # Unix
|
|
|
|
statvfs = os.statvfs(config.data_dir)
|
|
|
|
free_space = statvfs.f_frsize * statvfs.f_bavail
|
|
|
|
else: # Windows
|
|
|
|
try:
|
|
|
|
import ctypes
|
|
|
|
free_space_pointer = ctypes.c_ulonglong(0)
|
|
|
|
ctypes.windll.kernel32.GetDiskFreeSpaceExW(
|
|
|
|
ctypes.c_wchar_p(config.data_dir), None, None, ctypes.pointer(free_space_pointer)
|
|
|
|
)
|
|
|
|
free_space = free_space_pointer.value
|
|
|
|
except Exception, err:
|
|
|
|
self.log.debug("GetFreeSpace error: %s" % err)
|
|
|
|
return free_space
|
|
|
|
|
|
|
|
def sidebarRenderSizeLimit(self, body, site):
|
|
|
|
free_space = self.getFreeSpace() / 1024 / 1024
|
|
|
|
size = float(site.settings["size"]) / 1024 / 1024
|
|
|
|
size_limit = site.getSizeLimit()
|
|
|
|
percent_used = size / size_limit
|
|
|
|
body.append("""
|
|
|
|
<li>
|
|
|
|
<label>Size limit <small>(limit used: {percent_used:.0%}, free space: {free_space:,d}MB)</small></label>
|
2016-02-23 01:36:47 +01:00
|
|
|
<input type='text' class='text text-num' value="{size_limit}" id='input-sitelimit'/><span class='text-post'>MB</span>
|
2015-08-16 11:51:00 +02:00
|
|
|
<a href='#Set' class='button' id='button-sitelimit'>Set</a>
|
|
|
|
</li>
|
|
|
|
""".format(**locals()))
|
|
|
|
|
Rev571, Optional file sizes to sidebar, Download all optional files option in sidebar, Optional file number in peer stats, Delete removed or changed optional files, Auto download optional files if autodownloadoptional checked, SiteReload command, Peer use global file server if no site defined, Allow browser cache video files, Allow more keepalive connections, Gevent 1.1 ranged request bugfix, Dont sent optional files details on websocket, Remove files from workermanager tasks if no longer in bad_files, Notify local client about changes on external siteSign
2015-11-09 00:44:03 +01:00
|
|
|
def sidebarRenderOptionalFileStats(self, body, site):
|
|
|
|
size_total = 0.0
|
|
|
|
size_downloaded = 0.0
|
|
|
|
for content in site.content_manager.contents.values():
|
|
|
|
if "files_optional" not in content:
|
|
|
|
continue
|
|
|
|
for file_name, file_details in content["files_optional"].items():
|
|
|
|
size_total += file_details["size"]
|
|
|
|
if site.content_manager.hashfield.hasHash(file_details["sha512"]):
|
|
|
|
size_downloaded += file_details["size"]
|
|
|
|
|
|
|
|
if not size_total:
|
|
|
|
return False
|
|
|
|
|
|
|
|
percent_downloaded = size_downloaded / size_total
|
|
|
|
|
|
|
|
size_formatted_total = size_total / 1024 / 1024
|
|
|
|
size_formatted_downloaded = size_downloaded / 1024 / 1024
|
|
|
|
|
|
|
|
body.append("""
|
|
|
|
<li>
|
|
|
|
<label>Optional files</label>
|
|
|
|
<ul class='graph'>
|
|
|
|
<li style='width: 100%' class='total back-black' title="Total size"></li>
|
|
|
|
<li style='width: {percent_downloaded:.0%}' class='connected back-green' title='Downloaded files'></li>
|
|
|
|
</ul>
|
|
|
|
<ul class='graph-legend'>
|
|
|
|
<li class='color-green'><span>Downloaded:</span><b>{size_formatted_downloaded:.2f}MB</b></li>
|
|
|
|
<li class='color-black'><span>Total:</span><b>{size_formatted_total:.2f}MB</b></li>
|
|
|
|
</ul>
|
|
|
|
</li>
|
|
|
|
""".format(**locals()))
|
|
|
|
|
|
|
|
return True
|
|
|
|
|
|
|
|
def sidebarRenderOptionalFileSettings(self, body, site):
|
|
|
|
if self.site.settings.get("autodownloadoptional"):
|
|
|
|
checked = "checked='checked'"
|
|
|
|
else:
|
|
|
|
checked = ""
|
|
|
|
body.append("""
|
|
|
|
<li>
|
|
|
|
<label>Download and help distribute all files</label>
|
|
|
|
<input type="checkbox" class="checkbox" id="checkbox-autodownloadoptional" {checked}/><div class="checkbox-skin"></div>
|
|
|
|
</li>
|
|
|
|
""".format(**locals()))
|
|
|
|
|
Rev903, FeedQuery command only available for ADMIN sites, Show bad files in sidebar, Log unknown messages, Add and check inner_path and site address on sign/verify, Better peer cleanup limit, Log site load times, Testcase for address and inner_path verification, Re-sign testsite with new fields, Fix unnecessary loading screen display when browsing sub-folder with index.html, Fix safari notification width
2016-02-18 11:22:21 +01:00
|
|
|
def sidebarRenderBadFiles(self, body, site):
|
|
|
|
body.append("""
|
|
|
|
<li>
|
|
|
|
<label>Missing files:</label>
|
|
|
|
<ul class='filelist'>
|
|
|
|
""")
|
|
|
|
|
2016-03-16 00:35:58 +01:00
|
|
|
i = 0
|
Rev957, Sidebar displays onion peers in graph, Sidebar display bad file retry number, Sidebar site Update/Pause/Delete, Ratelimit sidebar update, Encoded typo, Fix onion findHashId, More retry for bad files, Log file path errors, Testcase for self findhashIds, Testcase for Tor findHashId, Better Tor version parse, UiWebsocket callback on update/pause/resume/delete, Skip invalid postMessage messages
2016-03-09 00:48:57 +01:00
|
|
|
for bad_file, tries in site.bad_files.iteritems():
|
2016-03-16 00:35:58 +01:00
|
|
|
i += 1
|
Rev957, Sidebar displays onion peers in graph, Sidebar display bad file retry number, Sidebar site Update/Pause/Delete, Ratelimit sidebar update, Encoded typo, Fix onion findHashId, More retry for bad files, Log file path errors, Testcase for self findhashIds, Testcase for Tor findHashId, Better Tor version parse, UiWebsocket callback on update/pause/resume/delete, Skip invalid postMessage messages
2016-03-09 00:48:57 +01:00
|
|
|
body.append("""<li class='color-red' title="%s (%s tries)">%s</li>""" % (cgi.escape(bad_file, True), tries, cgi.escape(bad_file, True)))
|
2016-03-16 00:35:58 +01:00
|
|
|
if i > 30:
|
|
|
|
break
|
|
|
|
|
|
|
|
if len(site.bad_files) > 30:
|
|
|
|
body.append("""<li class='color-red'>+ %s more</li>""" % (len(site.bad_files)-30))
|
|
|
|
|
Rev903, FeedQuery command only available for ADMIN sites, Show bad files in sidebar, Log unknown messages, Add and check inner_path and site address on sign/verify, Better peer cleanup limit, Log site load times, Testcase for address and inner_path verification, Re-sign testsite with new fields, Fix unnecessary loading screen display when browsing sub-folder with index.html, Fix safari notification width
2016-02-18 11:22:21 +01:00
|
|
|
|
|
|
|
body.append("""
|
|
|
|
</ul>
|
|
|
|
</li>
|
|
|
|
""")
|
|
|
|
|
2015-08-16 11:51:00 +02:00
|
|
|
def sidebarRenderDbOptions(self, body, site):
|
2016-04-18 02:24:14 +02:00
|
|
|
if site.storage.db:
|
|
|
|
inner_path = site.storage.getInnerPath(site.storage.db.db_path)
|
|
|
|
size = float(site.storage.getSize(inner_path)) / 1024
|
|
|
|
feeds = len(site.storage.db.schema.get("feeds", {}))
|
|
|
|
else:
|
|
|
|
inner_path = "No database found"
|
|
|
|
size = 0.0
|
|
|
|
feeds = 0
|
2015-08-16 11:51:00 +02:00
|
|
|
|
2015-10-27 01:26:02 +01:00
|
|
|
body.append(u"""
|
2015-08-16 11:51:00 +02:00
|
|
|
<li>
|
2016-04-18 02:24:14 +02:00
|
|
|
<label>Database <small>({size:.2f}kB, search feeds: {feeds} query)</small></label>
|
2016-02-23 01:36:47 +01:00
|
|
|
<input type='text' class='text disabled' value="{inner_path}" disabled='disabled'/>
|
2016-04-18 02:24:14 +02:00
|
|
|
<a href='#Reload' id="button-dbreload" class='button'>Reload</a>
|
2015-08-16 11:51:00 +02:00
|
|
|
</li>
|
|
|
|
""".format(**locals()))
|
|
|
|
|
|
|
|
def sidebarRenderIdentity(self, body, site):
|
|
|
|
auth_address = self.user.getAuthAddress(self.site.address)
|
2016-03-09 15:30:04 +01:00
|
|
|
rules = self.site.content_manager.getRules("data/users/%s/content.json" % auth_address)
|
|
|
|
if rules and rules.get("max_size"):
|
|
|
|
quota = rules["max_size"] / 1024
|
|
|
|
content = site.content_manager.contents["data/users/%s/content.json" % auth_address]
|
|
|
|
used = len(json.dumps(content)) + sum([file["size"] for file in content["files"].values()])
|
|
|
|
used = used / 1024
|
|
|
|
else:
|
|
|
|
quota = used = 0
|
|
|
|
|
2015-08-16 11:51:00 +02:00
|
|
|
body.append("""
|
|
|
|
<li>
|
2016-03-11 12:39:39 +01:00
|
|
|
<label>Identity address <small>(limit used: {used:.2f}kB / {quota:.2f}kB)</small></label>
|
2015-08-16 11:51:00 +02:00
|
|
|
<span class='input text disabled'>{auth_address}</span>
|
|
|
|
<a href='#Change' class='button' id='button-identity'>Change</a>
|
|
|
|
</li>
|
|
|
|
""".format(**locals()))
|
|
|
|
|
Rev957, Sidebar displays onion peers in graph, Sidebar display bad file retry number, Sidebar site Update/Pause/Delete, Ratelimit sidebar update, Encoded typo, Fix onion findHashId, More retry for bad files, Log file path errors, Testcase for self findhashIds, Testcase for Tor findHashId, Better Tor version parse, UiWebsocket callback on update/pause/resume/delete, Skip invalid postMessage messages
2016-03-09 00:48:57 +01:00
|
|
|
def sidebarRenderControls(self, body, site):
|
|
|
|
auth_address = self.user.getAuthAddress(self.site.address)
|
|
|
|
if self.site.settings["serving"]:
|
|
|
|
class_pause = ""
|
|
|
|
class_resume = "hidden"
|
|
|
|
else:
|
|
|
|
class_pause = "hidden"
|
|
|
|
class_resume = ""
|
|
|
|
|
|
|
|
body.append("""
|
|
|
|
<li>
|
|
|
|
<label>Site control</label>
|
|
|
|
<a href='#Update' class='button noupdate' id='button-update'>Update</a>
|
|
|
|
<a href='#Pause' class='button {class_pause}' id='button-pause'>Pause</a>
|
|
|
|
<a href='#Resume' class='button {class_resume}' id='button-resume'>Resume</a>
|
|
|
|
<a href='#Delete' class='button noupdate' id='button-delete'>Delete</a>
|
|
|
|
</li>
|
|
|
|
""".format(**locals()))
|
|
|
|
|
2016-04-06 13:40:45 +02:00
|
|
|
site_address = self.site.address
|
|
|
|
body.append("""
|
|
|
|
<li>
|
|
|
|
<label>Site address</label><br>
|
|
|
|
<span class='input text disabled'>{site_address}</span>
|
|
|
|
<a href='bitcoin:{site_address}' class='button' id='button-donate'>Donate</a>
|
|
|
|
</li>
|
|
|
|
""".format(**locals()))
|
|
|
|
|
2015-08-16 11:51:00 +02:00
|
|
|
def sidebarRenderOwnedCheckbox(self, body, site):
|
|
|
|
if self.site.settings["own"]:
|
|
|
|
checked = "checked='checked'"
|
|
|
|
else:
|
|
|
|
checked = ""
|
|
|
|
|
|
|
|
body.append("""
|
Rev571, Optional file sizes to sidebar, Download all optional files option in sidebar, Optional file number in peer stats, Delete removed or changed optional files, Auto download optional files if autodownloadoptional checked, SiteReload command, Peer use global file server if no site defined, Allow browser cache video files, Allow more keepalive connections, Gevent 1.1 ranged request bugfix, Dont sent optional files details on websocket, Remove files from workermanager tasks if no longer in bad_files, Notify local client about changes on external siteSign
2015-11-09 00:44:03 +01:00
|
|
|
<h2 class='owned-title'>This is my site</h2>
|
2015-08-16 11:51:00 +02:00
|
|
|
<input type="checkbox" class="checkbox" id="checkbox-owned" {checked}/><div class="checkbox-skin"></div>
|
|
|
|
""".format(**locals()))
|
|
|
|
|
|
|
|
def sidebarRenderOwnSettings(self, body, site):
|
2016-02-18 19:21:22 +01:00
|
|
|
title = cgi.escape(site.content_manager.contents.get("content.json", {}).get("title", ""), True)
|
|
|
|
description = cgi.escape(site.content_manager.contents.get("content.json", {}).get("description", ""), True)
|
2015-08-16 11:51:00 +02:00
|
|
|
privatekey = cgi.escape(self.user.getSiteData(site.address, create=False).get("privatekey", ""))
|
|
|
|
|
2015-10-27 01:26:02 +01:00
|
|
|
body.append(u"""
|
2015-08-16 11:51:00 +02:00
|
|
|
<li>
|
|
|
|
<label for='settings-title'>Site title</label>
|
|
|
|
<input type='text' class='text' value="{title}" id='settings-title'/>
|
|
|
|
</li>
|
|
|
|
|
|
|
|
<li>
|
|
|
|
<label for='settings-description'>Site description</label>
|
|
|
|
<input type='text' class='text' value="{description}" id='settings-description'/>
|
|
|
|
</li>
|
|
|
|
|
|
|
|
<li style='display: none'>
|
|
|
|
<label>Private key</label>
|
|
|
|
<input type='text' class='text long' value="{privatekey}" placeholder='[Ask on signing]'/>
|
|
|
|
</li>
|
|
|
|
|
|
|
|
<li>
|
|
|
|
<a href='#Save' class='button' id='button-settings'>Save site settings</a>
|
|
|
|
</li>
|
|
|
|
""".format(**locals()))
|
|
|
|
|
|
|
|
def sidebarRenderContents(self, body, site):
|
|
|
|
body.append("""
|
|
|
|
<li>
|
|
|
|
<label>Content publishing</label>
|
2016-03-06 19:28:22 +01:00
|
|
|
<input type='text' class='text' value="content.json" id='input-contents' style='width: 201px'/>
|
2015-08-16 11:51:00 +02:00
|
|
|
<a href='#Sign' class='button' id='button-sign'>Sign</a>
|
|
|
|
<a href='#Publish' class='button' id='button-publish'>Publish</a>
|
|
|
|
</li>
|
|
|
|
""")
|
|
|
|
|
|
|
|
def actionSidebarGetHtmlTag(self, to):
|
|
|
|
site = self.site
|
|
|
|
|
|
|
|
body = []
|
|
|
|
|
|
|
|
body.append("<div>")
|
2016-02-18 19:21:22 +01:00
|
|
|
body.append("<h1>%s</h1>" % cgi.escape(site.content_manager.contents.get("content.json", {}).get("title", ""), True))
|
2015-08-16 11:51:00 +02:00
|
|
|
|
|
|
|
body.append("<div class='globe loading'></div>")
|
|
|
|
|
|
|
|
body.append("<ul class='fields'>")
|
|
|
|
|
|
|
|
self.sidebarRenderPeerStats(body, site)
|
|
|
|
self.sidebarRenderTransferStats(body, site)
|
|
|
|
self.sidebarRenderFileStats(body, site)
|
|
|
|
self.sidebarRenderSizeLimit(body, site)
|
Rev571, Optional file sizes to sidebar, Download all optional files option in sidebar, Optional file number in peer stats, Delete removed or changed optional files, Auto download optional files if autodownloadoptional checked, SiteReload command, Peer use global file server if no site defined, Allow browser cache video files, Allow more keepalive connections, Gevent 1.1 ranged request bugfix, Dont sent optional files details on websocket, Remove files from workermanager tasks if no longer in bad_files, Notify local client about changes on external siteSign
2015-11-09 00:44:03 +01:00
|
|
|
has_optional = self.sidebarRenderOptionalFileStats(body, site)
|
|
|
|
if has_optional:
|
|
|
|
self.sidebarRenderOptionalFileSettings(body, site)
|
2015-08-16 11:51:00 +02:00
|
|
|
self.sidebarRenderDbOptions(body, site)
|
|
|
|
self.sidebarRenderIdentity(body, site)
|
Rev957, Sidebar displays onion peers in graph, Sidebar display bad file retry number, Sidebar site Update/Pause/Delete, Ratelimit sidebar update, Encoded typo, Fix onion findHashId, More retry for bad files, Log file path errors, Testcase for self findhashIds, Testcase for Tor findHashId, Better Tor version parse, UiWebsocket callback on update/pause/resume/delete, Skip invalid postMessage messages
2016-03-09 00:48:57 +01:00
|
|
|
self.sidebarRenderControls(body, site)
|
|
|
|
if site.bad_files:
|
|
|
|
self.sidebarRenderBadFiles(body, site)
|
2015-08-16 11:51:00 +02:00
|
|
|
|
|
|
|
self.sidebarRenderOwnedCheckbox(body, site)
|
|
|
|
body.append("<div class='settings-owned'>")
|
|
|
|
self.sidebarRenderOwnSettings(body, site)
|
|
|
|
self.sidebarRenderContents(body, site)
|
|
|
|
body.append("</div>")
|
|
|
|
body.append("</ul>")
|
|
|
|
body.append("</div>")
|
|
|
|
|
|
|
|
self.response(to, "".join(body))
|
|
|
|
|
|
|
|
def downloadGeoLiteDb(self, db_path):
|
|
|
|
import urllib
|
|
|
|
import gzip
|
|
|
|
import shutil
|
Version 0.3.5, Rev830, Full Tor mode support with hidden services, Onion stats in Sidebar, GeoDB download fix using Tor, Gray out disabled sites in Stats page, Tor hidden service status in stat page, Benchmark sha256, Skyts tracker out expodie in, 2 new tracker using ZeroNet protocol, Keep SSL cert option between restarts, SSL Certificate pinning support for connections, Site lock support for connections, Certificate pinned connections using implicit SSL, Flood protection whitelist support, Foreign keys support for DB layer, Not support for SQL query helper, 0 length file get bugfix, Pex onion address support, Faster port testing, Faster uPnP port opening, Need connections more often on owned sites, Delay ZeroHello startup message if port check or Tor manager not ready yet, Use lockfiles to avoid double start, Save original socket on proxy monkey patching to get ability to connect localhost directly, Handle atomic write errors, Broken gevent https workaround helper, Rsa crypt functions, Plugin to Bootstrap using ZeroNet protocol
2016-01-05 00:20:52 +01:00
|
|
|
from util import helper
|
2015-08-16 11:51:00 +02:00
|
|
|
|
|
|
|
self.log.info("Downloading GeoLite2 City database...")
|
2016-04-18 00:37:47 +02:00
|
|
|
self.cmd("notification", ["geolite-info", "Downloading GeoLite2 City database (one time only, ~20MB)...", 0])
|
Version 0.3.5, Rev830, Full Tor mode support with hidden services, Onion stats in Sidebar, GeoDB download fix using Tor, Gray out disabled sites in Stats page, Tor hidden service status in stat page, Benchmark sha256, Skyts tracker out expodie in, 2 new tracker using ZeroNet protocol, Keep SSL cert option between restarts, SSL Certificate pinning support for connections, Site lock support for connections, Certificate pinned connections using implicit SSL, Flood protection whitelist support, Foreign keys support for DB layer, Not support for SQL query helper, 0 length file get bugfix, Pex onion address support, Faster port testing, Faster uPnP port opening, Need connections more often on owned sites, Delay ZeroHello startup message if port check or Tor manager not ready yet, Use lockfiles to avoid double start, Save original socket on proxy monkey patching to get ability to connect localhost directly, Handle atomic write errors, Broken gevent https workaround helper, Rsa crypt functions, Plugin to Bootstrap using ZeroNet protocol
2016-01-05 00:20:52 +01:00
|
|
|
db_urls = [
|
2016-04-06 14:51:08 +02:00
|
|
|
"https://geolite.maxmind.com/download/geoip/database/GeoLite2-City.mmdb.gz",
|
Version 0.3.5, Rev830, Full Tor mode support with hidden services, Onion stats in Sidebar, GeoDB download fix using Tor, Gray out disabled sites in Stats page, Tor hidden service status in stat page, Benchmark sha256, Skyts tracker out expodie in, 2 new tracker using ZeroNet protocol, Keep SSL cert option between restarts, SSL Certificate pinning support for connections, Site lock support for connections, Certificate pinned connections using implicit SSL, Flood protection whitelist support, Foreign keys support for DB layer, Not support for SQL query helper, 0 length file get bugfix, Pex onion address support, Faster port testing, Faster uPnP port opening, Need connections more often on owned sites, Delay ZeroHello startup message if port check or Tor manager not ready yet, Use lockfiles to avoid double start, Save original socket on proxy monkey patching to get ability to connect localhost directly, Handle atomic write errors, Broken gevent https workaround helper, Rsa crypt functions, Plugin to Bootstrap using ZeroNet protocol
2016-01-05 00:20:52 +01:00
|
|
|
"https://raw.githubusercontent.com/texnikru/GeoLite2-Database/master/GeoLite2-City.mmdb.gz"
|
|
|
|
]
|
|
|
|
for db_url in db_urls:
|
|
|
|
try:
|
|
|
|
# Download
|
|
|
|
response = helper.httpRequest(db_url)
|
|
|
|
|
|
|
|
data = StringIO.StringIO()
|
|
|
|
while True:
|
|
|
|
buff = response.read(1024 * 512)
|
|
|
|
if not buff:
|
|
|
|
break
|
|
|
|
data.write(buff)
|
|
|
|
self.log.info("GeoLite2 City database downloaded (%s bytes), unpacking..." % data.tell())
|
|
|
|
data.seek(0)
|
|
|
|
|
|
|
|
# Unpack
|
|
|
|
with gzip.GzipFile(fileobj=data) as gzip_file:
|
|
|
|
shutil.copyfileobj(gzip_file, open(db_path, "wb"))
|
|
|
|
|
|
|
|
self.cmd("notification", ["geolite-done", "GeoLite2 City database downloaded!", 5000])
|
|
|
|
time.sleep(2) # Wait for notify animation
|
|
|
|
return True
|
|
|
|
except Exception, err:
|
|
|
|
self.log.error("Error downloading %s: %s" % (db_url, err))
|
|
|
|
pass
|
|
|
|
self.cmd("notification", [
|
|
|
|
"geolite-error",
|
|
|
|
"GeoLite2 City database download error: %s!<br>Please download and unpack to data dir:<br>%s" % (err, db_urls[0]),
|
|
|
|
0
|
|
|
|
])
|
2015-08-16 11:51:00 +02:00
|
|
|
|
|
|
|
def actionSidebarGetPeers(self, to):
|
|
|
|
permissions = self.getPermissions(to)
|
|
|
|
if "ADMIN" not in permissions:
|
|
|
|
return self.response(to, "You don't have permission to run this command")
|
|
|
|
try:
|
|
|
|
import maxminddb
|
|
|
|
db_path = config.data_dir + '/GeoLite2-City.mmdb'
|
Version 0.3.5, Rev830, Full Tor mode support with hidden services, Onion stats in Sidebar, GeoDB download fix using Tor, Gray out disabled sites in Stats page, Tor hidden service status in stat page, Benchmark sha256, Skyts tracker out expodie in, 2 new tracker using ZeroNet protocol, Keep SSL cert option between restarts, SSL Certificate pinning support for connections, Site lock support for connections, Certificate pinned connections using implicit SSL, Flood protection whitelist support, Foreign keys support for DB layer, Not support for SQL query helper, 0 length file get bugfix, Pex onion address support, Faster port testing, Faster uPnP port opening, Need connections more often on owned sites, Delay ZeroHello startup message if port check or Tor manager not ready yet, Use lockfiles to avoid double start, Save original socket on proxy monkey patching to get ability to connect localhost directly, Handle atomic write errors, Broken gevent https workaround helper, Rsa crypt functions, Plugin to Bootstrap using ZeroNet protocol
2016-01-05 00:20:52 +01:00
|
|
|
if not os.path.isfile(db_path) or os.path.getsize(db_path) == 0:
|
|
|
|
if not self.downloadGeoLiteDb(db_path):
|
|
|
|
return False
|
2015-08-16 11:51:00 +02:00
|
|
|
geodb = maxminddb.open_database(db_path)
|
|
|
|
|
|
|
|
peers = self.site.peers.values()
|
|
|
|
# Find avg ping
|
|
|
|
ping_times = [
|
|
|
|
peer.connection.last_ping_delay
|
|
|
|
for peer in peers
|
|
|
|
if peer.connection and peer.connection.last_ping_delay and peer.connection.last_ping_delay
|
|
|
|
]
|
|
|
|
if ping_times:
|
|
|
|
ping_avg = sum(ping_times) / float(len(ping_times))
|
|
|
|
else:
|
|
|
|
ping_avg = 0
|
|
|
|
# Place bars
|
|
|
|
globe_data = []
|
|
|
|
placed = {} # Already placed bars here
|
|
|
|
for peer in peers:
|
|
|
|
# Height of bar
|
|
|
|
if peer.connection and peer.connection.last_ping_delay:
|
|
|
|
ping = min(0.20, math.log(1 + peer.connection.last_ping_delay / ping_avg, 300))
|
|
|
|
else:
|
|
|
|
ping = -0.03
|
|
|
|
|
|
|
|
# Query and cache location
|
|
|
|
if peer.ip in loc_cache:
|
|
|
|
loc = loc_cache[peer.ip]
|
|
|
|
else:
|
Version 0.3.5, Rev830, Full Tor mode support with hidden services, Onion stats in Sidebar, GeoDB download fix using Tor, Gray out disabled sites in Stats page, Tor hidden service status in stat page, Benchmark sha256, Skyts tracker out expodie in, 2 new tracker using ZeroNet protocol, Keep SSL cert option between restarts, SSL Certificate pinning support for connections, Site lock support for connections, Certificate pinned connections using implicit SSL, Flood protection whitelist support, Foreign keys support for DB layer, Not support for SQL query helper, 0 length file get bugfix, Pex onion address support, Faster port testing, Faster uPnP port opening, Need connections more often on owned sites, Delay ZeroHello startup message if port check or Tor manager not ready yet, Use lockfiles to avoid double start, Save original socket on proxy monkey patching to get ability to connect localhost directly, Handle atomic write errors, Broken gevent https workaround helper, Rsa crypt functions, Plugin to Bootstrap using ZeroNet protocol
2016-01-05 00:20:52 +01:00
|
|
|
try:
|
|
|
|
loc = geodb.get(peer.ip)
|
|
|
|
except:
|
|
|
|
loc = None
|
2015-08-16 11:51:00 +02:00
|
|
|
loc_cache[peer.ip] = loc
|
2015-09-10 23:25:09 +02:00
|
|
|
if not loc or "location" not in loc:
|
2015-08-16 11:51:00 +02:00
|
|
|
continue
|
|
|
|
|
|
|
|
# Create position array
|
|
|
|
lat, lon = (loc["location"]["latitude"], loc["location"]["longitude"])
|
|
|
|
latlon = "%s,%s" % (lat, lon)
|
|
|
|
if latlon in placed: # Dont place more than 1 bar to same place, fake repos using ip address last two part
|
|
|
|
lat += float(128 - int(peer.ip.split(".")[-2])) / 50
|
|
|
|
lon += float(128 - int(peer.ip.split(".")[-1])) / 50
|
|
|
|
latlon = "%s,%s" % (lat, lon)
|
|
|
|
placed[latlon] = True
|
|
|
|
|
|
|
|
globe_data += (lat, lon, ping)
|
|
|
|
# Append myself
|
|
|
|
loc = geodb.get(config.ip_external)
|
|
|
|
if loc:
|
|
|
|
lat, lon = (loc["location"]["latitude"], loc["location"]["longitude"])
|
|
|
|
globe_data += (lat, lon, -0.135)
|
|
|
|
|
|
|
|
self.response(to, globe_data)
|
|
|
|
except Exception, err:
|
|
|
|
self.log.debug("sidebarGetPeers error: %s" % Debug.formatException(err))
|
|
|
|
self.response(to, {"error": err})
|
|
|
|
|
|
|
|
def actionSiteSetOwned(self, to, owned):
|
|
|
|
permissions = self.getPermissions(to)
|
2016-03-03 21:12:16 +01:00
|
|
|
|
|
|
|
if "Multiuser" in PluginManager.plugin_manager.plugin_names:
|
|
|
|
self.cmd("notification", ["info", "This function is disabled on this proxy"])
|
|
|
|
return False
|
|
|
|
|
2015-08-16 11:51:00 +02:00
|
|
|
if "ADMIN" not in permissions:
|
|
|
|
return self.response(to, "You don't have permission to run this command")
|
|
|
|
self.site.settings["own"] = bool(owned)
|
Rev571, Optional file sizes to sidebar, Download all optional files option in sidebar, Optional file number in peer stats, Delete removed or changed optional files, Auto download optional files if autodownloadoptional checked, SiteReload command, Peer use global file server if no site defined, Allow browser cache video files, Allow more keepalive connections, Gevent 1.1 ranged request bugfix, Dont sent optional files details on websocket, Remove files from workermanager tasks if no longer in bad_files, Notify local client about changes on external siteSign
2015-11-09 00:44:03 +01:00
|
|
|
|
|
|
|
def actionSiteSetAutodownloadoptional(self, to, owned):
|
|
|
|
permissions = self.getPermissions(to)
|
2016-03-03 21:12:16 +01:00
|
|
|
|
|
|
|
if "Multiuser" in PluginManager.plugin_manager.plugin_names:
|
|
|
|
self.cmd("notification", ["info", "This function is disabled on this proxy"])
|
|
|
|
return False
|
|
|
|
|
Rev571, Optional file sizes to sidebar, Download all optional files option in sidebar, Optional file number in peer stats, Delete removed or changed optional files, Auto download optional files if autodownloadoptional checked, SiteReload command, Peer use global file server if no site defined, Allow browser cache video files, Allow more keepalive connections, Gevent 1.1 ranged request bugfix, Dont sent optional files details on websocket, Remove files from workermanager tasks if no longer in bad_files, Notify local client about changes on external siteSign
2015-11-09 00:44:03 +01:00
|
|
|
if "ADMIN" not in permissions:
|
|
|
|
return self.response(to, "You don't have permission to run this command")
|
|
|
|
self.site.settings["autodownloadoptional"] = bool(owned)
|
|
|
|
self.site.update()
|
2016-02-18 19:21:22 +01:00
|
|
|
self.site.worker_manager.removeGoodFileTasks()
|
2016-04-18 02:24:14 +02:00
|
|
|
|
|
|
|
def actionDbReload(self, to):
|
|
|
|
permissions = self.getPermissions(to)
|
|
|
|
if "ADMIN" not in permissions:
|
|
|
|
return self.response(to, "You don't have permission to run this command")
|
|
|
|
|
|
|
|
self.site.storage.closeDb()
|
|
|
|
self.site.storage.getDb()
|
|
|
|
|
|
|
|
return self.response(to, "ok")
|