From 687a84829205528e0d1b7ea3aca4f33b5eeb6688 Mon Sep 17 00:00:00 2001 From: HelloZeroNet Date: Tue, 2 Feb 2016 11:40:45 +0100 Subject: [PATCH] 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 --- .gitignore | 1 + plugins/Newsfeed/NewsfeedPlugin.py | 48 ++++++++++++++++ plugins/Newsfeed/__init__.py | 1 + plugins/Sidebar/SidebarPlugin.py | 4 +- plugins/Trayicon/trayicon.ico | Bin 1150 -> 1150 bytes plugins/disabled-Multiuser/MultiuserPlugin.py | 13 +++++ src/Config.py | 14 ++--- src/Db/DbCursor.py | 5 +- src/Site/Site.py | 16 ++++-- src/Test/testdata/bootstrapper.db | Bin 13312 -> 0 bytes src/Ui/UiRequest.py | 5 +- src/Ui/UiWebsocket.py | 53 ++++++++++++++++-- src/Ui/media/img/favicon.ico | Bin 1150 -> 1150 bytes src/main.py | 2 +- src/util/helper.py | 11 ++-- 15 files changed, 144 insertions(+), 29 deletions(-) create mode 100644 plugins/Newsfeed/NewsfeedPlugin.py create mode 100644 plugins/Newsfeed/__init__.py delete mode 100644 src/Test/testdata/bootstrapper.db diff --git a/.gitignore b/.gitignore index 76380f5b..eb61fdcb 100644 --- a/.gitignore +++ b/.gitignore @@ -13,3 +13,4 @@ __pycache__/ # Data dir data/* +.db \ No newline at end of file diff --git a/plugins/Newsfeed/NewsfeedPlugin.py b/plugins/Newsfeed/NewsfeedPlugin.py new file mode 100644 index 00000000..118099a0 --- /dev/null +++ b/plugins/Newsfeed/NewsfeedPlugin.py @@ -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 diff --git a/plugins/Newsfeed/__init__.py b/plugins/Newsfeed/__init__.py new file mode 100644 index 00000000..20cc04a1 --- /dev/null +++ b/plugins/Newsfeed/__init__.py @@ -0,0 +1 @@ +import NewsfeedPlugin \ No newline at end of file diff --git a/plugins/Sidebar/SidebarPlugin.py b/plugins/Sidebar/SidebarPlugin.py index 6f1b525e..b22ddc17 100644 --- a/plugins/Sidebar/SidebarPlugin.py +++ b/plugins/Sidebar/SidebarPlugin.py @@ -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() \ No newline at end of file diff --git a/plugins/Trayicon/trayicon.ico b/plugins/Trayicon/trayicon.ico index fad67073e655e317d7283fc04dbd3b383a98ad2a..8e1a528501aeda828ca283d01c3203c4a5c0b55f 100644 GIT binary patch literal 1150 zcma)*y=zlp6vj`q(4h*2Lf1-4Z(S6ngR8Fo0R=%2p@TRH;vfjRiDS&5qS-1g2}G0- z$dtht2t*779UM&B&D-~`<9zPOWyG0zUQ3hIp@4zA|ZaOtHS>|xw9m) zE+XdvE&o$EFaQJOJ9v>K+m{X}# zphm2qUh{#ghBq3GelVWJVzKMVWb#J0+kGF*t6bHX9P|2qzn@nv{%vp;SdB*GjmeKa zqt`t6F2d<)kMO+7WYVVYhfF53M=V?{79aY0PxYp@`QqDQz29xyb_RpNS5u38zuA{p zrBdk;d(p%{nb%_({ z=l0G&gApOG*=!Do?VO~q)oL%`n7!L%eucYKG`(QY>>u_~|H{#`avbL)<7Og}*ro5+ z^iV%e@2|nqx@i9xo@zkF*m^eAYV|qwX6}!#KaD@Eca$~nYa2$V^H!_1AGp7#g6j{? z$*}^q^v!UOa*Mv7U=F{ZHS*}&J@Nfcry|~C5qCr6=dwuUsmQ@+<~G9tVA#f7O}C= zM$w=s&h?y`osiv`En=3Fo!mR;&bg0?NQS4~7JRSE&a%j=h-?5b!Q$pQ;BH_~jcpVV6Qz&a719MOEvV4gk)^X9=!Z=T7BJ@V?eWCb`IPNn|hcsQ*WV-@(tl limit * 2: # Publish to already connected peers if possible peers = connected_peers diff --git a/src/Test/testdata/bootstrapper.db b/src/Test/testdata/bootstrapper.db deleted file mode 100644 index 0513f1e54d230724a53f66bd8618b947eefe680c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 13312 zcmeHN&2G~`5MKYpX;XUO5aqySFHsV;mr^8XLfeyo7t?T`C5mDH*)dYU~t+S;a#L6 zNkY#tMhI=vM=Tq(AqgF;fON3lwi`8* zYONE~#%;59*e2L)*w}0v#`a>BR8>?Wl@{427BMTN#W#hEd~MGu;f9H;#2|Ff6}?r_ zt7Kj&Gm`BuDhre{5nK!fOR;U0o~E?iL0&?h@3`l~vlHsTZf`sac)J?|VMlCfO-0LX zZAl%DcsOzBo{e4qjXTp+W4O-@7X99-yG>`7E*?thTsA9xPW|;FTTzb9W|9jT4x%}?<9PXu{vlOuaxDDb_&pNcIOa(c`Yj^j>T zTcv?(*Xo4E!@k}&Y+S6gEgCd-m-V)6z1}R%uQXBO`@xuc#ld$`5)Y4ptmXEyH--lf z3wj*aRes1-b~K>?0)Rl$5Xdlt;ru7f?O-n;z!8A^9|8doNG<|!{*&u_upAJ8?|+B^ zKp?pY!2O?G--G3V0Nno&1Asts5n%VfiY^hllwZn2`G@jFxk3e0n90o-)^5rv@-+2h z_M5q%gz){WA`%6n^f9EJr@8Cp($32NXCVNWWN9u5-2ch_?+42P0e1gu(oZCx%iol* z%9UKA4Ja#sKs}@79_1yEvjRgRp~wc@3^{r=vr3L|D8Sf@qR^CrSYH>^aS_iEB_G7p zg#z>H!hz*Ej33@>oN;*ZiZc$`zS)zGF%DVJ0>)uvq(BRdvkm`^8_HLia01Ilqs(i! u5=sS*;1bln^sS%aJ8V~Lcm7_7`+o(FI+y?mEQtV||0RKgX@I~AAn*ql2&ruV diff --git a/src/Ui/UiRequest.py b/src/Ui/UiRequest.py index f755e978..bb85fcf0 100644 --- a/src/Ui/UiRequest.py +++ b/src/Ui/UiRequest.py @@ -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 diff --git a/src/Ui/UiWebsocket.py b/src/Ui/UiWebsocket.py index 7124b575..0de2ee27 100644 --- a/src/Ui/UiWebsocket.py +++ b/src/Ui/UiWebsocket.py @@ -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") diff --git a/src/Ui/media/img/favicon.ico b/src/Ui/media/img/favicon.ico index fad67073e655e317d7283fc04dbd3b383a98ad2a..3f75912aeb9866bdc297c5050fa378bdfaf1e18c 100644 GIT binary patch literal 1150 zcma)*%TE(g6vnU7gy=>RBP?8C;zn5#cdlI;{{h0Iv=u0nKA?abO-yjfBXnp>z^1lJ zu`QPJh!6$EMA_&{*^-zD?ezVcPKzAB3*3a%5NY%E%$)Q6PVYT;hOrCy*48ro-ejGZ z7^`E9-G-1t<~WbQ7;5MJ><@mr2W>-Zam%~L^K$Su#B3WcqP7i+4ZJ7ZQ_8qV`A*-s z+UBS~tB=|uUC!&hPgBNlnftlYJt4|=`6;jWkkalVwN=VN!_bxLJ{iO7ol?6K9tSC! z87gXKzZGGz+YZT#S%%RgA~+G@OXj=Xlr_9mL=IdNdWKc4 zL}kq+ct~sCRW~VGke<5xScjHW(akg^QwnBTu zYZM(^C7jjvzkHwu%;SV*A;-@UEXn;`i+B$r&@x4B%h|o*^`ZU2)tYKv+=H!`t>H1b zKZ0jz3EUFrpp{YRy72uk;y)X~t%KpZbC&<`31g)O#&)kV_VF2GU$z+A!qdIUb&Ijj R7m?%ILLTCtG`yVQ>|c^jwR->n literal 1150 zcmbVMyGjE=6upbW5^Pf0YAJ-^2h30S3wG9ifqsC9g@k|~V7E=IL`V>9tVA#f7O}C= zM$w=s&h?y`osiv`En=3Fo!mR;&bg0?NQS4~7JRSE&a%j=h-?5b!Q$pQ;BH_~jcpVV6Qz&a719MOEvV4gk)^X9=!Z=T7BJ@V?eWCb`IPNn|hcsQ*WV-@(tl