Reformatted code base using black.
This commit is contained in:
parent
56319cbad3
commit
53fdaa9d09
1 changed files with 12604 additions and 8966 deletions
|
|
@ -82,10 +82,7 @@ OVER_QUOTA_TXT = D_(
|
|||
"{used_space}, you can't upload {file_size} more."
|
||||
)
|
||||
|
||||
HTTP_VERSION = unicodedata.normalize(
|
||||
'NFKD',
|
||||
f"{C.APP_NAME} file sharing {C.APP_VERSION}"
|
||||
)
|
||||
HTTP_VERSION = unicodedata.normalize("NFKD", f"{C.APP_NAME} file sharing {C.APP_VERSION}")
|
||||
|
||||
|
||||
class HTTPFileServer(resource.Resource):
|
||||
|
|
@ -94,32 +91,32 @@ class HTTPFileServer(resource.Resource):
|
|||
def errorPage(self, request, code):
|
||||
request.setResponseCode(code)
|
||||
if code == http.BAD_REQUEST:
|
||||
brief = 'Bad Request'
|
||||
brief = "Bad Request"
|
||||
details = "Your request is invalid"
|
||||
elif code == http.FORBIDDEN:
|
||||
brief = 'Forbidden'
|
||||
brief = "Forbidden"
|
||||
details = "You're not allowed to use this resource"
|
||||
elif code == http.NOT_FOUND:
|
||||
brief = 'Not Found'
|
||||
brief = "Not Found"
|
||||
details = "No resource found at this URL"
|
||||
else:
|
||||
brief = 'Error'
|
||||
brief = "Error"
|
||||
details = "This resource can't be used"
|
||||
log.error(f"Unexpected return code used: {code}")
|
||||
log.warning(
|
||||
f'Error returned while trying to access url {request.uri.decode()}: '
|
||||
f"Error returned while trying to access url {request.uri.decode()}: "
|
||||
f'"{brief}" ({code}): {details}'
|
||||
)
|
||||
|
||||
return resource.ErrorPage(code, brief, details).render(request)
|
||||
|
||||
def get_disposition_type(self, media_type, media_subtype):
|
||||
if media_type in ('image', 'video'):
|
||||
return 'inline'
|
||||
elif media_type == 'application' and media_subtype == 'pdf':
|
||||
return 'inline'
|
||||
if media_type in ("image", "video"):
|
||||
return "inline"
|
||||
elif media_type == "application" and media_subtype == "pdf":
|
||||
return "inline"
|
||||
else:
|
||||
return 'attachment'
|
||||
return "attachment"
|
||||
|
||||
def render(self, request):
|
||||
request.setHeader("server", HTTP_VERSION)
|
||||
|
|
@ -127,13 +124,14 @@ class HTTPFileServer(resource.Resource):
|
|||
request.setHeader("Access-Control-Allow-Methods", "OPTIONS, HEAD, GET, PUT")
|
||||
request.setHeader(
|
||||
"Access-Control-Allow-Headers",
|
||||
"Content-Type, Range, Xmpp-File-Path, Xmpp-File-No-Http")
|
||||
"Content-Type, Range, Xmpp-File-Path, Xmpp-File-No-Http",
|
||||
)
|
||||
request.setHeader("Access-Control-Allow-Credentials", "true")
|
||||
request.setHeader("Accept-Ranges", "bytes")
|
||||
|
||||
request.setHeader(
|
||||
"Access-Control-Expose-Headers",
|
||||
"Date, Content-Length, Content-Range")
|
||||
"Access-Control-Expose-Headers", "Date, Content-Length, Content-Range"
|
||||
)
|
||||
return super().render(request)
|
||||
|
||||
def render_OPTIONS(self, request):
|
||||
|
|
@ -157,7 +155,8 @@ class HTTPFileServer(resource.Resource):
|
|||
request.finish()
|
||||
return
|
||||
found_files = await request.file_sharing.host.memory.get_files(
|
||||
client=None, peer_jid=None, perms_to_check=None, public_id=upload_id)
|
||||
client=None, peer_jid=None, perms_to_check=None, public_id=upload_id
|
||||
)
|
||||
if not found_files:
|
||||
request.write(self.errorPage(request, http.NOT_FOUND))
|
||||
request.finish()
|
||||
|
|
@ -166,22 +165,22 @@ class HTTPFileServer(resource.Resource):
|
|||
log.error(f"more that one files found for public id {upload_id!r}")
|
||||
|
||||
found_file = found_files[0]
|
||||
file_path = request.file_sharing.files_path/found_file['file_hash']
|
||||
file_path = request.file_sharing.files_path / found_file["file_hash"]
|
||||
file_res = static.File(file_path)
|
||||
file_res.type = f'{found_file["media_type"]}/{found_file["media_subtype"]}'
|
||||
file_res.encoding = file_res.contentEncodings.get(Path(found_file['name']).suffix)
|
||||
file_res.encoding = file_res.contentEncodings.get(Path(found_file["name"]).suffix)
|
||||
disp_type = self.get_disposition_type(
|
||||
found_file['media_type'], found_file['media_subtype'])
|
||||
found_file["media_type"], found_file["media_subtype"]
|
||||
)
|
||||
# the URL is percent encoded, and not all browsers/tools unquote the file name,
|
||||
# thus we add a content disposition header
|
||||
request.setHeader(
|
||||
'Content-Disposition',
|
||||
f"{disp_type}; filename*=UTF-8''{quote(found_file['name'])}"
|
||||
"Content-Disposition",
|
||||
f"{disp_type}; filename*=UTF-8''{quote(found_file['name'])}",
|
||||
)
|
||||
# cf. https://xmpp.org/extensions/xep-0363.html#server
|
||||
request.setHeader(
|
||||
'Content-Security-Policy',
|
||||
"default-src 'none'; frame-ancestors 'none';"
|
||||
"Content-Security-Policy", "default-src 'none'; frame-ancestors 'none';"
|
||||
)
|
||||
ret = file_res.render(request)
|
||||
if ret != server.NOT_DONE_YET:
|
||||
|
|
@ -215,7 +214,7 @@ class HTTPFileServer(resource.Resource):
|
|||
if path:
|
||||
path = unquote(path)
|
||||
else:
|
||||
path = "/uploads"
|
||||
path = "/uploads"
|
||||
if request.getHeader("Xmpp-File-No-Http") is not None:
|
||||
public_id = None
|
||||
else:
|
||||
|
|
@ -225,11 +224,14 @@ class HTTPFileServer(resource.Resource):
|
|||
"name": unquote(upload_request.filename),
|
||||
"mime_type": upload_request.content_type,
|
||||
"size": upload_request.size,
|
||||
"path": path
|
||||
"path": path,
|
||||
}
|
||||
|
||||
await request.file_sharing.register_received_file(
|
||||
client, upload_request.from_, file_data, tmp_file_path,
|
||||
client,
|
||||
upload_request.from_,
|
||||
file_data,
|
||||
tmp_file_path,
|
||||
public_id=public_id,
|
||||
)
|
||||
|
||||
|
|
@ -256,11 +258,13 @@ class FileSharingRequest(server.Request):
|
|||
# we normalise the path
|
||||
path = urlparse(path.decode()).path
|
||||
try:
|
||||
__, upload_id, filename = path.split('/')
|
||||
__, upload_id, filename = path.split("/")
|
||||
except ValueError:
|
||||
raise exceptions.DataError("no enought path elements")
|
||||
if len(upload_id) < 10:
|
||||
raise exceptions.DataError(f"invalid upload ID received for a PUT: {upload_id!r}")
|
||||
raise exceptions.DataError(
|
||||
f"invalid upload ID received for a PUT: {upload_id!r}"
|
||||
)
|
||||
|
||||
self._upload_data = (upload_id, filename)
|
||||
return self._upload_data
|
||||
|
|
@ -276,11 +280,11 @@ class FileSharingRequest(server.Request):
|
|||
def refuse_request(self):
|
||||
if self.content is not None:
|
||||
self.content.close()
|
||||
self.content = open(os.devnull, 'w+b')
|
||||
self.content = open(os.devnull, "w+b")
|
||||
self.channel._respondToBadRequestAndDisconnect()
|
||||
|
||||
def gotLength(self, length):
|
||||
if self.channel._command.decode().upper() == 'PUT':
|
||||
if self.channel._command.decode().upper() == "PUT":
|
||||
# for PUT we check early if upload_id is fine, to avoid buffering a file we'll refuse
|
||||
# we buffer the file in component's TMP_BUFFER_DIR, so we just have to rename it at the end
|
||||
try:
|
||||
|
|
@ -289,9 +293,13 @@ class FileSharingRequest(server.Request):
|
|||
log.warning(f"Invalid PUT request, we stop here: {e}")
|
||||
return self.refuse_request()
|
||||
try:
|
||||
client, upload_request, timer = self.file_sharing.expected_uploads.pop(upload_id)
|
||||
client, upload_request, timer = self.file_sharing.expected_uploads.pop(
|
||||
upload_id
|
||||
)
|
||||
except KeyError:
|
||||
log.warning(f"unknown (expired?) upload ID received for a PUT: {upload_id!r}")
|
||||
log.warning(
|
||||
f"unknown (expired?) upload ID received for a PUT: {upload_id!r}"
|
||||
)
|
||||
return self.refuse_request()
|
||||
|
||||
if not timer.active:
|
||||
|
|
@ -309,10 +317,9 @@ class FileSharingRequest(server.Request):
|
|||
|
||||
self.upload_request_data = (client, upload_request)
|
||||
|
||||
file_tmp_path = files_utils.get_unique_name(
|
||||
self.file_tmp_dir/upload_id)
|
||||
file_tmp_path = files_utils.get_unique_name(self.file_tmp_dir / upload_id)
|
||||
|
||||
self.content = open(file_tmp_path, 'w+b')
|
||||
self.content = open(file_tmp_path, "w+b")
|
||||
else:
|
||||
return super().gotLength(length)
|
||||
|
||||
|
|
@ -331,8 +338,8 @@ class FileSharingSite(server.Site):
|
|||
super().__init__(HTTPFileServer())
|
||||
|
||||
def getContentFile(self, length):
|
||||
file_tmp_path = self.file_tmp_dir/shortuuid.uuid()
|
||||
return open(file_tmp_path, 'w+b')
|
||||
file_tmp_path = self.file_tmp_dir / shortuuid.uuid()
|
||||
return open(file_tmp_path, "w+b")
|
||||
|
||||
|
||||
class FileSharing:
|
||||
|
|
@ -356,37 +363,53 @@ class FileSharing:
|
|||
self._t = self.host.plugins["XEP-0264"]
|
||||
self._hu = self.host.plugins["XEP-0363"]
|
||||
self._hu.register_handler(self._on_http_upload)
|
||||
self.host.trigger.add_with_check("FILE_getDestDir", self, self._get_dest_dir_trigger)
|
||||
self.host.trigger.add_with_check(
|
||||
"XEP-0234_fileSendingRequest", self, self._file_sending_request_trigger, priority=1000
|
||||
"FILE_getDestDir", self, self._get_dest_dir_trigger
|
||||
)
|
||||
self.host.trigger.add_with_check(
|
||||
"XEP-0234_fileSendingRequest",
|
||||
self,
|
||||
self._file_sending_request_trigger,
|
||||
priority=1000,
|
||||
)
|
||||
self.host.trigger.add_with_check(
|
||||
"XEP-0234_buildFileElement", self, self._add_file_metadata_elts
|
||||
)
|
||||
self.host.trigger.add_with_check(
|
||||
"XEP-0234_parseFileElement", self, self._get_file_metadata_elts
|
||||
)
|
||||
self.host.trigger.add_with_check(
|
||||
"XEP-0329_compGetFilesFromNode", self, self._add_file_metadata
|
||||
)
|
||||
self.host.trigger.add_with_check("XEP-0234_buildFileElement", self, self._add_file_metadata_elts)
|
||||
self.host.trigger.add_with_check("XEP-0234_parseFileElement", self, self._get_file_metadata_elts)
|
||||
self.host.trigger.add_with_check("XEP-0329_compGetFilesFromNode", self, self._add_file_metadata)
|
||||
self.host.trigger.add_with_check(
|
||||
"XEP-0329_compGetFilesFromNode_build_directory",
|
||||
self,
|
||||
self._add_directory_metadata_elts)
|
||||
self._add_directory_metadata_elts,
|
||||
)
|
||||
self.host.trigger.add_with_check(
|
||||
"XEP-0329_parseResult_directory",
|
||||
self,
|
||||
self._get_directory_metadata_elts)
|
||||
"XEP-0329_parseResult_directory", self, self._get_directory_metadata_elts
|
||||
)
|
||||
self.files_path = self.host.get_local_path(None, C.FILES_DIR)
|
||||
self.http_port = int(self.host.memory.config_get(
|
||||
'component file-sharing', 'http_upload_port', 8888))
|
||||
self.http_port = int(
|
||||
self.host.memory.config_get(
|
||||
"component file-sharing", "http_upload_port", 8888
|
||||
)
|
||||
)
|
||||
connection_type = self.host.memory.config_get(
|
||||
'component file-sharing', 'http_upload_connection_type', 'https')
|
||||
if connection_type not in ('http', 'https'):
|
||||
"component file-sharing", "http_upload_connection_type", "https"
|
||||
)
|
||||
if connection_type not in ("http", "https"):
|
||||
raise exceptions.ConfigError(
|
||||
'bad http_upload_connection_type, you must use one of "http" or "https"'
|
||||
)
|
||||
self.server = FileSharingSite(self)
|
||||
self.expected_uploads = {}
|
||||
if connection_type == 'http':
|
||||
if connection_type == "http":
|
||||
reactor.listenTCP(self.http_port, self.server)
|
||||
else:
|
||||
options = tls.get_options_from_config(
|
||||
self.host.memory.config, "component file-sharing")
|
||||
self.host.memory.config, "component file-sharing"
|
||||
)
|
||||
tls.tls_options_check(options)
|
||||
context_factory = tls.get_tls_context_factory(options)
|
||||
reactor.listenSSL(self.http_port, self.server, context_factory)
|
||||
|
|
@ -400,7 +423,8 @@ class FileSharing:
|
|||
|
||||
self.init()
|
||||
public_base_url = self.host.memory.config_get(
|
||||
'component file-sharing', 'http_upload_public_facing_url')
|
||||
"component file-sharing", "http_upload_public_facing_url"
|
||||
)
|
||||
if public_base_url is None:
|
||||
client._file_sharing_base_url = f"https://{client.host}:{self.http_port}"
|
||||
else:
|
||||
|
|
@ -441,7 +465,8 @@ class FileSharing:
|
|||
thumbnails.append({"id": thumb_id, "size": thumb_size})
|
||||
|
||||
async def register_received_file(
|
||||
self, client, peer_jid, file_data, file_path, public_id=None, extra=None):
|
||||
self, client, peer_jid, file_data, file_path, public_id=None, extra=None
|
||||
):
|
||||
"""Post file reception tasks
|
||||
|
||||
once file is received, this method create hash/thumbnails if necessary
|
||||
|
|
@ -463,9 +488,9 @@ class FileSharing:
|
|||
file_hash = file_data["hash_hasher"].hexdigest()
|
||||
else:
|
||||
hasher = self._h.get_hasher(HASH_ALGO)
|
||||
with file_path.open('rb') as f:
|
||||
with file_path.open("rb") as f:
|
||||
file_hash = await self._h.calculate_hash(f, hasher)
|
||||
final_path = self.files_path/file_hash
|
||||
final_path = self.files_path / file_hash
|
||||
|
||||
if final_path.is_file():
|
||||
log.debug(
|
||||
|
|
@ -490,8 +515,11 @@ class FileSharing:
|
|||
try:
|
||||
await video.get_thumbnail(final_path, thumb_path)
|
||||
except Exception as e:
|
||||
log.warning(_("Can't get thumbnail for {final_path}: {e}").format(
|
||||
final_path=final_path, e=e))
|
||||
log.warning(
|
||||
_("Can't get thumbnail for {final_path}: {e}").format(
|
||||
final_path=final_path, e=e
|
||||
)
|
||||
)
|
||||
else:
|
||||
await self.generate_thumbnails(extra, thumb_path)
|
||||
|
||||
|
|
@ -534,14 +562,15 @@ class FileSharing:
|
|||
text=OVER_QUOTA_TXT.format(
|
||||
quota=utils.get_human_size(quota),
|
||||
used_space=utils.get_human_size(used_space),
|
||||
file_size=utils.get_human_size(file_data['size'])
|
||||
)
|
||||
file_size=utils.get_human_size(file_data["size"]),
|
||||
),
|
||||
)
|
||||
file_tmp_dir = self.host.get_local_path(
|
||||
None, C.FILES_TMP_DIR, peer_jid.userhost(), component=True
|
||||
)
|
||||
file_tmp_path = file_data['file_path'] = files_utils.get_unique_name(
|
||||
file_tmp_dir/filename)
|
||||
file_tmp_path = file_data["file_path"] = files_utils.get_unique_name(
|
||||
file_tmp_dir / filename
|
||||
)
|
||||
|
||||
transfer_data["finished_d"].addCallback(
|
||||
lambda __: defer.ensureDeferred(
|
||||
|
|
@ -559,8 +588,8 @@ class FileSharing:
|
|||
):
|
||||
"""This method retrieve a file on request, and send if after checking permissions"""
|
||||
peer_jid = session["peer_jid"]
|
||||
if session['local_jid'].user:
|
||||
owner = client.get_owner_from_jid(session['local_jid'])
|
||||
if session["local_jid"].user:
|
||||
owner = client.get_owner_from_jid(session["local_jid"])
|
||||
else:
|
||||
owner = peer_jid
|
||||
try:
|
||||
|
|
@ -592,9 +621,10 @@ class FileSharing:
|
|||
|
||||
# we only use the first found file
|
||||
found_file = found_files[0]
|
||||
if found_file['type'] != C.FILE_TYPE_FILE:
|
||||
raise TypeError("a file was expected, type is {type_}".format(
|
||||
type_=found_file['type']))
|
||||
if found_file["type"] != C.FILE_TYPE_FILE:
|
||||
raise TypeError(
|
||||
"a file was expected, type is {type_}".format(type_=found_file["type"])
|
||||
)
|
||||
file_hash = found_file["file_hash"]
|
||||
file_path = self.files_path / file_hash
|
||||
file_data["hash_hasher"] = hasher = self._h.get_hasher(found_file["hash_algo"])
|
||||
|
|
@ -624,9 +654,11 @@ class FileSharing:
|
|||
else:
|
||||
return (
|
||||
False,
|
||||
defer.ensureDeferred(self._retrieve_files(
|
||||
client, session, content_data, content_name, file_data, file_elt
|
||||
)),
|
||||
defer.ensureDeferred(
|
||||
self._retrieve_files(
|
||||
client, session, content_data, content_name, file_data, file_elt
|
||||
)
|
||||
),
|
||||
)
|
||||
|
||||
## HTTP Upload ##
|
||||
|
|
@ -639,7 +671,7 @@ class FileSharing:
|
|||
|
||||
async def _on_http_upload(self, client, request):
|
||||
# filename should be already cleaned, but it's better to double check
|
||||
assert '/' not in request.filename
|
||||
assert "/" not in request.filename
|
||||
# client._file_sharing_allowed_hosts is set in plugin XEP-0329
|
||||
if request.from_.host not in client._file_sharing_allowed_hosts:
|
||||
raise error.StanzaError("forbidden")
|
||||
|
|
@ -654,13 +686,15 @@ class FileSharing:
|
|||
text=OVER_QUOTA_TXT.format(
|
||||
quota=utils.get_human_size(quota),
|
||||
used_space=utils.get_human_size(used_space),
|
||||
file_size=utils.get_human_size(request.size)
|
||||
file_size=utils.get_human_size(request.size),
|
||||
),
|
||||
appCondition=self._hu.get_file_too_large_elt(
|
||||
max(quota - used_space, 0)
|
||||
),
|
||||
appCondition = self._hu.get_file_too_large_elt(max(quota - used_space, 0))
|
||||
)
|
||||
|
||||
upload_id = shortuuid.ShortUUID().random(length=30)
|
||||
assert '/' not in upload_id
|
||||
assert "/" not in upload_id
|
||||
timer = reactor.callLater(30, self._purge_slot, upload_id)
|
||||
self.expected_uploads[upload_id] = (client, request, timer)
|
||||
url = urljoin(client._file_sharing_base_url, f"{upload_id}/{request.filename}")
|
||||
|
|
@ -675,7 +709,7 @@ class FileSharing:
|
|||
|
||||
def _add_file_metadata_elts(self, client, file_elt, extra_args):
|
||||
# affiliation
|
||||
affiliation = extra_args.get('affiliation')
|
||||
affiliation = extra_args.get("affiliation")
|
||||
if affiliation is not None:
|
||||
file_elt.addElement((NS_FS_AFFILIATION, "affiliation"), content=affiliation)
|
||||
|
||||
|
|
@ -715,7 +749,8 @@ class FileSharing:
|
|||
return True
|
||||
|
||||
def _add_file_metadata(
|
||||
self, client, iq_elt, iq_result_elt, owner, node_path, files_data):
|
||||
self, client, iq_elt, iq_result_elt, owner, node_path, files_data
|
||||
):
|
||||
for file_data in files_data:
|
||||
file_data["comments_url"] = uri.build_xmpp_uri(
|
||||
"pubsub",
|
||||
|
|
@ -725,22 +760,21 @@ class FileSharing:
|
|||
return True
|
||||
|
||||
def _add_directory_metadata_elts(
|
||||
self, client, file_data, directory_elt, owner, node_path):
|
||||
affiliation = file_data.get('affiliation')
|
||||
self, client, file_data, directory_elt, owner, node_path
|
||||
):
|
||||
affiliation = file_data.get("affiliation")
|
||||
if affiliation is not None:
|
||||
directory_elt.addElement(
|
||||
(NS_FS_AFFILIATION, "affiliation"),
|
||||
content=affiliation
|
||||
(NS_FS_AFFILIATION, "affiliation"), content=affiliation
|
||||
)
|
||||
|
||||
def _get_directory_metadata_elts(
|
||||
self, client, elt, file_data):
|
||||
def _get_directory_metadata_elts(self, client, elt, file_data):
|
||||
try:
|
||||
affiliation_elt = next(elt.elements(NS_FS_AFFILIATION, "affiliation"))
|
||||
except StopIteration:
|
||||
pass
|
||||
else:
|
||||
file_data['affiliation'] = str(affiliation_elt)
|
||||
file_data["affiliation"] = str(affiliation_elt)
|
||||
|
||||
|
||||
class Comments_handler(pubsub.PubSubService):
|
||||
|
|
@ -841,7 +875,9 @@ class Comments_handler(pubsub.PubSubService):
|
|||
peer_jid = None
|
||||
else:
|
||||
peer_jid = requestor.userhost()
|
||||
update_cb = partial(self.comments_update, new_comments=comments, peer_jid=peer_jid)
|
||||
update_cb = partial(
|
||||
self.comments_update, new_comments=comments, peer_jid=peer_jid
|
||||
)
|
||||
try:
|
||||
await self.host.memory.file_update(file_id, "extra", update_cb)
|
||||
except exceptions.PermissionError:
|
||||
|
|
|
|||
Loading…
Reference in a new issue