diff --git a/plugins/Mute/MutePlugin.py b/plugins/Mute/MutePlugin.py index d16a97cd..fe5968f8 100644 --- a/plugins/Mute/MutePlugin.py +++ b/plugins/Mute/MutePlugin.py @@ -11,12 +11,16 @@ from util import helper if os.path.isfile("%s/mutes.json" % config.data_dir): try: - mutes = json.load(open("%s/mutes.json" % config.data_dir))["mutes"] + data = json.load(open("%s/mutes.json" % config.data_dir)) + mutes = data.get("mutes", {}) + site_blacklist = data.get("site_blacklist", {}) except Exception, err: mutes = {} + site_blacklist = {} else: - open("%s/mutes.json" % config.data_dir, "w").write('{"mutes": {}}') + open("%s/mutes.json" % config.data_dir, "w").write('{"mutes": {}, "site_blacklist": {}}') mutes = {} + site_blacklist = {} if "_" not in locals(): _ = Translate("plugins/Mute/languages/") @@ -81,8 +85,30 @@ class UiWebsocketPlugin(object): else: return self.response(to, {"error": "Only ADMIN sites can list mutes"}) + # Blacklist + def actionBlacklistAdd(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 blacklist"}) + site_blacklist[site_address] = {"date_added": time.time(), "reason": reason} + self.saveMutes() + self.response(to, "ok") + + def actionBlacklistRemove(self, to, site_address): + if "ADMIN" not in self.getPermissions(to): + return self.response(to, {"error": "Forbidden, only admin sites can remove from blacklist"}) + del site_blacklist[site_address] + self.saveMutes() + self.response(to, "ok") + + def actionBlacklistList(self, to): + if "ADMIN" in self.getPermissions(to): + self.response(to, site_blacklist) + else: + return self.response(to, {"error": "Only ADMIN sites can list blacklists"}) + + # Write mutes and blacklist to json file def saveMutes(self): - helper.atomicWrite("%s/mutes.json" % config.data_dir, json.dumps({"mutes": mutes}, indent=2, sort_keys=True)) + helper.atomicWrite("%s/mutes.json" % config.data_dir, json.dumps({"mutes": mutes, "site_blacklist": site_blacklist}, indent=2, sort_keys=True)) @PluginManager.registerTo("SiteStorage") @@ -98,3 +124,37 @@ class SiteStoragePlugin(object): return False return super(SiteStoragePlugin, self).updateDbFile(inner_path, file=file, cur=cur) + + +@PluginManager.registerTo("UiRequest") +class UiRequestPlugin(object): + def actionWrapper(self, path, extra_headers=None): + match = re.match("/(?P
[A-Za-z0-9\._-]+)(?P/.*|$)", path) + if not match: + return False + address = match.group("address") + + if self.server.site_manager.get(address): # Site already exists + return super(UiRequestPlugin, self).actionWrapper(path, extra_headers) + + if self.server.site_manager.isDomain(address): + address = self.server.site_manager.resolveDomain(address) + + if address in site_blacklist: + site = self.server.site_manager.get(config.homepage) + if not extra_headers: + extra_headers = [] + self.sendHeader(extra_headers=extra_headers[:]) + return iter([super(UiRequestPlugin, self).renderWrapper( + site, path, site.address + "//uimedia/plugins/mute/blacklisted.html?address=" + address, + "Blacklisted site", extra_headers, show_loadingscreen=False + )]) + else: + return super(UiRequestPlugin, self).actionWrapper(path, extra_headers) + + def actionUiMedia(self, path, *args, **kwargs): + if path.startswith("/uimedia/plugins/mute/"): + file_path = path.replace("/uimedia/plugins/mute/", "plugins/Mute/media/") + return self.actionFile(file_path) + else: + return super(UiRequestPlugin, self).actionUiMedia(path) diff --git a/plugins/Mute/media/blacklisted.html b/plugins/Mute/media/blacklisted.html new file mode 100644 index 00000000..5d2bf80c --- /dev/null +++ b/plugins/Mute/media/blacklisted.html @@ -0,0 +1,64 @@ + + + + + +
+

Site blocked

+

This site is on your blacklist:

+
+
Too much image
+
on 2015-01-25 12:32:11
+
+
Remove from blacklist
+
+ + + + + + \ No newline at end of file diff --git a/plugins/Mute/media/js/ZeroFrame.js b/plugins/Mute/media/js/ZeroFrame.js new file mode 100644 index 00000000..f3e2214b --- /dev/null +++ b/plugins/Mute/media/js/ZeroFrame.js @@ -0,0 +1,93 @@ +const CMD_INNER_READY = 'innerReady' +const CMD_RESPONSE = 'response' +const CMD_WRAPPER_READY = 'wrapperReady' +const CMD_PING = 'ping' +const CMD_PONG = 'pong' +const CMD_WRAPPER_OPENED_WEBSOCKET = 'wrapperOpenedWebsocket' +const CMD_WRAPPER_CLOSE_WEBSOCKET = 'wrapperClosedWebsocket' + +class ZeroFrame { + constructor(url) { + this.url = url + this.waiting_cb = {} + this.wrapper_nonce = document.location.href.replace(/.*wrapper_nonce=([A-Za-z0-9]+).*/, "$1") + this.connect() + this.next_message_id = 1 + this.init() + } + + init() { + return this + } + + connect() { + this.target = window.parent + window.addEventListener('message', e => this.onMessage(e), false) + this.cmd(CMD_INNER_READY) + } + + onMessage(e) { + let message = e.data + let cmd = message.cmd + if (cmd === CMD_RESPONSE) { + if (this.waiting_cb[message.to] !== undefined) { + this.waiting_cb[message.to](message.result) + } + else { + this.log("Websocket callback not found:", message) + } + } else if (cmd === CMD_WRAPPER_READY) { + this.cmd(CMD_INNER_READY) + } else if (cmd === CMD_PING) { + this.response(message.id, CMD_PONG) + } else if (cmd === CMD_WRAPPER_OPENED_WEBSOCKET) { + this.onOpenWebsocket() + } else if (cmd === CMD_WRAPPER_CLOSE_WEBSOCKET) { + this.onCloseWebsocket() + } else { + this.onRequest(cmd, message) + } + } + + onRequest(cmd, message) { + this.log("Unknown request", message) + } + + response(to, result) { + this.send({ + cmd: CMD_RESPONSE, + to: to, + result: result + }) + } + + cmd(cmd, params={}, cb=null) { + this.send({ + cmd: cmd, + params: params + }, cb) + } + + send(message, cb=null) { + message.wrapper_nonce = this.wrapper_nonce + message.id = this.next_message_id + this.next_message_id++ + this.target.postMessage(message, '*') + if (cb) { + this.waiting_cb[message.id] = cb + } + } + + log(...args) { + console.log.apply(console, ['[ZeroFrame]'].concat(args)) + } + + onOpenWebsocket() { + this.log('Websocket open') + } + + onCloseWebsocket() { + this.log('Websocket close') + } +} +