mirror of
https://github.com/HelloZeroNet/ZeroNet.git
synced 2023-12-14 04:33:03 +01:00
Version 0.3.6, Rev879, Fix sidebar error on description missing, New trayicon, New favicon, Disable some functions on MultiUser proxies, New homepage, Replace only the last ? in SQL queries, Alwaays grant ADMIN permission to homepage site, Announce before publish if no peers, configSet, serverShutdown, ADMIN WebsocketAPI command, Stop Tor client before updating, Ignore peer ip packing error, Ignore db files from git, Fix safari ajax error when UiPassword enabled
This commit is contained in:
parent
f7eaf7b222
commit
687a848292
15 changed files with 144 additions and 29 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -13,3 +13,4 @@ __pycache__/
|
|||
|
||||
# Data dir
|
||||
data/*
|
||||
.db
|
48
plugins/Newsfeed/NewsfeedPlugin.py
Normal file
48
plugins/Newsfeed/NewsfeedPlugin.py
Normal file
|
@ -0,0 +1,48 @@
|
|||
from Plugin import PluginManager
|
||||
import re
|
||||
|
||||
@PluginManager.registerTo("UiWebsocket")
|
||||
class UiWebsocketPlugin(object):
|
||||
def actionFeedFollow(self, to, feeds):
|
||||
self.user.setFeedFollow(self.site.address, feeds)
|
||||
self.response(to, "ok")
|
||||
|
||||
def actionFeedListFollow(self, to):
|
||||
feeds = self.user.sites[self.site.address].get("follow", {})
|
||||
self.response(to, feeds)
|
||||
|
||||
def actionFeedQuery(self, to):
|
||||
from Site import SiteManager
|
||||
rows = []
|
||||
for address, site_data in self.user.sites.iteritems():
|
||||
feeds = site_data.get("follow")
|
||||
if not feeds:
|
||||
continue
|
||||
for name, query_set in feeds.iteritems():
|
||||
site = SiteManager.site_manager.get(address)
|
||||
try:
|
||||
query, params = query_set
|
||||
if ":params" in query:
|
||||
query = query.replace(":params", ",".join(["?"]*len(params)))
|
||||
res = site.storage.query(query+" ORDER BY date_added DESC LIMIT 10", params)
|
||||
else:
|
||||
res = site.storage.query(query+" ORDER BY date_added DESC LIMIT 10")
|
||||
except Exception, err: # Log error
|
||||
self.log.error("%s feed query %s error: %s" % (address, name, err))
|
||||
continue
|
||||
for row in res:
|
||||
row = dict(row)
|
||||
row["site"] = address
|
||||
row["feed_name"] = name
|
||||
rows.append(row)
|
||||
return self.response(to, rows)
|
||||
|
||||
|
||||
@PluginManager.registerTo("User")
|
||||
class UserPlugin(object):
|
||||
# Set queries that user follows
|
||||
def setFeedFollow(self, address, feeds):
|
||||
site_data = self.getSiteData(address)
|
||||
site_data["follow"] = feeds
|
||||
self.save()
|
||||
return site_data
|
1
plugins/Newsfeed/__init__.py
Normal file
1
plugins/Newsfeed/__init__.py
Normal file
|
@ -0,0 +1 @@
|
|||
import NewsfeedPlugin
|
|
@ -290,7 +290,7 @@ class UiWebsocketPlugin(object):
|
|||
|
||||
def sidebarRenderOwnSettings(self, body, site):
|
||||
title = cgi.escape(site.content_manager.contents["content.json"]["title"], True)
|
||||
description = cgi.escape(site.content_manager.contents["content.json"]["description"], True)
|
||||
description = cgi.escape(site.content_manager.contents["content.json"].get("description", ""), True)
|
||||
privatekey = cgi.escape(self.user.getSiteData(site.address, create=False).get("privatekey", ""))
|
||||
|
||||
body.append(u"""
|
||||
|
@ -484,4 +484,4 @@ class UiWebsocketPlugin(object):
|
|||
return self.response(to, "You don't have permission to run this command")
|
||||
self.site.settings["autodownloadoptional"] = bool(owned)
|
||||
self.site.update()
|
||||
self.site.worker_manager.removeGoodFileTasks()
|
||||
self.site.worker_manager.removeGoodFileTasks()
|
Binary file not shown.
Before Width: | Height: | Size: 1.1 KiB After Width: | Height: | Size: 1.1 KiB |
|
@ -169,3 +169,16 @@ class UiWebsocketPlugin(object):
|
|||
else:
|
||||
self.cmd("notification", ["error", "Error: Invalid master seed"])
|
||||
self.actionUserLoginForm(0)
|
||||
|
||||
# Disable not Multiuser safe functions
|
||||
def actionConfigSet(self, to, *args, **kwargs):
|
||||
self.cmd("notification", ["info", "This function is disabled on this proxy"])
|
||||
|
||||
def actionServerShutdown(self, to, *args, **kwargs):
|
||||
self.cmd("notification", ["info", "This function is disabled on this proxy"])
|
||||
|
||||
def actionServerUpdate(self, to, *args, **kwargs):
|
||||
self.cmd("notification", ["info", "This function is disabled on this proxy"])
|
||||
|
||||
def actionSiteClone(self, to, *args, **kwargs):
|
||||
self.cmd("notification", ["info", "This function is disabled on this proxy"])
|
||||
|
|
|
@ -7,10 +7,11 @@ import ConfigParser
|
|||
class Config(object):
|
||||
|
||||
def __init__(self, argv):
|
||||
self.version = "0.3.5"
|
||||
self.rev = 860
|
||||
self.version = "0.3.6"
|
||||
self.rev = 879
|
||||
self.argv = argv
|
||||
self.action = None
|
||||
self.config_file = "zeronet.conf"
|
||||
self.createParser()
|
||||
self.createArguments()
|
||||
|
||||
|
@ -129,7 +130,7 @@ class Config(object):
|
|||
self.parser.add_argument('--ui_restrict', help='Restrict web access', default=False, metavar='ip', nargs='*')
|
||||
self.parser.add_argument('--open_browser', help='Open homepage in web browser automatically',
|
||||
nargs='?', const="default_browser", metavar='browser_name')
|
||||
self.parser.add_argument('--homepage', help='Web interface Homepage', default='1EU1tbG9oC1A8jz2ouVwGZyQ5asrNsE4Vr',
|
||||
self.parser.add_argument('--homepage', help='Web interface Homepage', default='1HeLLo4uzjaLetFx6NH3PMwFP3qbRbTf3D',
|
||||
metavar='address')
|
||||
self.parser.add_argument('--size_limit', help='Default site size limit in MB', default=10, metavar='size')
|
||||
|
||||
|
@ -254,13 +255,12 @@ class Config(object):
|
|||
# Parse config file
|
||||
def parseConfig(self, argv):
|
||||
# Find config file path from parameters
|
||||
config_file = "zeronet.conf"
|
||||
if "--config_file" in argv:
|
||||
config_file = argv[argv.index("--config_file") + 1]
|
||||
self.config_file = argv[argv.index("--config_file") + 1]
|
||||
# Load config file
|
||||
if os.path.isfile(config_file):
|
||||
if os.path.isfile(self.config_file):
|
||||
config = ConfigParser.ConfigParser(allow_no_value=True)
|
||||
config.read(config_file)
|
||||
config.read(self.config_file)
|
||||
for section in config.sections():
|
||||
for key, val in config.items(section):
|
||||
if section != "global": # If not global prefix key with section
|
||||
|
|
|
@ -32,13 +32,14 @@ class DbCursor:
|
|||
query_wheres.append(key+" = ?")
|
||||
values.append(value)
|
||||
wheres = " AND ".join(query_wheres)
|
||||
query = query.replace("?", wheres)
|
||||
query = re.sub("(.*)[?]", "\\1%s" % wheres, query) # Replace the last ?
|
||||
params = values
|
||||
else:
|
||||
# Convert param dict to INSERT INTO table (key, key2) VALUES (?, ?) format
|
||||
keys = ", ".join(params.keys())
|
||||
values = ", ".join(['?' for key in params.keys()])
|
||||
query = query.replace("?", "(%s) VALUES (%s)" % (keys, values))
|
||||
keysvalues = "(%s) VALUES (%s)" % (keys, values)
|
||||
query = re.sub("(.*)[?]", "\\1%s" % keysvalues, query) # Replace the last ?
|
||||
params = tuple(params.values())
|
||||
|
||||
s = time.time()
|
||||
|
|
|
@ -80,11 +80,12 @@ class Site(object):
|
|||
if self.address in sites_settings:
|
||||
self.settings = sites_settings[self.address]
|
||||
else:
|
||||
if self.address == config.homepage: # Add admin permissions to homepage
|
||||
permissions = ["ADMIN"]
|
||||
else:
|
||||
permissions = []
|
||||
self.settings = {"own": False, "serving": True, "permissions": permissions} # Default
|
||||
self.settings = {"own": False, "serving": True, "permissions": []} # Default
|
||||
|
||||
# Add admin permissions to homepage
|
||||
if self.address == config.homepage and "ADMIN" not in self.settings["permissions"]:
|
||||
self.settings["permissions"].append("ADMIN")
|
||||
|
||||
return
|
||||
|
||||
# Save site settings to data/sites.json
|
||||
|
@ -171,7 +172,7 @@ class Site(object):
|
|||
|
||||
# Retry download bad files
|
||||
def retryBadFiles(self, force=False):
|
||||
for bad_file, tries in self.bad_files.iteritems():
|
||||
for bad_file, tries in self.bad_files.items():
|
||||
if force or random.randint(0, min(20, tries)) == 0: # Larger number tries = less likely to check every 15min
|
||||
self.needFile(bad_file, update=True, blocking=False)
|
||||
|
||||
|
@ -353,6 +354,9 @@ class Site(object):
|
|||
published = [] # Successfully published (Peer)
|
||||
publishers = [] # Publisher threads
|
||||
|
||||
if not self.peers:
|
||||
self.announce()
|
||||
|
||||
connected_peers = self.getConnectedPeers()
|
||||
if len(connected_peers) > limit * 2: # Publish to already connected peers if possible
|
||||
peers = connected_peers
|
||||
|
|
BIN
src/Test/testdata/bootstrapper.db
vendored
BIN
src/Test/testdata/bootstrapper.db
vendored
Binary file not shown.
|
@ -188,8 +188,10 @@ class UiRequest(object):
|
|||
inner_path = match.group("inner_path").lstrip("/")
|
||||
if "." in inner_path and not inner_path.endswith(".html"):
|
||||
return self.actionSiteMedia("/media" + path) # Only serve html files with frame
|
||||
if self.env.get("HTTP_X_REQUESTED_WITH") or self.env.get("HTTP_ORIGIN"):
|
||||
if self.env.get("HTTP_X_REQUESTED_WITH"):
|
||||
return self.error403("Ajax request not allowed to load wrapper") # No ajax allowed on wrapper
|
||||
# if self.env.get("HTTP_ORIGIN") and self.env.get("HTTP_ORIGIN").strip("/") != self.env.get("HTTP_HOST", "").strip("/"):
|
||||
# return self.error403("Origin does not match")
|
||||
|
||||
site = SiteManager.site_manager.get(address)
|
||||
|
||||
|
@ -478,6 +480,7 @@ class UiRequest(object):
|
|||
# You are not allowed to access this
|
||||
def error403(self, message="", details=True):
|
||||
self.sendHeader(403)
|
||||
self.log.debug("Error 403: %s" % message)
|
||||
return self.formatError("Forbidden", message, details=details)
|
||||
|
||||
# Send file not found error
|
||||
|
|
|
@ -2,6 +2,7 @@ import json
|
|||
import time
|
||||
import sys
|
||||
import hashlib
|
||||
import os
|
||||
|
||||
import gevent
|
||||
|
||||
|
@ -21,6 +22,7 @@ class UiWebsocket(object):
|
|||
self.user = user
|
||||
self.log = site.log
|
||||
self.request = request
|
||||
self.permissions = []
|
||||
self.server = server
|
||||
self.next_message_id = 1
|
||||
self.waiting_cb = {} # Waiting for callback. Key: message_id, Value: function pointer
|
||||
|
@ -53,7 +55,7 @@ class UiWebsocket(object):
|
|||
""",
|
||||
10000
|
||||
])
|
||||
elif config.tor == "always" and not file_server.tor_manager.start_onions == False:
|
||||
elif config.tor == "always" and file_server.tor_manager.start_onions is not False:
|
||||
self.site.notifications.append([
|
||||
"error",
|
||||
"""
|
||||
|
@ -81,7 +83,6 @@ class UiWebsocket(object):
|
|||
0
|
||||
])
|
||||
|
||||
|
||||
for notification in self.site.notifications: # Send pending notification messages
|
||||
self.cmd("notification", notification)
|
||||
self.site.notifications = []
|
||||
|
@ -149,16 +150,16 @@ class UiWebsocket(object):
|
|||
|
||||
cmd = req.get("cmd")
|
||||
params = req.get("params")
|
||||
permissions = self.getPermissions(req["id"])
|
||||
self.permissions = self.getPermissions(req["id"])
|
||||
|
||||
admin_commands = (
|
||||
"sitePause", "siteResume", "siteDelete", "siteList", "siteSetLimit", "siteClone",
|
||||
"channelJoinAllsite", "serverUpdate", "serverPortcheck", "certSet"
|
||||
"channelJoinAllsite", "serverUpdate", "serverPortcheck", "certSet", "configSet"
|
||||
)
|
||||
|
||||
if cmd == "response": # It's a response to a command
|
||||
return self.actionResponse(req["to"], req["result"])
|
||||
elif cmd in admin_commands and "ADMIN" not in permissions: # Admin commands
|
||||
elif cmd in admin_commands and "ADMIN" not in self.permissions: # Admin commands
|
||||
return self.response(req["id"], {"error:", "You don't have permission to run %s" % cmd})
|
||||
else: # Normal command
|
||||
func_name = "action" + cmd[0].upper() + cmd[1:]
|
||||
|
@ -332,7 +333,7 @@ class UiWebsocket(object):
|
|||
site.updateWebsocket() # Send updated site data to local websocket clients
|
||||
else:
|
||||
if len(site.peers) == 0:
|
||||
if sys.modules["main"].file_server.port_opened:
|
||||
if sys.modules["main"].file_server.port_opened or sys.modules["main"].file_server.tor_manager.start_onions:
|
||||
if notification:
|
||||
self.cmd("notification", ["info", "No peers found, but your content is ready to access.", 5000])
|
||||
self.response(to, "ok")
|
||||
|
@ -406,6 +407,7 @@ class UiWebsocket(object):
|
|||
def actionDbQuery(self, to, query, params=None, wait_for=None):
|
||||
rows = []
|
||||
try:
|
||||
assert query.upper().startswith("SELECT"), "Only SELECT query supported"
|
||||
res = self.site.storage.query(query, params)
|
||||
except Exception, err: # Response the error to client
|
||||
return self.response(to, {"error": str(err)})
|
||||
|
@ -594,6 +596,8 @@ class UiWebsocket(object):
|
|||
def actionServerUpdate(self, to):
|
||||
self.cmd("updating")
|
||||
sys.modules["main"].update_after_shutdown = True
|
||||
if sys.modules["main"].file_server.tor_manager.tor_process:
|
||||
sys.modules["main"].file_server.tor_manager.stopTor()
|
||||
sys.modules["main"].file_server.stop()
|
||||
sys.modules["main"].ui_server.stop()
|
||||
|
||||
|
@ -601,3 +605,40 @@ class UiWebsocket(object):
|
|||
sys.modules["main"].file_server.port_opened = None
|
||||
res = sys.modules["main"].file_server.openport()
|
||||
self.response(to, res)
|
||||
|
||||
def actionServerShutdown(self, to):
|
||||
sys.modules["main"].file_server.stop()
|
||||
sys.modules["main"].ui_server.stop()
|
||||
|
||||
def actionConfigSet(self, to, key, value):
|
||||
if not os.path.isfile(config.config_file):
|
||||
content = ""
|
||||
else:
|
||||
content = open(config.config_file).read()
|
||||
lines = content.splitlines()
|
||||
|
||||
global_line_i = None
|
||||
key_line_i = None
|
||||
i = 0
|
||||
for line in lines:
|
||||
if line.strip() == "[global]":
|
||||
global_line_i = i
|
||||
if line.startswith(key+" = "):
|
||||
key_line_i = i
|
||||
i += 1
|
||||
|
||||
if value == None: # Delete line
|
||||
if key_line_i:
|
||||
del lines[key_line_i]
|
||||
else: # Add / update
|
||||
new_line = "%s = %s" % (key, value)
|
||||
if key_line_i: # Already in the config, change the line
|
||||
lines[key_line_i] = new_line
|
||||
elif global_line_i is None: # No global section yet, append to end of file
|
||||
lines.append("[global]")
|
||||
lines.append(new_line)
|
||||
else: # Has global section, append the line after it
|
||||
lines.insert(global_line_i+1, new_line)
|
||||
|
||||
open(config.config_file, "w").write("\n".join(lines))
|
||||
self.response(to, "ok")
|
||||
|
|
Binary file not shown.
Before Width: | Height: | Size: 1.1 KiB After Width: | Height: | Size: 1.1 KiB |
|
@ -241,7 +241,7 @@ class Actions(object):
|
|||
while 1:
|
||||
s = time.time()
|
||||
time.sleep(1)
|
||||
print time.time()-s
|
||||
print "Switch time:", time.time()-s
|
||||
gevent.spawn(checker)
|
||||
|
||||
logging.info("Opening a simple connection server")
|
||||
|
|
|
@ -51,10 +51,13 @@ def shellquote(*args):
|
|||
def packPeers(peers):
|
||||
packed_peers = {"ip4": [], "onion": []}
|
||||
for peer in peers:
|
||||
if peer.ip.endswith(".onion"):
|
||||
packed_peers["onion"].append(peer.packMyAddress())
|
||||
else:
|
||||
packed_peers["ip4"].append(peer.packMyAddress())
|
||||
try:
|
||||
if peer.ip.endswith(".onion"):
|
||||
packed_peers["onion"].append(peer.packMyAddress())
|
||||
else:
|
||||
packed_peers["ip4"].append(peer.packMyAddress())
|
||||
except Exception, err:
|
||||
logging.error("Error packing peer address: %s" % peer)
|
||||
return packed_peers
|
||||
|
||||
|
||||
|
|
Loading…
Reference in a new issue