tahoe-lafs/src/allmydata/blacklist.py
2021-03-31 10:35:25 -04:00

171 lines
5.2 KiB
Python

"""
Ported to Python 3.
"""
from __future__ import absolute_import
from __future__ import division
from __future__ import print_function
from __future__ import unicode_literals
from future.utils import PY2
if PY2:
from future.builtins import filter, map, zip, ascii, chr, hex, input, next, oct, open, pow, round, super, bytes, dict, list, object, range, str, max, min # noqa: F401
import os
from zope.interface import implementer
from twisted.internet import defer
from twisted.python import log as twisted_log
from allmydata.interfaces import IFileNode, IFilesystemNode
from allmydata.util import base32
from allmydata.util.encodingutil import quote_output
class FileProhibited(Exception):
"""This client has been configured to prohibit access to this object."""
def __init__(self, reason):
Exception.__init__(self, "Access Prohibited: %s" % quote_output(reason, encoding='utf-8', quotemarks=False))
self.reason = reason
class Blacklist(object):
def __init__(self, blacklist_fn):
self.blacklist_fn = blacklist_fn
self.last_mtime = None
self.entries = {}
self.read_blacklist() # sets .last_mtime and .entries
def read_blacklist(self):
try:
current_mtime = os.stat(self.blacklist_fn).st_mtime
except EnvironmentError:
# unreadable blacklist file means no blacklist
self.entries.clear()
return
try:
if self.last_mtime is None or current_mtime > self.last_mtime:
self.entries.clear()
with open(self.blacklist_fn, "rb") as f:
for line in f:
line = line.strip()
if not line or line.startswith(b"#"):
continue
si_s, reason = line.split(None, 1)
si = base32.a2b(si_s) # must be valid base32
self.entries[si] = reason
self.last_mtime = current_mtime
except Exception as e:
twisted_log.err(e, "unparseable blacklist file")
raise
def check_storageindex(self, si):
self.read_blacklist()
reason = self.entries.get(si, None)
if reason is not None:
# log this to logs/twistd.log, since web logs go there too
twisted_log.msg("blacklist prohibited access to SI %r: %r" %
(base32.b2a(si), reason))
return reason
@implementer(IFileNode)
class ProhibitedNode(object):
def __init__(self, wrapped_node, reason):
assert IFilesystemNode.providedBy(wrapped_node), wrapped_node
self.wrapped_node = wrapped_node
self.reason = reason
def get_cap(self):
return self.wrapped_node.get_cap()
def get_readcap(self):
return self.wrapped_node.get_readcap()
def is_readonly(self):
return self.wrapped_node.is_readonly()
def is_mutable(self):
return self.wrapped_node.is_mutable()
def is_unknown(self):
return self.wrapped_node.is_unknown()
def is_allowed_in_immutable_directory(self):
return self.wrapped_node.is_allowed_in_immutable_directory()
def is_alleged_immutable(self):
return self.wrapped_node.is_alleged_immutable()
def raise_error(self):
# We don't raise an exception here because that would prevent the node from being listed.
pass
def get_uri(self):
return self.wrapped_node.get_uri()
def get_write_uri(self):
return self.wrapped_node.get_write_uri()
def get_readonly_uri(self):
return self.wrapped_node.get_readonly_uri()
def get_storage_index(self):
return self.wrapped_node.get_storage_index()
def get_verify_cap(self):
return self.wrapped_node.get_verify_cap()
def get_repair_cap(self):
return self.wrapped_node.get_repair_cap()
def get_size(self):
return None
def get_current_size(self):
return defer.succeed(None)
def get_size_of_best_version(self):
return defer.succeed(None)
def check(self, monitor, verify, add_lease):
return defer.succeed(None)
def check_and_repair(self, monitor, verify, add_lease):
return defer.succeed(None)
def get_version(self):
return None
# Omitting any of these methods would fail safe; they are just to ensure correct error reporting.
def get_best_readable_version(self):
raise FileProhibited(self.reason)
def download_best_version(self):
raise FileProhibited(self.reason)
def get_best_mutable_version(self):
raise FileProhibited(self.reason)
def overwrite(self, new_contents):
raise FileProhibited(self.reason)
def modify(self, modifier_cb):
raise FileProhibited(self.reason)
def get_servermap(self, mode):
raise FileProhibited(self.reason)
def download_version(self, servermap, version):
raise FileProhibited(self.reason)
def upload(self, new_contents, servermap):
raise FileProhibited(self.reason)
def get_writekey(self):
raise FileProhibited(self.reason)
def read(self, consumer, offset=0, size=None):
raise FileProhibited(self.reason)