def validate_hash(self, password, stored_hash): """Validates that self.hash(password) == stored_hash. Args: password (unicode): Password to hash. stored_hash (bytes): Expected hash value. Returns: Deferred(bool): Whether self.hash(password) == stored_hash. """ def _do_validate_hash(): # Normalise the Unicode in the password pw = unicodedata.normalize("NFKC", password) return bcrypt.checkpw( pw.encode('utf8') + self.hs.config.password_pepper.encode("utf8"), stored_hash ) if stored_hash: if not isinstance(stored_hash, bytes): stored_hash = stored_hash.encode('ascii') return logcontext.defer_to_thread(self.hs.get_reactor(), _do_validate_hash) else: return defer.succeed(False)
def validate_hash(self, password, stored_hash): """Validates that self.hash(password) == stored_hash. Args: password (unicode): Password to hash. stored_hash (bytes): Expected hash value. Returns: Deferred(bool): Whether self.hash(password) == stored_hash. """ def _do_validate_hash(): # Normalise the Unicode in the password pw = unicodedata.normalize("NFKC", password) return bcrypt.checkpw( pw.encode("utf8") + self.hs.config.password_pepper.encode("utf8"), stored_hash, ) if stored_hash: if not isinstance(stored_hash, bytes): stored_hash = stored_hash.encode("ascii") return logcontext.defer_to_thread(self.hs.get_reactor(), _do_validate_hash) else: return defer.succeed(False)
def generate_remote_exact_thumbnail( self, server_name, file_id, media_id, t_width, t_height, t_method, t_type ): input_path = yield self.media_storage.ensure_media_is_in_local_cache( FileInfo(server_name, file_id, url_cache=False) ) thumbnailer = Thumbnailer(input_path) t_byte_source = yield logcontext.defer_to_thread( self.hs.get_reactor(), self._generate_thumbnail, thumbnailer, t_width, t_height, t_method, t_type, ) if t_byte_source: try: file_info = FileInfo( server_name=server_name, file_id=media_id, thumbnail=True, thumbnail_width=t_width, thumbnail_height=t_height, thumbnail_method=t_method, thumbnail_type=t_type, ) output_path = yield self.media_storage.store_file( t_byte_source, file_info ) finally: t_byte_source.close() logger.info("Stored thumbnail in file %r", output_path) t_len = os.path.getsize(output_path) yield self.store.store_remote_media_thumbnail( server_name, media_id, file_id, t_width, t_height, t_type, t_method, t_len, ) defer.returnValue(output_path)
def store_file(self, path, file_info): """See StorageProvider.store_file""" primary_fname = os.path.join(self.cache_directory, path) backup_fname = os.path.join(self.base_directory, path) dirname = os.path.dirname(backup_fname) if not os.path.exists(dirname): os.makedirs(dirname) return logcontext.defer_to_thread(self.hs.get_reactor(), shutil.copyfile, primary_fname, backup_fname)
def store_file(self, path, file_info): """See StorageProvider.store_file""" primary_fname = os.path.join(self.cache_directory, path) backup_fname = os.path.join(self.base_directory, path) dirname = os.path.dirname(backup_fname) if not os.path.exists(dirname): os.makedirs(dirname) return logcontext.defer_to_thread( self.hs.get_reactor(), shutil.copyfile, primary_fname, backup_fname, )
def hash(self, password): """Computes a secure hash of password. Args: password (unicode): Password to hash. Returns: Deferred(unicode): Hashed password. """ def _do_hash(): # Normalise the Unicode in the password pw = unicodedata.normalize("NFKC", password) return bcrypt.hashpw( pw.encode('utf8') + self.hs.config.password_pepper.encode("utf8"), bcrypt.gensalt(self.bcrypt_rounds), ).decode('ascii') return logcontext.defer_to_thread(self.hs.get_reactor(), _do_hash)
def store_file(self, source, file_info): """Write `source` to the on disk media store, and also any other configured storage providers Args: source: A file like object that should be written file_info (FileInfo): Info about the file to store Returns: Deferred[str]: the file path written to in the primary media store """ with self.store_into_file(file_info) as (f, fname, finish_cb): # Write to the main repository yield logcontext.defer_to_thread(self.hs.get_reactor(), _write_file_synchronously, source, f) yield finish_cb() defer.returnValue(fname)
def generate_remote_exact_thumbnail(self, server_name, file_id, media_id, t_width, t_height, t_method, t_type): input_path = yield self.media_storage.ensure_media_is_in_local_cache(FileInfo( server_name, file_id, url_cache=False, )) thumbnailer = Thumbnailer(input_path) t_byte_source = yield logcontext.defer_to_thread( self.hs.get_reactor(), self._generate_thumbnail, thumbnailer, t_width, t_height, t_method, t_type ) if t_byte_source: try: file_info = FileInfo( server_name=server_name, file_id=media_id, thumbnail=True, thumbnail_width=t_width, thumbnail_height=t_height, thumbnail_method=t_method, thumbnail_type=t_type, ) output_path = yield self.media_storage.store_file( t_byte_source, file_info, ) finally: t_byte_source.close() logger.info("Stored thumbnail in file %r", output_path) t_len = os.path.getsize(output_path) yield self.store.store_remote_media_thumbnail( server_name, media_id, file_id, t_width, t_height, t_type, t_method, t_len ) defer.returnValue(output_path)
def store_file(self, source, file_info): """Write `source` to the on disk media store, and also any other configured storage providers Args: source: A file like object that should be written file_info (FileInfo): Info about the file to store Returns: Deferred[str]: the file path written to in the primary media store """ with self.store_into_file(file_info) as (f, fname, finish_cb): # Write to the main repository yield logcontext.defer_to_thread( self.hs.get_reactor(), _write_file_synchronously, source, f, ) yield finish_cb() defer.returnValue(fname)
def _generate_thumbnails(self, server_name, media_id, file_id, media_type, url_cache=False): """Generate and store thumbnails for an image. Args: server_name (str|None): The server name if remote media, else None if local media_id (str): The media ID of the content. (This is the same as the file_id for local content) file_id (str): Local file ID media_type (str): The content type of the file url_cache (bool): If we are thumbnailing images downloaded for the URL cache, used exclusively by the url previewer Returns: Deferred[dict]: Dict with "width" and "height" keys of original image """ requirements = self._get_thumbnail_requirements(media_type) if not requirements: return input_path = yield self.media_storage.ensure_media_is_in_local_cache( FileInfo( server_name, file_id, url_cache=url_cache, )) thumbnailer = Thumbnailer(input_path) m_width = thumbnailer.width m_height = thumbnailer.height if m_width * m_height >= self.max_image_pixels: logger.info("Image too large to thumbnail %r x %r > %r", m_width, m_height, self.max_image_pixels) return if thumbnailer.transpose_method is not None: m_width, m_height = yield logcontext.defer_to_thread( self.hs.get_reactor(), thumbnailer.transpose) # We deduplicate the thumbnail sizes by ignoring the cropped versions if # they have the same dimensions of a scaled one. thumbnails = {} for r_width, r_height, r_method, r_type in requirements: if r_method == "crop": thumbnails.setdefault((r_width, r_height, r_type), r_method) elif r_method == "scale": t_width, t_height = thumbnailer.aspect(r_width, r_height) t_width = min(m_width, t_width) t_height = min(m_height, t_height) thumbnails[(t_width, t_height, r_type)] = r_method # Now we generate the thumbnails for each dimension, store it for (t_width, t_height, t_type), t_method in iteritems(thumbnails): # Generate the thumbnail if t_method == "crop": t_byte_source = yield logcontext.defer_to_thread( self.hs.get_reactor(), thumbnailer.crop, t_width, t_height, t_type, ) elif t_method == "scale": t_byte_source = yield logcontext.defer_to_thread( self.hs.get_reactor(), thumbnailer.scale, t_width, t_height, t_type, ) else: logger.error("Unrecognized method: %r", t_method) continue if not t_byte_source: continue try: file_info = FileInfo( server_name=server_name, file_id=file_id, thumbnail=True, thumbnail_width=t_width, thumbnail_height=t_height, thumbnail_method=t_method, thumbnail_type=t_type, url_cache=url_cache, ) output_path = yield self.media_storage.store_file( t_byte_source, file_info, ) finally: t_byte_source.close() t_len = os.path.getsize(output_path) # Write to database if server_name: yield self.store.store_remote_media_thumbnail( server_name, media_id, file_id, t_width, t_height, t_type, t_method, t_len) else: yield self.store.store_local_thumbnail(media_id, t_width, t_height, t_type, t_method, t_len) defer.returnValue({ "width": m_width, "height": m_height, })
def _generate_thumbnails(self, server_name, media_id, file_id, media_type, url_cache=False): """Generate and store thumbnails for an image. Args: server_name (str|None): The server name if remote media, else None if local media_id (str): The media ID of the content. (This is the same as the file_id for local content) file_id (str): Local file ID media_type (str): The content type of the file url_cache (bool): If we are thumbnailing images downloaded for the URL cache, used exclusively by the url previewer Returns: Deferred[dict]: Dict with "width" and "height" keys of original image """ requirements = self._get_thumbnail_requirements(media_type) if not requirements: return input_path = yield self.media_storage.ensure_media_is_in_local_cache(FileInfo( server_name, file_id, url_cache=url_cache, )) thumbnailer = Thumbnailer(input_path) m_width = thumbnailer.width m_height = thumbnailer.height if m_width * m_height >= self.max_image_pixels: logger.info( "Image too large to thumbnail %r x %r > %r", m_width, m_height, self.max_image_pixels ) return # We deduplicate the thumbnail sizes by ignoring the cropped versions if # they have the same dimensions of a scaled one. thumbnails = {} for r_width, r_height, r_method, r_type in requirements: if r_method == "crop": thumbnails.setdefault((r_width, r_height, r_type), r_method) elif r_method == "scale": t_width, t_height = thumbnailer.aspect(r_width, r_height) t_width = min(m_width, t_width) t_height = min(m_height, t_height) thumbnails[(t_width, t_height, r_type)] = r_method # Now we generate the thumbnails for each dimension, store it for (t_width, t_height, t_type), t_method in iteritems(thumbnails): # Generate the thumbnail if t_method == "crop": t_byte_source = yield logcontext.defer_to_thread( self.hs.get_reactor(), thumbnailer.crop, t_width, t_height, t_type, ) elif t_method == "scale": t_byte_source = yield logcontext.defer_to_thread( self.hs.get_reactor(), thumbnailer.scale, t_width, t_height, t_type, ) else: logger.error("Unrecognized method: %r", t_method) continue if not t_byte_source: continue try: file_info = FileInfo( server_name=server_name, file_id=file_id, thumbnail=True, thumbnail_width=t_width, thumbnail_height=t_height, thumbnail_method=t_method, thumbnail_type=t_type, url_cache=url_cache, ) output_path = yield self.media_storage.store_file( t_byte_source, file_info, ) finally: t_byte_source.close() t_len = os.path.getsize(output_path) # Write to database if server_name: yield self.store.store_remote_media_thumbnail( server_name, media_id, file_id, t_width, t_height, t_type, t_method, t_len ) else: yield self.store.store_local_thumbnail( media_id, t_width, t_height, t_type, t_method, t_len ) defer.returnValue({ "width": m_width, "height": m_height, })