diff --git a/plugins/Bigfile/BigfilePlugin.py b/plugins/Bigfile/BigfilePlugin.py index 60e43693..13270ca9 100644 --- a/plugins/Bigfile/BigfilePlugin.py +++ b/plugins/Bigfile/BigfilePlugin.py @@ -21,6 +21,7 @@ with warnings.catch_warnings(): from util import helper from util import Msgpack +from util.Flag import flag import util from .BigfilePiecefield import BigfilePiecefield, BigfilePiecefieldPacked @@ -167,6 +168,7 @@ class UiWebsocketPlugin(object): "file_relative_path": file_relative_path } + @flag.no_multiuser def actionSiteSetAutodownloadBigfileLimit(self, to, limit): permissions = self.getPermissions(to) if "ADMIN" not in permissions: diff --git a/plugins/Chart/ChartPlugin.py b/plugins/Chart/ChartPlugin.py index ddc1e609..80a4d976 100644 --- a/plugins/Chart/ChartPlugin.py +++ b/plugins/Chart/ChartPlugin.py @@ -5,6 +5,7 @@ import gevent from Config import config from util import helper +from util.Flag import flag from Plugin import PluginManager from .ChartDb import ChartDb from .ChartCollector import ChartCollector @@ -28,10 +29,8 @@ class SiteManagerPlugin(object): @PluginManager.registerTo("UiWebsocket") class UiWebsocketPlugin(object): + @flag.admin def actionChartDbQuery(self, to, query, params=None): - if not "ADMIN" in self.permissions: - return {"error": "No permission"} - if config.debug or config.verbose: s = time.time() rows = [] @@ -49,10 +48,8 @@ class UiWebsocketPlugin(object): self.log.debug("Slow query: %s (%.3fs)" % (query, time.time() - s)) return rows + @flag.admin def actionChartGetPeerLocations(self, to): - if not "ADMIN" in self.permissions: - return {"error": "No permission"} - peers = {} for site in self.server.sites.values(): peers.update(site.peers) diff --git a/plugins/ContentFilter/ContentFilterPlugin.py b/plugins/ContentFilter/ContentFilterPlugin.py index 0a45ceec..f46321d4 100644 --- a/plugins/ContentFilter/ContentFilterPlugin.py +++ b/plugins/ContentFilter/ContentFilterPlugin.py @@ -7,6 +7,7 @@ import os from Plugin import PluginManager from Translate import Translate from Config import config +from util.Flag import flag from .ContentFilterStorage import ContentFilterStorage @@ -36,6 +37,7 @@ class UiWebsocketPlugin(object): filter_storage.changeDbs(auth_address, "remove") self.response(to, "ok") + @flag.no_multiuser def actionMuteAdd(self, to, auth_address, cert_user_id, reason): if "ADMIN" in self.getPermissions(to): self.cbMuteAdd(to, auth_address, cert_user_id, reason) @@ -46,12 +48,14 @@ class UiWebsocketPlugin(object): lambda res: self.cbMuteAdd(to, auth_address, cert_user_id, reason) ) + @flag.no_multiuser def cbMuteRemove(self, to, auth_address): del filter_storage.file_content["mutes"][auth_address] filter_storage.save() filter_storage.changeDbs(auth_address, "load") self.response(to, "ok") + @flag.no_multiuser def actionMuteRemove(self, to, auth_address): if "ADMIN" in self.getPermissions(to): self.cbMuteRemove(to, auth_address) @@ -63,34 +67,31 @@ class UiWebsocketPlugin(object): lambda res: self.cbMuteRemove(to, auth_address) ) + @flag.admin def actionMuteList(self, to): - if "ADMIN" in self.getPermissions(to): - self.response(to, filter_storage.file_content["mutes"]) - else: - return self.response(to, {"error": "Forbidden: Only ADMIN sites can list mutes"}) + self.response(to, filter_storage.file_content["mutes"]) # Siteblock + @flag.no_multiuser + @flag.admin def actionSiteblockAdd(self, to, site_address, reason=None): - if "ADMIN" not in self.getPermissions(to): - return self.response(to, {"error": "Forbidden: Only ADMIN sites can add to blocklist"}) filter_storage.file_content["siteblocks"][site_address] = {"date_added": time.time(), "reason": reason} filter_storage.save() self.response(to, "ok") + @flag.no_multiuser + @flag.admin def actionSiteblockRemove(self, to, site_address): - if "ADMIN" not in self.getPermissions(to): - return self.response(to, {"error": "Forbidden: Only ADMIN sites can remove from blocklist"}) del filter_storage.file_content["siteblocks"][site_address] filter_storage.save() self.response(to, "ok") + @flag.admin def actionSiteblockList(self, to): - if "ADMIN" in self.getPermissions(to): - self.response(to, filter_storage.file_content["siteblocks"]) - else: - return self.response(to, {"error": "Forbidden: Only ADMIN sites can list blocklists"}) + self.response(to, filter_storage.file_content["siteblocks"]) # Include + @flag.no_multiuser def actionFilterIncludeAdd(self, to, inner_path, description=None, address=None): if address: if "ADMIN" not in self.getPermissions(to): @@ -122,6 +123,7 @@ class UiWebsocketPlugin(object): filter_storage.includeAdd(address, inner_path, description) self.response(to, "ok") + @flag.no_multiuser def actionFilterIncludeRemove(self, to, inner_path, address=None): if address: if "ADMIN" not in self.getPermissions(to): diff --git a/plugins/MergerSite/MergerSitePlugin.py b/plugins/MergerSite/MergerSitePlugin.py index 77d83931..ac1b467b 100644 --- a/plugins/MergerSite/MergerSitePlugin.py +++ b/plugins/MergerSite/MergerSitePlugin.py @@ -7,6 +7,7 @@ from Plugin import PluginManager from Translate import Translate from util import RateLimit from util import helper +from util.Flag import flag from Debug import Debug try: import OptionalManager.UiWebsocketPlugin # To make optioanlFileInfo merger sites compatible @@ -86,6 +87,7 @@ class UiWebsocketPlugin(object): site_manager.updateMergerSites() # Delete a merged site + @flag.no_multiuser def actionMergerSiteDelete(self, to, address): site = self.server.sites.get(address) if not site: diff --git a/plugins/Newsfeed/NewsfeedPlugin.py b/plugins/Newsfeed/NewsfeedPlugin.py index f15d7447..3eb14d6c 100644 --- a/plugins/Newsfeed/NewsfeedPlugin.py +++ b/plugins/Newsfeed/NewsfeedPlugin.py @@ -5,6 +5,7 @@ from Plugin import PluginManager from Db.DbQuery import DbQuery from Debug import Debug from util import helper +from util.Flag import flag @PluginManager.registerTo("UiWebsocket") @@ -27,10 +28,8 @@ class UiWebsocketPlugin(object): feeds = self.user.sites.get(self.site.address, {}).get("follow", {}) self.response(to, feeds) + @flag.admin def actionFeedQuery(self, to, limit=10, day_limit=3): - if "ADMIN" not in self.site.settings["permissions"]: - return self.response(to, "FeedQuery not allowed") - from Site import SiteManager rows = [] stats = [] diff --git a/plugins/OptionalManager/UiWebsocketPlugin.py b/plugins/OptionalManager/UiWebsocketPlugin.py index 9c6ad742..103bbe84 100644 --- a/plugins/OptionalManager/UiWebsocketPlugin.py +++ b/plugins/OptionalManager/UiWebsocketPlugin.py @@ -8,6 +8,7 @@ import gevent from Plugin import PluginManager from Config import config from util import helper +from util.Flag import flag from Translate import Translate @@ -214,6 +215,7 @@ class UiWebsocketPlugin(object): return "ok" + @flag.no_multiuser def actionOptionalFilePin(self, to, inner_path, address=None): if type(inner_path) is not list: inner_path = [inner_path] @@ -226,6 +228,7 @@ class UiWebsocketPlugin(object): self.cmd("notification", ["done", _["Pinned %s files"] % num_file, 5000]) self.response(to, back) + @flag.no_multiuser def actionOptionalFileUnpin(self, to, inner_path, address=None): if type(inner_path) is not list: inner_path = [inner_path] @@ -238,6 +241,7 @@ class UiWebsocketPlugin(object): self.cmd("notification", ["done", _["Removed pin from %s files"] % num_file, 5000]) self.response(to, back) + @flag.no_multiuser def actionOptionalFileDelete(self, to, inner_path, address=None): if not address: address = self.site.address @@ -275,10 +279,8 @@ class UiWebsocketPlugin(object): # Limit functions + @flag.admin def actionOptionalLimitStats(self, to): - if "ADMIN" not in self.site.settings["permissions"]: - return self.response(to, "Forbidden") - back = {} back["limit"] = config.optional_limit back["used"] = self.site.content_manager.contents.db.getOptionalUsedBytes() @@ -286,9 +288,9 @@ class UiWebsocketPlugin(object): self.response(to, back) + @flag.no_multiuser + @flag.admin def actionOptionalLimitSet(self, to, limit): - if "ADMIN" not in self.site.settings["permissions"]: - return self.response(to, {"error": "Forbidden"}) config.optional_limit = re.sub(r"\.0+$", "", limit) # Remove unnecessary digits from end config.saveValue("optional_limit", limit) self.response(to, "ok") @@ -306,6 +308,7 @@ class UiWebsocketPlugin(object): self.response(to, site.settings.get("optional_help", {})) + @flag.no_multiuser def actionOptionalHelp(self, to, directory, title, address=None): if not address: address = self.site.address @@ -342,6 +345,7 @@ class UiWebsocketPlugin(object): self.response(to, dict(stats)) + @flag.no_multiuser def actionOptionalHelpRemove(self, to, directory, address=None): if not address: address = self.site.address @@ -361,6 +365,7 @@ class UiWebsocketPlugin(object): site.settings["autodownloadoptional"] = value self.response(to, value) + @flag.no_multiuser def actionOptionalHelpAll(self, to, value, address=None): if not address: address = self.site.address diff --git a/plugins/OptionalManager/__init__.py b/plugins/OptionalManager/__init__.py index 1f0ad2dd..77b8c348 100644 --- a/plugins/OptionalManager/__init__.py +++ b/plugins/OptionalManager/__init__.py @@ -1 +1,2 @@ -from . import OptionalManagerPlugin \ No newline at end of file +from . import OptionalManagerPlugin +from . import UiWebsocketPlugin diff --git a/plugins/Sidebar/ConsolePlugin.py b/plugins/Sidebar/ConsolePlugin.py index 72192aa7..30d00fee 100644 --- a/plugins/Sidebar/ConsolePlugin.py +++ b/plugins/Sidebar/ConsolePlugin.py @@ -5,6 +5,7 @@ from Plugin import PluginManager from Config import config from Debug import Debug from util import SafeRe +from util.Flag import flag class WsLogStreamer(logging.StreamHandler): @@ -37,10 +38,11 @@ class WsLogStreamer(logging.StreamHandler): @PluginManager.registerTo("UiWebsocket") class UiWebsocketPlugin(object): def __init__(self, *args, **kwargs): - self.admin_commands.update(["consoleLogRead", "consoleLogStream", "consoleLogStreamRemove"]) self.log_streamers = {} return super(UiWebsocketPlugin, self).__init__(*args, **kwargs) + @flag.no_multiuser + @flag.admin def actionConsoleLogRead(self, to, filter=None, read_size=32 * 1024, limit=500): log_file_path = "%s/debug.log" % config.log_dir log_file = open(log_file_path, encoding="utf-8") @@ -74,11 +76,15 @@ class UiWebsocketPlugin(object): logging.getLogger('').addHandler(logger) return logger + @flag.no_multiuser + @flag.admin def actionConsoleLogStream(self, to, filter=None): stream_id = to self.log_streamers[stream_id] = self.addLogStreamer(stream_id, filter) self.response(to, {"stream_id": stream_id}) + @flag.no_multiuser + @flag.admin def actionConsoleLogStreamRemove(self, to, stream_id): try: self.log_streamers[stream_id].stop() diff --git a/plugins/Sidebar/SidebarPlugin.py b/plugins/Sidebar/SidebarPlugin.py index f1a5e8e8..c4b3a4bb 100644 --- a/plugins/Sidebar/SidebarPlugin.py +++ b/plugins/Sidebar/SidebarPlugin.py @@ -16,6 +16,7 @@ from Plugin import PluginManager from Debug import Debug from Translate import Translate from util import helper +from util.Flag import flag from .ZipStream import ZipStream plugin_dir = os.path.dirname(__file__) @@ -85,10 +86,6 @@ class UiRequestPlugin(object): @PluginManager.registerTo("UiWebsocket") class UiWebsocketPlugin(object): - def __init__(self, *args, **kwargs): - self.async_commands.add("sidebarGetPeers") - return super(UiWebsocketPlugin, self).__init__(*args, **kwargs) - def sidebarRenderPeerStats(self, body, site): connected = len([peer for peer in list(site.peers.values()) if peer.connection and peer.connection.connected]) connectable = len([peer_id for peer_id in list(site.peers.keys()) if not peer_id.endswith(":0")]) @@ -511,11 +508,8 @@ class UiWebsocketPlugin(object): body.append("") body.append("") + @flag.admin def actionSidebarGetHtmlTag(self, to): - permissions = self.getPermissions(to) - if "ADMIN" not in permissions: - return self.response(to, "You don't have permission to run this command") - site = self.site body = [] @@ -706,11 +700,9 @@ class UiWebsocketPlugin(object): return peer_locations - + @flag.admin + @flag.async_run 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: peer_locations = self.getPeerLocations(self.site.peers) globe_data = [] @@ -739,53 +731,43 @@ class UiWebsocketPlugin(object): self.log.debug("sidebarGetPeers error: %s" % Debug.formatException(err)) self.response(to, {"error": str(err)}) + @flag.admin + @flag.no_multiuser def actionSiteSetOwned(self, to, owned): - permissions = self.getPermissions(to) - if "ADMIN" not in permissions: - return self.response(to, "You don't have permission to run this command") - if self.site.address == config.updatesite: return self.response(to, "You can't change the ownership of the updater site") self.site.settings["own"] = bool(owned) self.site.updateWebsocket(owned=owned) + @flag.admin + @flag.no_multiuser def actionUserSetSitePrivatekey(self, to, privatekey): - permissions = self.getPermissions(to) - if "ADMIN" not in permissions: - return self.response(to, "You don't have permission to run this command") - site_data = self.user.sites[self.site.address] site_data["privatekey"] = privatekey self.site.updateWebsocket(set_privatekey=bool(privatekey)) return "ok" + @flag.admin + @flag.no_multiuser def actionSiteSetAutodownloadoptional(self, to, owned): - permissions = self.getPermissions(to) - 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.bad_files = {} gevent.spawn(self.site.update, check_files=True) self.site.worker_manager.removeSolvedFileTasks() + @flag.no_multiuser + @flag.admin 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") + @flag.no_multiuser + @flag.admin def actionDbRebuild(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: self.site.storage.rebuildDb() except Exception as err: diff --git a/plugins/UiConfig/UiConfigPlugin.py b/plugins/UiConfig/UiConfigPlugin.py index fc71e28b..81cfe992 100644 --- a/plugins/UiConfig/UiConfigPlugin.py +++ b/plugins/UiConfig/UiConfigPlugin.py @@ -4,6 +4,7 @@ import os from Plugin import PluginManager from Config import config from Translate import Translate +from util.Flag import flag plugin_dir = os.path.dirname(__file__) @@ -12,12 +13,6 @@ if "_" not in locals(): _ = Translate(plugin_dir + "/languages/") -@PluginManager.afterLoad -def importPluginnedClasses(): - from Ui import UiWebsocket - UiWebsocket.admin_commands.add("configList") - - @PluginManager.registerTo("UiRequest") class UiRequestPlugin(object): def actionWrapper(self, path, extra_headers=None): @@ -58,6 +53,7 @@ class UiRequestPlugin(object): @PluginManager.registerTo("UiWebsocket") class UiWebsocketPlugin(object): + @flag.admin def actionConfigList(self, to): back = {} config_values = vars(config.arguments) diff --git a/plugins/UiPluginManager/UiPluginManagerPlugin.py b/plugins/UiPluginManager/UiPluginManagerPlugin.py index df6236db..1ab80f53 100644 --- a/plugins/UiPluginManager/UiPluginManagerPlugin.py +++ b/plugins/UiPluginManager/UiPluginManagerPlugin.py @@ -8,6 +8,7 @@ from Plugin import PluginManager from Config import config from Debug import Debug from Translate import Translate +from util.Flag import flag plugin_dir = os.path.dirname(__file__) @@ -16,14 +17,6 @@ if "_" not in locals(): _ = Translate(plugin_dir + "/languages/") -@PluginManager.afterLoad -def importPluginnedClasses(): - from Ui import UiWebsocket - UiWebsocket.admin_commands.update([ - "pluginList", "pluginConfigSet", "pluginAdd", "pluginRemove", "pluginUpdate" - ]) - - # Convert non-str,int,float values to str in a dict def restrictDictValues(input_dict): allowed_types = (int, str, float) @@ -73,6 +66,7 @@ class UiRequestPlugin(object): @PluginManager.registerTo("UiWebsocket") class UiWebsocketPlugin(object): + @flag.admin def actionPluginList(self, to): plugins = [] for plugin in PluginManager.plugin_manager.listPlugins(list_disabled=True): @@ -107,6 +101,8 @@ class UiWebsocketPlugin(object): return {"plugins": plugins} + @flag.admin + @flag.no_multiuser def actionPluginConfigSet(self, to, source, inner_path, key, value): plugin_manager = PluginManager.plugin_manager plugins = plugin_manager.listPlugins(list_disabled=True) @@ -196,6 +192,7 @@ class UiWebsocketPlugin(object): self.response(to, "ok") + @flag.no_multiuser def actionPluginAddRequest(self, to, inner_path): self.pluginAction("add_request", self.site.address, inner_path) plugin_info = self.site.storage.loadJson(inner_path + "/plugin_info.json") @@ -208,11 +205,15 @@ class UiWebsocketPlugin(object): lambda res: self.doPluginAdd(to, inner_path, res) ) + @flag.admin + @flag.no_multiuser def actionPluginRemove(self, to, address, inner_path): self.pluginAction("remove", address, inner_path) PluginManager.plugin_manager.saveConfig() return "ok" + @flag.admin + @flag.no_multiuser def actionPluginUpdate(self, to, address, inner_path): self.pluginAction("update", address, inner_path) PluginManager.plugin_manager.saveConfig() diff --git a/plugins/disabled-Multiuser/MultiuserPlugin.py b/plugins/disabled-Multiuser/MultiuserPlugin.py index fc88922a..8a8ee8f2 100644 --- a/plugins/disabled-Multiuser/MultiuserPlugin.py +++ b/plugins/disabled-Multiuser/MultiuserPlugin.py @@ -6,6 +6,8 @@ from Config import config from Plugin import PluginManager from Crypt import CryptBitcoin from . import UserPlugin +from util.Flag import flag + # We can only import plugin host clases after the plugins are loaded @PluginManager.afterLoad @@ -101,16 +103,8 @@ class UiRequestPlugin(object): @PluginManager.registerTo("UiWebsocket") class UiWebsocketPlugin(object): def __init__(self, *args, **kwargs): - self.multiuser_denied_cmds = ( - "siteDelete", "configSet", "serverShutdown", "serverUpdate", "siteClone", - "siteSetOwned", "siteSetAutodownloadoptional", "dbReload", "dbRebuild", - "mergerSiteDelete", "siteSetLimit", "siteSetAutodownloadBigfileLimit", - "optionalLimitSet", "optionalHelp", "optionalHelpRemove", "optionalHelpAll", "optionalFilePin", "optionalFileUnpin", "optionalFileDelete", - "muteAdd", "muteRemove", "siteblockAdd", "siteblockRemove", "filterIncludeAdd", "filterIncludeRemove", - "pluginConfigSet", "pluginAdd", "pluginRemove", "pluginUpdate", "pluginAddRequest" - ) if config.multiuser_no_new_sites: - self.multiuser_denied_cmds += ("mergerSiteAdd", ) + flag.no_multiuser(self.actionMergerSiteAdd) super(UiWebsocketPlugin, self).__init__(*args, **kwargs) @@ -123,18 +117,16 @@ class UiWebsocketPlugin(object): return server_info # Show current user's master seed + @flag.admin def actionUserShowMasterSeed(self, to): - if "ADMIN" not in self.site.settings["permissions"]: - return self.response(to, "Show master seed not allowed") message = "Your unique private key:" message += "