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
+
+
+
+
+
+
+
+
+
\ 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')
+ }
+}
+