def test_configure_filedepot(self, no_filedepots): from depot.manager import DepotManager from kotti.filedepot import configure_filedepot from kotti import tests tests.TFS1 = Mock(return_value=Mock(marker="TFS1")) tests.TFS2 = Mock(return_value=Mock(marker="TFS2")) settings = { "kotti.depot.0.backend": "kotti.tests.TFS1", "kotti.depot.0.name": "localfs", "kotti.depot.0.location": "/tmp", "kotti.depot.1.backend": "kotti.tests.TFS2", "kotti.depot.1.uri": "mongo://", "kotti.depot.1.name": "mongo", } configure_filedepot(settings) assert DepotManager.get().marker == "TFS1" assert DepotManager.get("localfs").marker == "TFS1" assert DepotManager.get("mongo").marker == "TFS2" tests.TFS1.assert_called_with(location="/tmp") tests.TFS2.assert_called_with(uri="mongo://") del tests.TFS1 del tests.TFS2
def test_configure_filedepot(self, no_filedepots): from depot.manager import DepotManager from kotti.filedepot import configure_filedepot from kotti import tests tests.TFS1 = Mock(return_value=Mock(marker="TFS1")) tests.TFS2 = Mock(return_value=Mock(marker="TFS2")) settings = { 'kotti.depot.0.backend': 'kotti.tests.TFS1', 'kotti.depot.0.name': 'localfs', 'kotti.depot.0.location': '/tmp', 'kotti.depot.1.backend': 'kotti.tests.TFS2', 'kotti.depot.1.uri': 'mongo://', 'kotti.depot.1.name': 'mongo', } configure_filedepot(settings) assert DepotManager.get().marker == 'TFS1' assert DepotManager.get('localfs').marker == 'TFS1' assert DepotManager.get('mongo').marker == 'TFS2' tests.TFS1.assert_called_with(location='/tmp') tests.TFS2.assert_called_with(uri='mongo://') del tests.TFS1 del tests.TFS2
def test_application_separation(app): app.set_application_id('apps/one') ensure_correct_depot(app) transaction.begin() files = FileCollection(app.session()) first_id = files.add('readme.txt', b'README').id transaction.commit() app.set_application_id('apps/two') ensure_correct_depot(app) transaction.begin() files = FileCollection(app.session()) second_id = files.add('readme.txt', b'README').id transaction.commit() assert len(DepotManager.get('apps-one').list()) == 1 assert len(DepotManager.get('apps-two').list()) == 1 client = Client(app) app.set_application_id('apps/one') assert client.get('/storage/{}'.format(first_id))\ .status_code == 200 assert client.get('/storage/{}'.format(second_id), expect_errors=True)\ .status_code == 404 app.set_application_id('apps/two') assert client.get('/storage/{}'.format(first_id), expect_errors=True)\ .status_code == 404 assert client.get('/storage/{}'.format(second_id))\ .status_code == 200
def test_aliases(self): DepotManager.configure('first', {'depot.storage_path': './lfs'}) DepotManager.configure('second', {'depot.storage_path': './lfs2'}) DepotManager.alias('used_storage', 'first') storage = DepotManager.get('used_storage') assert storage.storage_path == './lfs', storage DepotManager.alias('used_storage', 'second') storage = DepotManager.get('used_storage') assert storage.storage_path == './lfs2', storage
def test_session_rollback(self, factory, db_session, filedepot): from depot.manager import DepotManager f = factory(data='file content', name=u'content', title=u'content') id = f.data['file_id'] db_session.add(f) db_session.flush() assert id in DepotManager.get()._storage.keys() db_session.rollback() assert id not in DepotManager.get()._storage.keys() assert DepotManager.get().delete.called
def index(request): if request.method == 'POST': file = request.FILES['file'] if file: fileid = DepotManager.get().create(file) UPLOADED_FILES.append(fileid) return HttpResponseRedirect('/') files = [DepotManager.get().get(fileid) for fileid in UPLOADED_FILES] template = loader.get_template('index.html') return HttpResponse(template.render({ 'files': files }, request))
def _flush_object(self, obj): history = self.get_depot_history(obj) for entry in history.deleted: depot, fileid = entry.split('/', 1) depot = DepotManager.get(depot) depot.delete(fileid) history.clear()
def get_attachment(self, workspace_name, vuln_id, attachment_filename): vuln_workspace_check = db.session.query(VulnerabilityGeneric, Workspace.id).join( Workspace).filter(VulnerabilityGeneric.id == vuln_id, Workspace.name == workspace_name).first() if vuln_workspace_check: file_obj = db.session.query(File).filter_by(object_type='vulnerability', object_id=vuln_id, filename=attachment_filename).first() if file_obj: depot = DepotManager.get() depot_file = depot.get(file_obj.content.get('file_id')) if depot_file.content_type.startswith('image/'): # Image content types are safe (they can't be executed like # html) so we don't have to force the download of the file as_attachment = False else: as_attachment = True return flask.send_file( io.BytesIO(depot_file.read()), attachment_filename=file_obj.filename, as_attachment=as_attachment, mimetype=depot_file.content_type ) else: flask.abort(404, "File not found") else: flask.abort(404, "Vulnerability not found")
def upgrade(): from depot.manager import DepotManager from depot.fields.upload import UploadedFile from depot.fields.sqlalchemy import UploadedFileField from kotti import DBSession, metadata from kotti.resources import File t = sa.Table('files', metadata) t.c.data.type = sa.LargeBinary() dn = DepotManager.get_default() update = t.update() conn = DBSession.connection() for obj in DBSession.query(File): uploaded_file = UploadedFile({'depot_name': dn, 'files': []}) uploaded_file._thaw() uploaded_file.process_content( obj.data, filename=obj.filename, content_type=obj.mimetype) stored_file = DepotManager.get().get(uploaded_file['file_id']) stmt = update.where( t.c.id == obj.id).values(data=uploaded_file.encode()) res = conn.execute(stmt) assert res.rowcount == 1 stored_file.last_modified = obj.modification_date log.info("Migrated {} bytes for File with pk {} to {}/{}".format( len(obj.data), obj.id, dn, uploaded_file['file_id'])) DBSession.flush() if DBSession.get_bind().name != 'sqlite': # not supported by sqlite op.alter_column('files', 'data', type_=UploadedFileField())
def test_delete(self, factory, db_session, root, filedepot): from depot.manager import DepotManager f = factory(data='file content', name=u'content', title=u'content') id = f.data['file_id'] root[str(id)] = f db_session.flush() assert id in DepotManager.get()._storage.keys() del root[str(id)] import transaction transaction.commit() assert DepotManager.get().delete.called assert id not in DepotManager.get()._storage.keys()
def take_action(self, parsed_args: argparse.Namespace) -> None: super(DeleteDBCommand, self).take_action(parsed_args) config_uri = parsed_args.config_file # setup_logging(config_uri) settings = get_appsettings(config_uri) settings.update(settings.global_conf) if 'sqlalchemy.url' not in settings or not settings['sqlalchemy.url']: raise InvalidSettingFile('Wrong or empty sqlalchemy database url,' 'check config file') engine = get_engine(settings) app_config = CFG(settings) app_config.configure_filedepot() if parsed_args.force: print('Database deletion begin.') DeclarativeBase.metadata.drop_all(engine) print('Database deletion done.') try: print('Cleaning depot begin.') depot = DepotManager.get() depot_files = depot.list() for file_ in depot_files: depot.delete(file_) print('Cleaning depot done.') except FileNotFoundError: print( 'Warning! Can delete depots file, is depot path correctly' ' configured?' ) else: raise ForceArgumentNeeded( 'Warning, You should use --force if you really want to' ' delete database.' )
def upgrade(): sa.orm.events.MapperEvents._clear() # avoids filedepot magic from depot.manager import DepotManager from depot.fields.upload import UploadedFile from depot.fields.sqlalchemy import UploadedFileField from kotti import DBSession, metadata from kotti.resources import File t = sa.Table("files", metadata) t.c.data.type = sa.LargeBinary() dn = DepotManager.get_default() for obj in DBSession.query(File): uploaded_file = UploadedFile({"depot_name": dn, "files": []}) uploaded_file._thaw() uploaded_file.process_content(obj.data, filename=obj.filename, content_type=obj.mimetype) stored_file = DepotManager.get().get(uploaded_file["file_id"]) obj.data = uploaded_file.encode() stored_file.last_modified = obj.modification_date log.info( "Migrated {} bytes for File with pk {} to {}/{}".format(len(obj.data), obj.id, dn, uploaded_file["file_id"]) ) DBSession.flush() if DBSession.get_bind().name != "sqlite": # not supported by sqlite op.alter_column("files", "data", type_=UploadedFileField())
def serialize_node_for_page(content: Content, context: Context): if content.type in (ContentType.Page, ContentType.File) : data_container = content # The following properties are overriden by revision values if content.revision_to_serialize>0: for revision in content.revisions: if revision.revision_id==content.revision_to_serialize: data_container = revision break result = DictLikeClass( id=content.content_id, parent=context.toDict(content.parent), workspace=context.toDict(content.workspace), type=content.type, is_new=content.has_new_information_for(context.get_user()), content=data_container.description, created=data_container.created, updated=content.last_revision.updated, label=data_container.label, icon=ContentType.get_icon(content.type), owner=context.toDict(content.first_revision.owner), last_modification_author=context.toDict(content.last_revision.owner), status=context.toDict(data_container.get_status()), links=[], revision_nb = len(content.revisions), selected_revision='latest' if content.revision_to_serialize<=0 else content.revision_to_serialize, history=Context(CTX.CONTENT_HISTORY).toDict(content.get_history()), is_editable=content.is_editable, is_deleted=content.is_deleted, is_archived=content.is_archived, urls = context.toDict({ 'mark_read': context.url(Content.format_path('/workspaces/{wid}/folders/{fid}/{ctype}s/{cid}/put_read', content)), 'mark_unread': context.url(Content.format_path('/workspaces/{wid}/folders/{fid}/{ctype}s/{cid}/put_unread', content)) }) ) if content.type == ContentType.File: depot = DepotManager.get() depot_stored_file = depot.get(data_container.depot_file) result.label = content.label result['file'] = DictLikeClass( name=data_container.file_name, size=depot_stored_file.content_length, mimetype=data_container.file_mimetype) return result if content.type==ContentType.Folder: value = DictLikeClass( id=content.content_id, label=content.label, is_new=content.has_new_information_for(context.get_user()), ) return value raise NotImplementedError
def test_default_filedepot(self, db_session): from kotti import main from depot.manager import DepotManager settings = self.required_settings() with patch('kotti.resources.initialize_sql'): main({}, **settings) assert DepotManager.get().__class__.__name__ == 'DBFileStorage'
def _session_rollback(cls, session, previous_transaction): if hasattr(session, "_depot_old"): del session._depot_old if hasattr(session, "_depot_new"): for entry in session._depot_new: depot, fileid = entry.split("/", 1) depot = DepotManager.get(depot) depot.delete(fileid) del session._depot_new
def _session_committed(cls, session): if hasattr(session, "_depot_old"): for entry in session._depot_old: depot, fileid = entry.split("/", 1) depot = DepotManager.get(depot) depot.delete(fileid) del session._depot_old if hasattr(session, "_depot_new"): del session._depot_new
def depot(temporary_directory): DepotManager.configure('default', { 'depot.backend': 'depot.io.local.LocalFileStorage', 'depot.storage_path': temporary_directory }) yield DepotManager.get() DepotManager._clear()
def create_file(self, lang='en'): fname = {'en': 'hello.txt', 'ru': u_('Крупный'), 'it': u_('àèìòù')}.get(lang, 'unknown') self.UPLOADED_FILES += [DepotManager.get().create(FILE_CONTENT, filename=fname)] return dict(files=self.UPLOADED_FILES, uploaded_to=DepotManager.get_default(), last=self.UPLOADED_FILES[-1])
def test_session_integration(self, db_session): from depot.manager import DepotManager DepotManager._default_depot = 'default' DepotManager._depots = {'default': DBFileStorage()} file_id = DepotManager.get().create('content here', u'f.jpg', 'image/jpg') fs = DepotManager.get().get(file_id) db_session.add(fs) import transaction transaction.commit() transaction.begin() db_session.delete(fs) transaction.commit() with pytest.raises(IOError): DepotManager.get().get(file_id)
def get_one_revision_filepath(self, revision_id: int = None) -> str: """ This method allows us to directly get a file path from its revision identifier. :param revision_id: The revision id of the filepath we want to return :return: The corresponding filepath """ revision = self.get_one_revision(revision_id) depot = DepotManager.get() depot_stored_file = depot.get(revision.depot_file) # type: StoredFile depot_file_path = depot_stored_file._file_path # type: str return depot_file_path
def __call__(self, request: Request) -> Response: """ :param request: Current request :type request: :class:`kotti.request.Request` :return: Respone object :rtype: :class:`pyramid.response.Response` """ # Only handle GET and HEAD requests for the mountpoint. # All other requests are passed to downstream handlers. if request.method not in ("GET", "HEAD") or not request.path.startswith( self.mountpoint ): response = self.handler(request) return response # paths match this pattern # /<mountpoint>/<depot name>/<file id>[/download] path = request.path.split("/") if len(path) and not path[0]: path = path[1:] if len(path) < 3: response = HTTPNotFound() return response __, depot, fileid = path[:3] depot = DepotManager.get(depot) if not depot: response = HTTPNotFound() return response try: f = depot.get(fileid) except (IOError, ValueError): response = HTTPNotFound() return response # if the file has a public_url, it's stored somewhere else (e.g. S3) public_url = f.public_url if public_url is not None: response = HTTPMovedPermanently(public_url) return response # file is not directly accessible for user agents, serve it ourselves if path[-1] == "download": disposition = "attachment" else: disposition = "inline" response = StoredFileResponse(f, request, disposition=disposition) return response
def download_revisions_file(self, context, request: TracimRequest, hapic_data=None): # nopep8 """ Download raw file for specific revision of content. Good pratice for filename is filename is `{label}_r{revision_id}{file_extension}`. Default filename value is 'raw' (without file extension) or nothing. """ app_config = request.registry.settings['CFG'] api = ContentApi( show_archived=True, show_deleted=True, current_user=request.current_user, session=request.dbsession, config=app_config, ) content = api.get_one( hapic_data.path.content_id, content_type=content_type_list.Any_SLUG ) revision = api.get_one_revision( revision_id=hapic_data.path.revision_id, content=content ) try: file = DepotManager.get().get(revision.depot_file) except IOError as exc: raise TracimFileNotFound( 'file related to revision {} of content {} not found in depot.'.format( revision.revision_id, revision.content_id ) ) from exc filename = hapic_data.path.filename if not filename or filename == 'raw': filename = "{label}_r{revision_id}{file_extension}".format( label=revision.file_name, revision_id=revision.revision_id, file_extension=revision.file_extension ) return HapicFile( file_object=file, mimetype=file.content_type, filename=filename, as_attachment=hapic_data.query.force_download )
def downgrade(): """Add the file content in revision.""" with op.batch_alter_table('content_revisions') as batch_op: batch_op.add_column(sa.Column('file_content', sa.LargeBinary)) configure_depot() depot = DepotManager.get() connection = op.get_bind() select_query = revision_helper.select() \ .where(revision_helper.c.type == 'file') \ .where(revision_helper.c.depot_file.isnot(None)) files = connection.execute(select_query).fetchall() for file in files: depot_file_content = depot.get(file.depot_file).read() update_query = revision_helper.update() \ .where(revision_helper.c.revision_id == file.revision_id) \ .values(file_content=depot_file_content) connection.execute(update_query)
def delete_attachment(self, workspace_name, vuln_id, attachment_filename): vuln_workspace_check = db.session.query(VulnerabilityGeneric, Workspace.id).join( Workspace).filter( VulnerabilityGeneric.id == vuln_id, Workspace.name == workspace_name).first() if vuln_workspace_check: file_obj = db.session.query(File).filter_by(object_type='vulnerability', object_id=vuln_id, filename=attachment_filename).first() if file_obj: db.session.delete(file_obj) db.session.commit() depot = DepotManager.get() depot.delete(file_obj.content.get('file_id')) return flask.jsonify({'message': 'Attachment was successfully deleted'}) else: flask.abort(404, "File not found") else: flask.abort(404, "Vulnerability not found")
def test_pdf_preview_creation(session): path = module_path('onegov.file', 'tests/fixtures/example.pdf') with open(path, 'rb') as f: session.add(File(name='example.pdf', reference=f)) transaction.commit() pdf = session.query(File).one() pdf.reference['thumbnail_medium'] # our example file contains a blue backgorund so we can verify that # the thumbnail for the pdf is generated correctly thumb = DepotManager.get().get(pdf.reference['thumbnail_medium']['id']) image = Image.open(thumb) assert (0, 91, 161, 255) in set(image.getdata()) assert image.size == (395, 512)
def create_app(db_connection_string=None, testing=None): app = Flask(__name__) try: secret_key = server.config.faraday_server.secret_key except Exception: # Now when the config file does not exist it doesn't enter in this # condition, but it could happen in the future. TODO check save_new_secret_key(app) else: if secret_key is None: # This is what happens now when the config file doesn't exist. # TODO check save_new_secret_key(app) else: app.config['SECRET_KEY'] = secret_key login_failed_message = ("Invalid username or password", 'error') app.config.update({ 'SECURITY_PASSWORD_SINGLE_HASH': True, 'WTF_CSRF_ENABLED': False, 'SECURITY_USER_IDENTITY_ATTRIBUTES': ['username'], 'SECURITY_POST_LOGIN_VIEW': '/_api/session', 'SECURITY_POST_LOGOUT_VIEW': '/_api/login', 'SECURITY_POST_CHANGE_VIEW': '/_api/change', 'SECURITY_CHANGEABLE': True, 'SECURITY_SEND_PASSWORD_CHANGE_EMAIL': False, 'SECURITY_MSG_USER_DOES_NOT_EXIST': login_failed_message, # The line bellow should not be necessary because of the # CustomLoginForm, but i'll include it anyway. 'SECURITY_MSG_INVALID_PASSWORD': login_failed_message, 'SESSION_TYPE': 'filesystem', 'SESSION_FILE_DIR': server.config.FARADAY_SERVER_SESSIONS_DIR, 'SQLALCHEMY_TRACK_MODIFICATIONS': False, 'SQLALCHEMY_RECORD_QUERIES': True, # app.config['SQLALCHEMY_ECHO'] = True 'SECURITY_PASSWORD_SCHEMES': [ 'bcrypt', # This should be the default value # 'des_crypt', 'pbkdf2_sha1', # Used by CouchDB passwords # 'pbkdf2_sha256', # 'pbkdf2_sha512', # 'sha256_crypt', # 'sha512_crypt', 'plaintext', # TODO: remove it ], 'PERMANENT_SESSION_LIFETIME': datetime.timedelta(hours=12), }) storage_path = server.config.storage.path if not storage_path: logger.warn('No storage section or path in the .faraday/server.ini. Setting the default value to .faraday/storage') storage_path = setup_storage_path() if not DepotManager.get('default'): if testing: DepotManager.configure('default', { 'depot.storage_path': '/tmp' }) else: DepotManager.configure('default', { 'depot.storage_path': storage_path }) check_testing_configuration(testing, app) try: app.config['SQLALCHEMY_DATABASE_URI'] = db_connection_string or server.config.database.connection_string.strip("'") except AttributeError: logger.info('Missing [database] section on server.ini. Please configure the database before running the server.') except NoOptionError: logger.info('Missing connection_string on [database] section on server.ini. Please configure the database before running the server.') from server.models import db db.init_app(app) #Session(app) # Setup Flask-Security app.user_datastore = SQLAlchemyUserDatastore( db, user_model=server.models.User, role_model=None) # We won't use flask security roles feature Security(app, app.user_datastore, login_form=CustomLoginForm) # Make API endpoints require a login user by default. Based on # https://stackoverflow.com/questions/13428708/best-way-to-make-flask-logins-login-required-the-default app.view_functions['security.login'].is_public = True app.view_functions['security.logout'].is_public = True app.debug = server.config.is_debug_mode() minify_json_output(app) for handler in LOGGING_HANDLERS: app.logger.addHandler(handler) register_blueprints(app) register_handlers(app) return app
def create_app(db_connection_string=None, testing=None): app = Flask(__name__) try: app.config['SECRET_KEY'] = server.config.faraday_server.secret_key except Exception: save_new_secret_key(app) app.config['SECURITY_PASSWORD_SINGLE_HASH'] = True app.config['WTF_CSRF_ENABLED'] = False app.config['SECURITY_USER_IDENTITY_ATTRIBUTES'] = ['username'] app.config['SECURITY_POST_LOGIN_VIEW'] = '/_api/session' app.config['SECURITY_POST_LOGOUT_VIEW'] = '/_api/login' app.config['SECURITY_POST_CHANGE_VIEW'] = '/_api/change' app.config['SECURITY_CHANGEABLE'] = True app.config['SECURITY_SEND_PASSWORD_CHANGE_EMAIL'] = False app.config['SESSION_TYPE'] = 'filesystem' app.config['SESSION_FILE_DIR'] = server.config.FARADAY_SERVER_SESSIONS_DIR app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False app.config['SQLALCHEMY_RECORD_QUERIES'] = True # app.config['SQLALCHEMY_ECHO'] = True app.config['SECURITY_PASSWORD_SCHEMES'] = [ 'bcrypt', # This should be the default value # 'des_crypt', 'pbkdf2_sha1', # Used by CouchDB passwords # 'pbkdf2_sha256', # 'pbkdf2_sha512', # 'sha256_crypt', # 'sha512_crypt', 'plaintext', # TODO: remove it ] app.config['PERMANENT_SESSION_LIFETIME'] = datetime.timedelta(hours=12) try: storage_path = server.config.storage.path except AttributeError: logger.warn( 'No storage section or path in the .faraday/server.ini. Setting the default value to .faraday/storage' ) storage_path = setup_storage_path() if not DepotManager.get('default'): if testing: DepotManager.configure('default', {'depot.storage_path': '/tmp'}) else: DepotManager.configure('default', {'depot.storage_path': storage_path}) check_testing_configuration(testing, app) try: app.config[ 'SQLALCHEMY_DATABASE_URI'] = db_connection_string or server.config.database.connection_string.strip( "'") except AttributeError: logger.info( 'Missing [database] section on server.ini. Please configure the database before running the server.' ) except NoOptionError: logger.info( 'Missing connection_string on [database] section on server.ini. Please configure the database before running the server.' ) from server.models import db db.init_app(app) #Session(app) # Setup Flask-Security app.user_datastore = SQLAlchemyUserDatastore( db, user_model=server.models.User, role_model=None) # We won't use flask security roles feature Security(app, app.user_datastore) # Make API endpoints require a login user by default. Based on # https://stackoverflow.com/questions/13428708/best-way-to-make-flask-logins-login-required-the-default app.view_functions['security.login'].is_public = True app.view_functions['security.logout'].is_public = True app.debug = server.config.is_debug_mode() minify_json_output(app) for handler in LOGGING_HANDLERS: app.logger.addHandler(handler) register_blueprints(app) register_handlers(app) return app
def depotfile(): depot = DepotManager.get('default') path = os.path.join(CURRENT_PATH, '../data', 'faraday.png') with open(path, 'rb') as fp: fileid = depot.create(fp, 'faraday.png', 'image/png') return fileid
def create_app(db_connection_string=None, testing=None): class CustomFlask(Flask): SKIP_RULES = [ # These endpoints will be removed for v3 '/v3/ws/<workspace_name>/hosts/bulk_delete/', '/v3/ws/<workspace_name>/vulns/bulk_delete/', '/v3/ws/<workspace_id>/change_readonly/', '/v3/ws/<workspace_id>/deactivate/', '/v3/ws/<workspace_id>/activate/', ] def add_url_rule(self, rule, endpoint=None, view_func=None, **options): # Flask registers views when an application starts # do not add view from SKIP_VIEWS for rule_ in CustomFlask.SKIP_RULES: if rule_ == rule: return return super(CustomFlask, self).add_url_rule(rule, endpoint, view_func, **options) app = CustomFlask(__name__, static_folder=None) try: secret_key = faraday.server.config.faraday_server.secret_key except Exception: # Now when the config file does not exist it doesn't enter in this # condition, but it could happen in the future. TODO check save_new_secret_key(app) else: if secret_key is None: # This is what happens now when the config file doesn't exist. # TODO check save_new_secret_key(app) else: app.config['SECRET_KEY'] = secret_key if faraday.server.config.faraday_server.agent_token is None: save_new_agent_creation_token() login_failed_message = ("Invalid username or password", 'error') app.config.update({ 'SECURITY_BACKWARDS_COMPAT_AUTH_TOKEN': True, 'SECURITY_PASSWORD_SINGLE_HASH': True, 'WTF_CSRF_ENABLED': False, 'SECURITY_USER_IDENTITY_ATTRIBUTES': ['username'], 'SECURITY_POST_LOGIN_VIEW': '/_api/session', 'SECURITY_POST_LOGOUT_VIEW': '/_api/logout', 'SECURITY_POST_CHANGE_VIEW': '/_api/change', 'SECURITY_RESET_PASSWORD_TEMPLATE': '/security/reset.html', 'SECURITY_POST_RESET_VIEW': '/', 'SECURITY_SEND_PASSWORD_RESET_EMAIL':True, #For testing porpouse 'SECURITY_EMAIL_SENDER': "*****@*****.**", 'SECURITY_CHANGEABLE': True, 'SECURITY_SEND_PASSWORD_CHANGE_EMAIL': False, 'SECURITY_MSG_USER_DOES_NOT_EXIST': login_failed_message, 'SECURITY_TOKEN_AUTHENTICATION_HEADER': 'Authorization', # The line bellow should not be necessary because of the # CustomLoginForm, but i'll include it anyway. 'SECURITY_MSG_INVALID_PASSWORD': login_failed_message, 'SESSION_TYPE': 'filesystem', 'SESSION_FILE_DIR': faraday.server.config.FARADAY_SERVER_SESSIONS_DIR, 'SQLALCHEMY_TRACK_MODIFICATIONS': False, 'SQLALCHEMY_RECORD_QUERIES': True, # app.config['SQLALCHEMY_ECHO'] = True 'SECURITY_PASSWORD_SCHEMES': [ 'bcrypt', # This should be the default value # 'des_crypt', # 'pbkdf2_sha256', # 'pbkdf2_sha512', # 'sha256_crypt', # 'sha512_crypt', ], 'PERMANENT_SESSION_LIFETIME': datetime.timedelta(hours=int(faraday.server.config.faraday_server.session_timeout or 12)), 'SESSION_COOKIE_NAME': 'faraday_session_2', 'SESSION_COOKIE_SAMESITE': 'Lax', }) store = FilesystemStore(app.config['SESSION_FILE_DIR']) prefixed_store = PrefixDecorator('sessions_', store) KVSessionExtension(prefixed_store, app) user_logged_in.connect(user_logged_in_succesfull, app) user_logged_out.connect(expire_session, app) storage_path = faraday.server.config.storage.path if not storage_path: logger.warn('No storage section or path in the .faraday/config/server.ini. Setting the default value to .faraday/storage') storage_path = setup_storage_path() if not DepotManager.get('default'): if testing: DepotManager.configure('default', { 'depot.storage_path': '/tmp' # nosec }) else: DepotManager.configure('default', { 'depot.storage_path': storage_path }) check_testing_configuration(testing, app) try: app.config['SQLALCHEMY_DATABASE_URI'] = db_connection_string or faraday.server.config.database.connection_string.strip("'") except AttributeError: logger.info('Missing [database] section on server.ini. Please configure the database before running the server.') except NoOptionError: logger.info('Missing connection_string on [database] section on server.ini. Please configure the database before running the server.') from faraday.server.models import db # pylint:disable=import-outside-toplevel db.init_app(app) #Session(app) # Setup Flask-Security app.user_datastore = SQLAlchemyUserDatastore( db, user_model=User, role_model=None) # We won't use flask security roles feature Security(app, app.user_datastore, login_form=CustomLoginForm) # Make API endpoints require a login user by default. Based on # https://stackoverflow.com/questions/13428708/best-way-to-make-flask-logins-login-required-the-default app.view_functions['security.login'].is_public = True app.view_functions['security.logout'].is_public = True app.debug = faraday.server.config.is_debug_mode() minify_json_output(app) for handler in LOGGING_HANDLERS: app.logger.addHandler(handler) app.logger.propagate = False register_blueprints(app) register_handlers(app) app.view_functions['agent_api.AgentCreationView:post'].is_public = True app.view_functions['agent_api.AgentCreationV3View:post'].is_public = True return app
def test_api__put_content__ok_200__nominal_case_libreoffice_online( self, content_api_factory, workspace_api_factory, content_type_list, session, web_testapp, app_config, admin_user, ) -> None: """Save file content""" workspace_api = workspace_api_factory.get() content_api = content_api_factory.get() business_workspace = workspace_api.create_workspace(label="business") tool_folder = content_api.create( label="tools", content_type_slug=content_type_list.Folder.slug, do_save=True, do_notify=None, parent=None, workspace=business_workspace, ) with freeze_time("1999-12-31 23:59:59"): test_file = content_api.create( content_type_slug=content_type_list.File.slug, workspace=business_workspace, parent=tool_folder, label="Test file", do_save=False, do_notify=False, ) with new_revision(session=session, tm=transaction.manager, content=test_file): content_api.update_file_data(test_file, "Test_file.txt", new_mimetype="plain/text", new_content=b"Test file") transaction.commit() with freeze_time("2000-01-01 00:00:05"): access_token = str( admin_user.ensure_auth_token( app_config.USER__AUTH_TOKEN__VALIDITY)) transaction.commit() url = "/api/v2/collaborative-document-edition/wopi/files/{}/contents?access_token={}".format( test_file.content_id, quote(access_token)) updated_at = test_file.updated new_content = b"content has been modified" res = web_testapp.post( url, params=new_content, status=200, headers={"X-LOOL-WOPI-Timestamp": str(test_file.updated)}, ) transaction.commit() # FIXME - H.D. - 2019/07/04 - MySQL has trouble finding the newly created revision # without reinstancing the database session content_api = content_api_factory.get() content = content_api.get_one(test_file.content_id, content_type=content_type_list.Any_SLUG) response = res.json_body file_ = DepotManager.get().get(content.depot_file) assert (response["LastModifiedTime"] != updated_at.replace(tzinfo=datetime.timezone.utc).isoformat()) assert content.file_mimetype == content.depot_file.content_type == "plain/text" assert file_.read() == new_content
def bound_depot(self): assert DepotManager._default_depot == self.bound_depot_id return DepotManager.get()
def get_content_type(self, file_obj): depot = DepotManager.get() return depot.get(file_obj.content.get('file_id')).content_type
#!/usr/bin/python from depot.manager import DepotManager from selenium import webdriver from pyvirtualdisplay import Display from PIL import Image depot = DepotManager.get() display = Display(visible=0, size=(800, 800)) display.start() driver = webdriver.Chrome('/usr/bin/chromedriver') driver.set_window_size(800, 800) # set the window size that you need driver.get('https://github.com') driver.save_screenshot('github.png') # remove scrollbar and whitespace img = Image.open('github.png') cropped_img = img.crop((0, 0, 650, 650)) cropped_img.save('cropped.png')
def __init__(self, store, prefix, update_listener=None): self.db = rdflib.ConjunctiveGraph(store) self.store = store self.depot = DepotManager.get('nanopublications') self.prefix = rdflib.Namespace(prefix) self.update_listener = update_listener
def get_data(self, file_obj): depot = DepotManager.get() return b64encode(depot.get(file_obj.content.get('file_id')).read())
def create_app(db_connection_string=None, testing=None): app = Flask(__name__) try: secret_key = server.config.faraday_server.secret_key except Exception: # Now when the config file does not exist it doesn't enter in this # condition, but it could happen in the future. TODO check save_new_secret_key(app) else: if secret_key is None: # This is what happens now when the config file doesn't exist. # TODO check save_new_secret_key(app) else: app.config['SECRET_KEY'] = secret_key login_failed_message = ("Invalid username or password", 'error') app.config.update({ 'SECURITY_PASSWORD_SINGLE_HASH': True, 'WTF_CSRF_ENABLED': False, 'SECURITY_USER_IDENTITY_ATTRIBUTES': ['username'], 'SECURITY_POST_LOGIN_VIEW': '/_api/session', 'SECURITY_POST_LOGOUT_VIEW': '/_api/login', 'SECURITY_POST_CHANGE_VIEW': '/_api/change', 'SECURITY_CHANGEABLE': True, 'SECURITY_SEND_PASSWORD_CHANGE_EMAIL': False, 'SECURITY_MSG_USER_DOES_NOT_EXIST': login_failed_message, # The line bellow should not be necessary because of the # CustomLoginForm, but i'll include it anyway. 'SECURITY_MSG_INVALID_PASSWORD': login_failed_message, 'SESSION_TYPE': 'filesystem', 'SESSION_FILE_DIR': server.config.FARADAY_SERVER_SESSIONS_DIR, 'SQLALCHEMY_TRACK_MODIFICATIONS': False, 'SQLALCHEMY_RECORD_QUERIES': True, # app.config['SQLALCHEMY_ECHO'] = True 'SECURITY_PASSWORD_SCHEMES': [ 'bcrypt', # This should be the default value # 'des_crypt', 'pbkdf2_sha1', # Used by CouchDB passwords # 'pbkdf2_sha256', # 'pbkdf2_sha512', # 'sha256_crypt', # 'sha512_crypt', 'plaintext', # TODO: remove it ], 'PERMANENT_SESSION_LIFETIME': datetime.timedelta(hours=12), }) try: storage_path = server.config.storage.path except AttributeError: logger.warn( 'No storage section or path in the .faraday/server.ini. Setting the default value to .faraday/storage' ) storage_path = setup_storage_path() if not DepotManager.get('default'): if testing: DepotManager.configure('default', {'depot.storage_path': '/tmp'}) else: DepotManager.configure('default', {'depot.storage_path': storage_path}) check_testing_configuration(testing, app) try: app.config[ 'SQLALCHEMY_DATABASE_URI'] = db_connection_string or server.config.database.connection_string.strip( "'") except AttributeError: logger.info( 'Missing [database] section on server.ini. Please configure the database before running the server.' ) except NoOptionError: logger.info( 'Missing connection_string on [database] section on server.ini. Please configure the database before running the server.' ) from server.models import db db.init_app(app) #Session(app) # Setup Flask-Security app.user_datastore = SQLAlchemyUserDatastore( db, user_model=server.models.User, role_model=None) # We won't use flask security roles feature Security(app, app.user_datastore, login_form=CustomLoginForm) # Make API endpoints require a login user by default. Based on # https://stackoverflow.com/questions/13428708/best-way-to-make-flask-logins-login-required-the-default app.view_functions['security.login'].is_public = True app.view_functions['security.logout'].is_public = True app.debug = server.config.is_debug_mode() minify_json_output(app) for handler in LOGGING_HANDLERS: app.logger.addHandler(handler) register_blueprints(app) register_handlers(app) return app
def create_file(self): self.UPLOADED_FILES += [DepotManager.get().create(FILE_CONTENT, filename='hello.txt')] return dict(files=self.UPLOADED_FILES, uploaded_to=DepotManager.get_default(), last=self.UPLOADED_FILES[-1])
def file_depot(self): if self._file_depot is None: if DepotManager.get('files') is None: DepotManager.configure('files', self.config['file_archive']) self._file_depot = DepotManager.get('files') return self._file_depot
def depot(self): return DepotManager.get(self.depot_name)